summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrej Shadura <andrewsh@debian.org>2018-05-08 15:59:29 +0200
committerAndrej Shadura <andrewsh@debian.org>2018-05-08 15:59:29 +0200
commit5b8466f7fae0e071c0f4eda13051c93313910028 (patch)
tree7061957f770e5e245ba00666dad912a2d44e7fdc
Import Upstream version 1.3.7
-rw-r--r--CMakeLists.txt117
-rw-r--r--ChangeLog198
-rw-r--r--LICENSE341
-rw-r--r--MicrosoftWindows_compatibility/external_command.bat1
-rw-r--r--MicrosoftWindows_compatibility/mcu8051ide.icobin0 -> 16958 bytes
-rw-r--r--MicrosoftWindows_compatibility/mcu8051ide_win_setup.iss66
-rw-r--r--MicrosoftWindows_compatibility/sdcc.bat2
-rw-r--r--README87
-rw-r--r--TODO5
-rwxr-xr-xclear_all.sh11
-rwxr-xr-xconfigure8
-rw-r--r--data/licence.txt341
-rw-r--r--data/m5ihib.dtd103
-rw-r--r--data/mcus.xml1968
-rw-r--r--data/project.dtd220
-rw-r--r--data/tips.xml191
-rw-r--r--demo/Demo project.mcu8051ide441
-rw-r--r--demo/demo.wtc15
-rw-r--r--demo/demo0.adf9
-rw-r--r--demo/demo0.asm27
-rw-r--r--demo/demo0.bin1
-rw-r--r--demo/demo0.hex2
-rw-r--r--demo/demo0.lst198
-rw-r--r--demo/demo0.sim6
-rw-r--r--demo/demo1.adf19
-rw-r--r--demo/demo1.asm63
-rw-r--r--demo/demo1.binbin0 -> 15 bytes
-rw-r--r--demo/demo1.hex2
-rw-r--r--demo/demo1.lst262
-rw-r--r--demo/demo1.sim16
-rw-r--r--demo/demo2.adf50
-rw-r--r--demo/demo2.asm78
-rw-r--r--demo/demo2.binbin0 -> 42 bytes
-rw-r--r--demo/demo2.hex3
-rw-r--r--demo/demo2.lst270
-rw-r--r--demo/demo2.sim47
-rw-r--r--demo/demo3.adf9
-rw-r--r--demo/demo3.asm72
-rw-r--r--demo/demo3.bin1
-rw-r--r--demo/demo3.sim6
-rw-r--r--demo/demo4.adf45
-rw-r--r--demo/demo4.asm81
-rw-r--r--demo/demo4.binbin0 -> 66 bytes
-rw-r--r--demo/demo4.hex9
-rw-r--r--demo/demo4.lst228
-rw-r--r--demo/demo4.sim42
-rw-r--r--demo/demo5.adf5
-rw-r--r--demo/demo5.asm35
-rw-r--r--demo/demo5.bin1
-rw-r--r--demo/demo5.hex2
-rw-r--r--demo/demo5.lst216
-rw-r--r--demo/demo5.sim2
-rw-r--r--demo/demo_c_0bin0 -> 1425 bytes
-rw-r--r--demo/demo_c_0.adb106
-rw-r--r--demo/demo_c_0.asm529
-rw-r--r--demo/demo_c_0.c41
-rw-r--r--demo/demo_c_0.cdb278
-rw-r--r--demo/demo_c_0.hashes1
-rw-r--r--demo/demo_c_0.hex34
-rw-r--r--demo/demo_c_0.ihx34
-rw-r--r--demo/demo_c_0.lnk19
-rw-r--r--demo/demo_c_0.lst529
-rw-r--r--demo/demo_c_0.map488
-rw-r--r--demo/demo_c_0.mem28
-rw-r--r--demo/demo_c_0.rel378
-rw-r--r--demo/demo_c_0.rst529
-rw-r--r--demo/demo_c_0.sym659
-rw-r--r--demo/file.hex2
-rw-r--r--demo/file.lst292
-rw-r--r--demo/keypad_displaybin0 -> 1614 bytes
-rw-r--r--demo/keypad_display.adb106
-rw-r--r--demo/keypad_display.asm624
-rw-r--r--demo/keypad_display.c84
-rw-r--r--demo/keypad_display.cdb328
-rw-r--r--demo/keypad_display.hashes1
-rw-r--r--demo/keypad_display.hex49
-rw-r--r--demo/keypad_display.ihx49
-rw-r--r--demo/keypad_display.lnk19
-rw-r--r--demo/keypad_display.lst624
-rw-r--r--demo/keypad_display.map536
-rw-r--r--demo/keypad_display.mem28
-rw-r--r--demo/keypad_display.rel490
-rw-r--r--demo/keypad_display.rst624
-rw-r--r--demo/keypad_display.sym712
-rw-r--r--demo/keypad_display.vhw6
-rw-r--r--demo/ledmatrix.adb102
-rw-r--r--demo/ledmatrix.asm494
-rw-r--r--demo/ledmatrix.c43
-rw-r--r--demo/ledmatrix.cdb251
-rw-r--r--demo/ledmatrix.hashes1
-rw-r--r--demo/ledmatrix.hex26
-rw-r--r--demo/ledmatrix.ihx26
-rw-r--r--demo/ledmatrix.lnk19
-rw-r--r--demo/ledmatrix.lst494
-rw-r--r--demo/ledmatrix.m5ihib599
-rw-r--r--demo/ledmatrix.map454
-rw-r--r--demo/ledmatrix.mem28
-rw-r--r--demo/ledmatrix.rel328
-rw-r--r--demo/ledmatrix.rst494
-rw-r--r--demo/ledmatrix.sym634
-rw-r--r--demo/ledmatrix.vhc6
-rw-r--r--demo/mleddisplay.adf45
-rw-r--r--demo/mleddisplay.asm125
-rw-r--r--demo/mleddisplay.binbin0 -> 38 bytes
-rw-r--r--demo/mleddisplay.hex2
-rw-r--r--demo/mleddisplay.lst316
-rw-r--r--demo/mleddisplay.vhw5
-rw-r--r--doc/man/mcu8051ide.1.gzbin0 -> 2334 bytes
-rw-r--r--icons/16x16/1downarrow.pngbin0 -> 306 bytes
-rw-r--r--icons/16x16/1leftarrow.pngbin0 -> 296 bytes
-rw-r--r--icons/16x16/1rightarrow.pngbin0 -> 314 bytes
-rw-r--r--icons/16x16/1uparrow.pngbin0 -> 305 bytes
-rw-r--r--icons/16x16/2_rightarrow.pngbin0 -> 333 bytes
-rw-r--r--icons/16x16/2downarrow.pngbin0 -> 407 bytes
-rw-r--r--icons/16x16/2leftarrow.pngbin0 -> 403 bytes
-rw-r--r--icons/16x16/2rightarrow.pngbin0 -> 385 bytes
-rw-r--r--icons/16x16/2uparrow.pngbin0 -> 386 bytes
-rw-r--r--icons/16x16/8seg.pngbin0 -> 232 bytes
-rw-r--r--icons/16x16/_1downarrow.pngbin0 -> 3262 bytes
-rw-r--r--icons/16x16/_1uparrow.pngbin0 -> 3238 bytes
-rw-r--r--icons/16x16/_blockdevice.pngbin0 -> 794 bytes
-rw-r--r--icons/16x16/add.pngbin0 -> 658 bytes
-rw-r--r--icons/16x16/amber_dot.pngbin0 -> 790 bytes
-rw-r--r--icons/16x16/arr.pngbin0 -> 181 bytes
-rw-r--r--icons/16x16/ascii.pngbin0 -> 579 bytes
-rw-r--r--icons/16x16/asm.pngbin0 -> 535 bytes
-rw-r--r--icons/16x16/back.pngbin0 -> 571 bytes
-rw-r--r--icons/16x16/bar5.pngbin0 -> 396 bytes
-rw-r--r--icons/16x16/bh.pngbin0 -> 333 bytes
-rw-r--r--icons/16x16/blockdevice.pngbin0 -> 736 bytes
-rw-r--r--icons/16x16/bm_ex.pngbin0 -> 661 bytes
-rw-r--r--icons/16x16/bookmark.pngbin0 -> 690 bytes
-rw-r--r--icons/16x16/bookmark_add.pngbin0 -> 708 bytes
-rw-r--r--icons/16x16/bookmark_toolbar.pngbin0 -> 3369 bytes
-rw-r--r--icons/16x16/bottom.pngbin0 -> 424 bytes
-rw-r--r--icons/16x16/bottom1.pngbin0 -> 572 bytes
-rw-r--r--icons/16x16/bug.pngbin0 -> 1107 bytes
-rw-r--r--icons/16x16/button_cancel.pngbin0 -> 779 bytes
-rw-r--r--icons/16x16/camera_test.pngbin0 -> 611 bytes
-rw-r--r--icons/16x16/cancel.pngbin0 -> 890 bytes
-rw-r--r--icons/16x16/change_case.pngbin0 -> 303 bytes
-rw-r--r--icons/16x16/chardevice.pngbin0 -> 778 bytes
-rw-r--r--icons/16x16/clear_left.pngbin0 -> 388 bytes
-rw-r--r--icons/16x16/clear_left_r.pngbin0 -> 368 bytes
-rw-r--r--icons/16x16/colorize.pngbin0 -> 1023 bytes
-rw-r--r--icons/16x16/compfile.pngbin0 -> 581 bytes
-rw-r--r--icons/16x16/compfile_this.pngbin0 -> 625 bytes
-rw-r--r--icons/16x16/configure.pngbin0 -> 1055 bytes
-rw-r--r--icons/16x16/configure_shortcuts.pngbin0 -> 1009 bytes
-rw-r--r--icons/16x16/configure_toolbars.pngbin0 -> 1160 bytes
-rw-r--r--icons/16x16/contents.pngbin0 -> 1111 bytes
-rw-r--r--icons/16x16/corner.pngbin0 -> 132 bytes
-rw-r--r--icons/16x16/diode.pngbin0 -> 222 bytes
-rw-r--r--icons/16x16/disasm.pngbin0 -> 574 bytes
-rw-r--r--icons/16x16/dot.pngbin0 -> 283 bytes
-rw-r--r--icons/16x16/dot_g.pngbin0 -> 307 bytes
-rw-r--r--icons/16x16/dot_r.pngbin0 -> 295 bytes
-rw-r--r--icons/16x16/down.pngbin0 -> 406 bytes
-rw-r--r--icons/16x16/down0.pngbin0 -> 593 bytes
-rw-r--r--icons/16x16/edit.pngbin0 -> 691 bytes
-rw-r--r--icons/16x16/editclear.pngbin0 -> 277 bytes
-rw-r--r--icons/16x16/editcopy.pngbin0 -> 777 bytes
-rw-r--r--icons/16x16/editcut.pngbin0 -> 804 bytes
-rw-r--r--icons/16x16/editdelete.pngbin0 -> 892 bytes
-rw-r--r--icons/16x16/editpaste.pngbin0 -> 979 bytes
-rw-r--r--icons/16x16/emacs.pngbin0 -> 632 bytes
-rw-r--r--icons/16x16/emptytrash.pngbin0 -> 691 bytes
-rw-r--r--icons/16x16/eraser.pngbin0 -> 806 bytes
-rw-r--r--icons/16x16/exclamation.pngbin0 -> 297 bytes
-rw-r--r--icons/16x16/exec.pngbin0 -> 854 bytes
-rw-r--r--icons/16x16/exit.pngbin0 -> 830 bytes
-rw-r--r--icons/16x16/fileclose.pngbin0 -> 1027 bytes
-rw-r--r--icons/16x16/filefind.pngbin0 -> 790 bytes
-rw-r--r--icons/16x16/fileimport.pngbin0 -> 851 bytes
-rw-r--r--icons/16x16/filenew.pngbin0 -> 686 bytes
-rw-r--r--icons/16x16/fileopen.pngbin0 -> 1080 bytes
-rw-r--r--icons/16x16/filesave.pngbin0 -> 838 bytes
-rw-r--r--icons/16x16/filesaveas.pngbin0 -> 1104 bytes
-rw-r--r--icons/16x16/filter.pngbin0 -> 820 bytes
-rw-r--r--icons/16x16/find.pngbin0 -> 987 bytes
-rw-r--r--icons/16x16/flag.pngbin0 -> 520 bytes
-rw-r--r--icons/16x16/folder_new.pngbin0 -> 649 bytes
-rw-r--r--icons/16x16/forward.pngbin0 -> 543 bytes
-rw-r--r--icons/16x16/fsview.pngbin0 -> 576 bytes
-rw-r--r--icons/16x16/gear.pngbin0 -> 1003 bytes
-rw-r--r--icons/16x16/gear0.pngbin0 -> 1166 bytes
-rw-r--r--icons/16x16/gear1.pngbin0 -> 1202 bytes
-rw-r--r--icons/16x16/gear2.pngbin0 -> 1190 bytes
-rw-r--r--icons/16x16/gedit.pngbin0 -> 541 bytes
-rw-r--r--icons/16x16/gohome.pngbin0 -> 410 bytes
-rw-r--r--icons/16x16/goto.pngbin0 -> 416 bytes
-rw-r--r--icons/16x16/goto2.pngbin0 -> 645 bytes
-rw-r--r--icons/16x16/graph.pngbin0 -> 194 bytes
-rw-r--r--icons/16x16/green_dot.pngbin0 -> 719 bytes
-rw-r--r--icons/16x16/grid0.pngbin0 -> 173 bytes
-rw-r--r--icons/16x16/grid1.pngbin0 -> 126 bytes
-rw-r--r--icons/16x16/grid2.pngbin0 -> 142 bytes
-rw-r--r--icons/16x16/grid3.pngbin0 -> 140 bytes
-rw-r--r--icons/16x16/gvim.pngbin0 -> 909 bytes
-rw-r--r--icons/16x16/hb.pngbin0 -> 334 bytes
-rw-r--r--icons/16x16/help.pngbin0 -> 746 bytes
-rw-r--r--icons/16x16/hh.pngbin0 -> 278 bytes
-rw-r--r--icons/16x16/html.pngbin0 -> 847 bytes
-rw-r--r--icons/16x16/indent.pngbin0 -> 381 bytes
-rw-r--r--icons/16x16/info.pngbin0 -> 936 bytes
-rw-r--r--icons/16x16/kaboodleloop.pngbin0 -> 844 bytes
-rw-r--r--icons/16x16/kcmdevices.pngbin0 -> 737 bytes
-rw-r--r--icons/16x16/kcmdf.pngbin0 -> 924 bytes
-rw-r--r--icons/16x16/kcmmemory.pngbin0 -> 931 bytes
-rw-r--r--icons/16x16/kcmmemory_B.pngbin0 -> 876 bytes
-rw-r--r--icons/16x16/kcmmemory_BA.pngbin0 -> 885 bytes
-rw-r--r--icons/16x16/kcmmemory_C.pngbin0 -> 872 bytes
-rw-r--r--icons/16x16/kcmmemory_E.pngbin0 -> 862 bytes
-rw-r--r--icons/16x16/kcmmemory_P.pngbin0 -> 883 bytes
-rw-r--r--icons/16x16/kcmmemory_S.pngbin0 -> 889 bytes
-rw-r--r--icons/16x16/kcmmemory_ST.pngbin0 -> 813 bytes
-rw-r--r--icons/16x16/kcmmemory_X.pngbin0 -> 891 bytes
-rw-r--r--icons/16x16/kcmpci.pngbin0 -> 836 bytes
-rw-r--r--icons/16x16/kcmsystem.pngbin0 -> 903 bytes
-rw-r--r--icons/16x16/key_enter.pngbin0 -> 614 bytes
-rw-r--r--icons/16x16/kservices.pngbin0 -> 3481 bytes
-rw-r--r--icons/16x16/kwrite.pngbin0 -> 963 bytes
-rw-r--r--icons/16x16/launch.pngbin0 -> 828 bytes
-rw-r--r--icons/16x16/launch_this.pngbin0 -> 824 bytes
-rw-r--r--icons/16x16/ledblue.pngbin0 -> 733 bytes
-rw-r--r--icons/16x16/ledblue2.pngbin0 -> 710 bytes
-rw-r--r--icons/16x16/leddisplay.pngbin0 -> 1203 bytes
-rw-r--r--icons/16x16/ledgray.pngbin0 -> 604 bytes
-rw-r--r--icons/16x16/ledgrayblue.pngbin0 -> 683 bytes
-rw-r--r--icons/16x16/ledgraygreen.pngbin0 -> 714 bytes
-rw-r--r--icons/16x16/ledgrayorange.pngbin0 -> 562 bytes
-rw-r--r--icons/16x16/ledgraypurple.pngbin0 -> 713 bytes
-rw-r--r--icons/16x16/ledgrayred.pngbin0 -> 684 bytes
-rw-r--r--icons/16x16/ledgrayyellow.pngbin0 -> 664 bytes
-rw-r--r--icons/16x16/ledgreen.pngbin0 -> 703 bytes
-rw-r--r--icons/16x16/ledgreen2.pngbin0 -> 690 bytes
-rw-r--r--icons/16x16/ledmatrix.pngbin0 -> 1166 bytes
-rw-r--r--icons/16x16/ledorange.pngbin0 -> 573 bytes
-rw-r--r--icons/16x16/ledorange2.pngbin0 -> 513 bytes
-rw-r--r--icons/16x16/ledpanel.pngbin0 -> 1160 bytes
-rw-r--r--icons/16x16/ledpurple.pngbin0 -> 717 bytes
-rw-r--r--icons/16x16/ledpurple2.pngbin0 -> 708 bytes
-rw-r--r--icons/16x16/ledred.pngbin0 -> 677 bytes
-rw-r--r--icons/16x16/ledred2.pngbin0 -> 660 bytes
-rw-r--r--icons/16x16/ledyellow.pngbin0 -> 644 bytes
-rw-r--r--icons/16x16/ledyellow2.pngbin0 -> 601 bytes
-rw-r--r--icons/16x16/left.pngbin0 -> 405 bytes
-rw-r--r--icons/16x16/line.pngbin0 -> 178 bytes
-rw-r--r--icons/16x16/locationbar_erase.pngbin0 -> 396 bytes
-rw-r--r--icons/16x16/lock.pngbin0 -> 759 bytes
-rw-r--r--icons/16x16/math_matrix.pngbin0 -> 246 bytes
-rw-r--r--icons/16x16/matrix2.pngbin0 -> 197 bytes
-rw-r--r--icons/16x16/matrixkeypad.pngbin0 -> 1147 bytes
-rw-r--r--icons/16x16/mcu8051ide.pngbin0 -> 352 bytes
-rw-r--r--icons/16x16/mleddisplay.pngbin0 -> 1170 bytes
-rw-r--r--icons/16x16/mouse.pngbin0 -> 3467 bytes
-rw-r--r--icons/16x16/next.pngbin0 -> 895 bytes
-rw-r--r--icons/16x16/no.pngbin0 -> 748 bytes
-rw-r--r--icons/16x16/ok.pngbin0 -> 661 bytes
-rw-r--r--icons/16x16/oval.pngbin0 -> 149 bytes
-rw-r--r--icons/16x16/pencil.pngbin0 -> 3364 bytes
-rw-r--r--icons/16x16/player_pause.pngbin0 -> 319 bytes
-rw-r--r--icons/16x16/player_playlist.pngbin0 -> 327 bytes
-rw-r--r--icons/16x16/player_time.pngbin0 -> 1049 bytes
-rw-r--r--icons/16x16/player_time2.pngbin0 -> 938 bytes
-rw-r--r--icons/16x16/project_open.pngbin0 -> 687 bytes
-rw-r--r--icons/16x16/queue.pngbin0 -> 808 bytes
-rw-r--r--icons/16x16/rebuild.pngbin0 -> 672 bytes
-rw-r--r--icons/16x16/red_dot.pngbin0 -> 731 bytes
-rw-r--r--icons/16x16/redo.pngbin0 -> 628 bytes
-rw-r--r--icons/16x16/reload.pngbin0 -> 463 bytes
-rw-r--r--icons/16x16/reload_red.pngbin0 -> 487 bytes
-rw-r--r--icons/16x16/resume.pngbin0 -> 587 bytes
-rw-r--r--icons/16x16/right.pngbin0 -> 423 bytes
-rw-r--r--icons/16x16/save_all.pngbin0 -> 917 bytes
-rw-r--r--icons/16x16/sb.pngbin0 -> 374 bytes
-rw-r--r--icons/16x16/sh.pngbin0 -> 360 bytes
-rw-r--r--icons/16x16/simplekeypad.pngbin0 -> 1170 bytes
-rw-r--r--icons/16x16/source_c.pngbin0 -> 647 bytes
-rw-r--r--icons/16x16/source_cpp.pngbin0 -> 622 bytes
-rw-r--r--icons/16x16/source_h.pngbin0 -> 628 bytes
-rw-r--r--icons/16x16/spellcheck.pngbin0 -> 554 bytes
-rw-r--r--icons/16x16/status_unknown.pngbin0 -> 571 bytes
-rw-r--r--icons/16x16/sub.pngbin0 -> 328 bytes
-rw-r--r--icons/16x16/symbol.pngbin0 -> 406 bytes
-rw-r--r--icons/16x16/terminal.pngbin0 -> 666 bytes
-rw-r--r--icons/16x16/tex.pngbin0 -> 797 bytes
-rw-r--r--icons/16x16/text_bold.pngbin0 -> 734 bytes
-rw-r--r--icons/16x16/text_italic.pngbin0 -> 660 bytes
-rw-r--r--icons/16x16/text_strike.pngbin0 -> 745 bytes
-rw-r--r--icons/16x16/text_under.pngbin0 -> 725 bytes
-rw-r--r--icons/16x16/today.pngbin0 -> 868 bytes
-rw-r--r--icons/16x16/top.pngbin0 -> 443 bytes
-rw-r--r--icons/16x16/undo.pngbin0 -> 585 bytes
-rw-r--r--icons/16x16/unindent.pngbin0 -> 381 bytes
-rw-r--r--icons/16x16/unlock.pngbin0 -> 923 bytes
-rw-r--r--icons/16x16/up.pngbin0 -> 412 bytes
-rw-r--r--icons/16x16/up0.pngbin0 -> 572 bytes
-rw-r--r--icons/16x16/usb.pngbin0 -> 695 bytes
-rw-r--r--icons/16x16/vcs_commit.pngbin0 -> 908 bytes
-rw-r--r--icons/16x16/vcs_update.pngbin0 -> 869 bytes
-rw-r--r--icons/16x16/view_choose.pngbin0 -> 646 bytes
-rw-r--r--icons/16x16/view_detailed.pngbin0 -> 597 bytes
-rw-r--r--icons/16x16/view_icon.pngbin0 -> 610 bytes
-rw-r--r--icons/16x16/view_left_right.pngbin0 -> 522 bytes
-rw-r--r--icons/16x16/view_remove.pngbin0 -> 484 bytes
-rw-r--r--icons/16x16/view_text.pngbin0 -> 283 bytes
-rw-r--r--icons/16x16/view_top_bottom.pngbin0 -> 510 bytes
-rw-r--r--icons/16x16/viewmag_in.pngbin0 -> 810 bytes
-rw-r--r--icons/16x16/viewmag_out.pngbin0 -> 800 bytes
-rw-r--r--icons/16x16/window_fullscreen.pngbin0 -> 785 bytes
-rw-r--r--icons/16x16/xcalc.pngbin0 -> 676 bytes
-rw-r--r--icons/22x22/1downarrow.pngbin0 -> 722 bytes
-rw-r--r--icons/22x22/1leftarrow.pngbin0 -> 832 bytes
-rw-r--r--icons/22x22/1rightarrow.pngbin0 -> 807 bytes
-rw-r--r--icons/22x22/1uparrow.pngbin0 -> 787 bytes
-rw-r--r--icons/22x22/2rightarrow.pngbin0 -> 1084 bytes
-rw-r--r--icons/22x22/8seg.pngbin0 -> 212 bytes
-rw-r--r--icons/22x22/_chardevice.pngbin0 -> 1150 bytes
-rw-r--r--icons/22x22/_kcmdf.pngbin0 -> 1078 bytes
-rw-r--r--icons/22x22/back.pngbin0 -> 1348 bytes
-rw-r--r--icons/22x22/bar0.pngbin0 -> 139 bytes
-rw-r--r--icons/22x22/bar1.pngbin0 -> 126 bytes
-rw-r--r--icons/22x22/bar5.pngbin0 -> 2454 bytes
-rw-r--r--icons/22x22/binary.pngbin0 -> 1183 bytes
-rw-r--r--icons/22x22/bookmark.pngbin0 -> 996 bytes
-rw-r--r--icons/22x22/bookmark_folder.pngbin0 -> 1101 bytes
-rw-r--r--icons/22x22/change_case.pngbin0 -> 516 bytes
-rw-r--r--icons/22x22/chardevice.pngbin0 -> 1229 bytes
-rw-r--r--icons/22x22/compfile.pngbin0 -> 729 bytes
-rw-r--r--icons/22x22/compfile_this.pngbin0 -> 746 bytes
-rw-r--r--icons/22x22/configure.pngbin0 -> 3797 bytes
-rw-r--r--icons/22x22/contents.pngbin0 -> 1300 bytes
-rw-r--r--icons/22x22/desktop.pngbin0 -> 1194 bytes
-rw-r--r--icons/22x22/disasm.pngbin0 -> 1069 bytes
-rw-r--r--icons/22x22/editclear.pngbin0 -> 203 bytes
-rw-r--r--icons/22x22/editcopy.pngbin0 -> 507 bytes
-rw-r--r--icons/22x22/editcut.pngbin0 -> 1196 bytes
-rw-r--r--icons/22x22/editdelete.pngbin0 -> 951 bytes
-rw-r--r--icons/22x22/editpaste.pngbin0 -> 881 bytes
-rw-r--r--icons/22x22/emptytrash.pngbin0 -> 1256 bytes
-rw-r--r--icons/22x22/exit.pngbin0 -> 1221 bytes
-rw-r--r--icons/22x22/fileclose.pngbin0 -> 1119 bytes
-rw-r--r--icons/22x22/filenew.pngbin0 -> 825 bytes
-rw-r--r--icons/22x22/fileopen.pngbin0 -> 1356 bytes
-rw-r--r--icons/22x22/filesave.pngbin0 -> 821 bytes
-rw-r--r--icons/22x22/filesaveas.pngbin0 -> 1137 bytes
-rw-r--r--icons/22x22/filter.pngbin0 -> 1168 bytes
-rw-r--r--icons/22x22/find.pngbin0 -> 1278 bytes
-rw-r--r--icons/22x22/flag.pngbin0 -> 770 bytes
-rw-r--r--icons/22x22/folder_home.pngbin0 -> 1199 bytes
-rw-r--r--icons/22x22/folder_new.pngbin0 -> 1278 bytes
-rw-r--r--icons/22x22/fork.pngbin0 -> 1263 bytes
-rw-r--r--icons/22x22/fork_this.pngbin0 -> 1175 bytes
-rw-r--r--icons/22x22/forward.pngbin0 -> 1311 bytes
-rw-r--r--icons/22x22/fsview.pngbin0 -> 950 bytes
-rw-r--r--icons/22x22/gear.pngbin0 -> 1408 bytes
-rw-r--r--icons/22x22/gear0.pngbin0 -> 1158 bytes
-rw-r--r--icons/22x22/gear0_play.pngbin0 -> 1185 bytes
-rw-r--r--icons/22x22/gear1.pngbin0 -> 1176 bytes
-rw-r--r--icons/22x22/gear1_play.pngbin0 -> 1239 bytes
-rw-r--r--icons/22x22/gear2.pngbin0 -> 1150 bytes
-rw-r--r--icons/22x22/gear2_play.pngbin0 -> 1218 bytes
-rw-r--r--icons/22x22/goto.pngbin0 -> 896 bytes
-rw-r--r--icons/22x22/goto2.pngbin0 -> 1246 bytes
-rw-r--r--icons/22x22/hdd_unmount.pngbin0 -> 1296 bytes
-rw-r--r--icons/22x22/help.pngbin0 -> 1186 bytes
-rw-r--r--icons/22x22/history.pngbin0 -> 1515 bytes
-rw-r--r--icons/22x22/history2.pngbin0 -> 1376 bytes
-rw-r--r--icons/22x22/html.pngbin0 -> 1336 bytes
-rw-r--r--icons/22x22/kaboodleloop.pngbin0 -> 1199 bytes
-rw-r--r--icons/22x22/kcmdf.pngbin0 -> 1152 bytes
-rw-r--r--icons/22x22/kcmsystem.pngbin0 -> 1536 bytes
-rw-r--r--icons/22x22/leddisplay.pngbin0 -> 333 bytes
-rw-r--r--icons/22x22/ledmatrix.pngbin0 -> 138 bytes
-rw-r--r--icons/22x22/ledpanel.pngbin0 -> 151 bytes
-rw-r--r--icons/22x22/math_matrix.pngbin0 -> 177 bytes
-rw-r--r--icons/22x22/matrixkeypad.pngbin0 -> 237 bytes
-rw-r--r--icons/22x22/mcu8051ide.pngbin0 -> 958 bytes
-rw-r--r--icons/22x22/memory.pngbin0 -> 960 bytes
-rw-r--r--icons/22x22/memory_B.pngbin0 -> 1091 bytes
-rw-r--r--icons/22x22/memory_BA.pngbin0 -> 1099 bytes
-rw-r--r--icons/22x22/memory_C.pngbin0 -> 1088 bytes
-rw-r--r--icons/22x22/memory_E.pngbin0 -> 1040 bytes
-rw-r--r--icons/22x22/memory_P.pngbin0 -> 1060 bytes
-rw-r--r--icons/22x22/memory_S.pngbin0 -> 1115 bytes
-rw-r--r--icons/22x22/memory_ST.pngbin0 -> 971 bytes
-rw-r--r--icons/22x22/memory_X.pngbin0 -> 1112 bytes
-rw-r--r--icons/22x22/mleddisplay.pngbin0 -> 177 bytes
-rw-r--r--icons/22x22/pencil.pngbin0 -> 3659 bytes
-rw-r--r--icons/22x22/player_pause.pngbin0 -> 1191 bytes
-rw-r--r--icons/22x22/player_play.pngbin0 -> 1263 bytes
-rw-r--r--icons/22x22/project_open.pngbin0 -> 790 bytes
-rw-r--r--icons/22x22/rebuild.pngbin0 -> 904 bytes
-rw-r--r--icons/22x22/redo.pngbin0 -> 736 bytes
-rw-r--r--icons/22x22/reload.pngbin0 -> 1420 bytes
-rw-r--r--icons/22x22/resume.pngbin0 -> 854 bytes
-rw-r--r--icons/22x22/run.pngbin0 -> 1354 bytes
-rw-r--r--icons/22x22/save_all.pngbin0 -> 999 bytes
-rw-r--r--icons/22x22/simplekeypad.pngbin0 -> 142 bytes
-rw-r--r--icons/22x22/stop.pngbin0 -> 1330 bytes
-rw-r--r--icons/22x22/symbol.pngbin0 -> 493 bytes
-rw-r--r--icons/22x22/tex.pngbin0 -> 1247 bytes
-rw-r--r--icons/22x22/undo.pngbin0 -> 683 bytes
-rw-r--r--icons/22x22/view_detailed.pngbin0 -> 697 bytes
-rw-r--r--icons/22x22/view_icon.pngbin0 -> 742 bytes
-rw-r--r--icons/22x22/window_fullscreen.pngbin0 -> 912 bytes
-rw-r--r--icons/22x22/window_nofullscreen.pngbin0 -> 927 bytes
-rw-r--r--icons/22x22/xcalc.pngbin0 -> 1203 bytes
-rw-r--r--icons/32x32/button_ok.pngbin0 -> 1393 bytes
-rw-r--r--icons/32x32/configure.pngbin0 -> 1839 bytes
-rw-r--r--icons/32x32/exec.pngbin0 -> 2296 bytes
-rw-r--r--icons/32x32/fileclose.pngbin0 -> 1594 bytes
-rw-r--r--icons/32x32/help.pngbin0 -> 1587 bytes
-rw-r--r--icons/32x32/kcmmemory.pngbin0 -> 1986 bytes
-rw-r--r--icons/32x32/mcu8051ide.pngbin0 -> 815 bytes
-rw-r--r--icons/32x32/messagebox_critical.pngbin0 -> 1591 bytes
-rw-r--r--icons/32x32/messagebox_info.pngbin0 -> 2362 bytes
-rw-r--r--icons/32x32/messagebox_warning.pngbin0 -> 1692 bytes
-rw-r--r--icons/32x32/user_away.pngbin0 -> 2027 bytes
-rw-r--r--icons/32x32/wizard.pngbin0 -> 1325 bytes
-rw-r--r--icons/mcu/8031.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/8032.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/8051.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/8052.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/80C31.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/80C31X2.pngbin0 -> 6578 bytes
-rw-r--r--icons/mcu/80C32.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/80C32X2.pngbin0 -> 6937 bytes
-rw-r--r--icons/mcu/80C51.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/80C52.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/80C52X2.pngbin0 -> 6937 bytes
-rw-r--r--icons/mcu/80C54.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/80C54X2.pngbin0 -> 6710 bytes
-rw-r--r--icons/mcu/80C58.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/80C58X2.pngbin0 -> 6710 bytes
-rw-r--r--icons/mcu/8731.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/8751.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/8752.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/87C51.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/87C52.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/87C52X2.pngbin0 -> 6937 bytes
-rw-r--r--icons/mcu/87C54.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/87C54X2.pngbin0 -> 6710 bytes
-rw-r--r--icons/mcu/87C58.pngbin0 -> 3841 bytes
-rw-r--r--icons/mcu/87C58X2.pngbin0 -> 6710 bytes
-rw-r--r--icons/mcu/AT80C31X2.pngbin0 -> 4218 bytes
-rw-r--r--icons/mcu/AT80C32X2.pngbin0 -> 4546 bytes
-rw-r--r--icons/mcu/AT80C52X2.pngbin0 -> 4546 bytes
-rw-r--r--icons/mcu/AT80C54X2.pngbin0 -> 4380 bytes
-rw-r--r--icons/mcu/AT80C58X2.pngbin0 -> 4380 bytes
-rw-r--r--icons/mcu/AT87C52X2.pngbin0 -> 4546 bytes
-rw-r--r--icons/mcu/AT87C54X2.pngbin0 -> 4380 bytes
-rw-r--r--icons/mcu/AT87C58X2.pngbin0 -> 4380 bytes
-rw-r--r--icons/mcu/AT89C2051.pngbin0 -> 3579 bytes
-rw-r--r--icons/mcu/AT89C4051.pngbin0 -> 3579 bytes
-rw-r--r--icons/mcu/AT89C51.pngbin0 -> 3678 bytes
-rw-r--r--icons/mcu/AT89C51RC.pngbin0 -> 4055 bytes
-rw-r--r--icons/mcu/AT89C52.pngbin0 -> 4150 bytes
-rw-r--r--icons/mcu/AT89C55WD.pngbin0 -> 3208 bytes
-rw-r--r--icons/mcu/AT89LP2052.pngbin0 -> 3892 bytes
-rw-r--r--icons/mcu/AT89LS51.pngbin0 -> 4096 bytes
-rw-r--r--icons/mcu/AT89LS52.pngbin0 -> 3236 bytes
-rw-r--r--icons/mcu/AT89LV51.pngbin0 -> 4256 bytes
-rw-r--r--icons/mcu/AT89LV52.pngbin0 -> 4554 bytes
-rw-r--r--icons/mcu/AT89LV55.pngbin0 -> 4823 bytes
-rw-r--r--icons/mcu/AT89S2051.pngbin0 -> 3752 bytes
-rw-r--r--icons/mcu/AT89S4051.pngbin0 -> 3752 bytes
-rw-r--r--icons/mcu/AT89S52.pngbin0 -> 3805 bytes
-rw-r--r--icons/mcu/AT89S8253.pngbin0 -> 4961 bytes
-rw-r--r--icons/mcu/T83C5101.pngbin0 -> 4084 bytes
-rw-r--r--icons/mcu/T83C5102.pngbin0 -> 4084 bytes
-rw-r--r--icons/mcu/T87C5101.pngbin0 -> 4084 bytes
-rw-r--r--icons/mcu/TS80C31X2.pngbin0 -> 4218 bytes
-rw-r--r--icons/mcu/TS80C32X2.pngbin0 -> 4546 bytes
-rw-r--r--icons/mcu/TS80C52X2.pngbin0 -> 4546 bytes
-rw-r--r--icons/mcu/TS80C54X2.pngbin0 -> 4380 bytes
-rw-r--r--icons/mcu/TS80C58X2.pngbin0 -> 4380 bytes
-rw-r--r--icons/mcu/TS87C52X2.pngbin0 -> 4546 bytes
-rw-r--r--icons/mcu/TS87C54X2.pngbin0 -> 4380 bytes
-rw-r--r--icons/mcu/TS87C58X2.pngbin0 -> 4380 bytes
-rw-r--r--icons/other/choff.pngbin0 -> 194 bytes
-rw-r--r--icons/other/chon.pngbin0 -> 277 bytes
-rw-r--r--icons/other/ibrg_brg.pngbin0 -> 7148 bytes
-rw-r--r--icons/other/math0.pngbin0 -> 2226 bytes
-rw-r--r--icons/other/raoff.pngbin0 -> 288 bytes
-rw-r--r--icons/other/raon.pngbin0 -> 310 bytes
-rw-r--r--icons/other/splash.pngbin0 -> 44991 bytes
-rw-r--r--icons/other/timer2_updown.pngbin0 -> 25219 bytes
-rw-r--r--icons/other/timer_01_0.pngbin0 -> 14260 bytes
-rw-r--r--icons/other/timer_01_0e.pngbin0 -> 14063 bytes
-rw-r--r--icons/other/timer_01_1.pngbin0 -> 13326 bytes
-rw-r--r--icons/other/timer_01_1e.pngbin0 -> 14909 bytes
-rw-r--r--icons/other/timer_01_2.pngbin0 -> 15211 bytes
-rw-r--r--icons/other/timer_01_2e.pngbin0 -> 12764 bytes
-rw-r--r--icons/other/timer_brg.pngbin0 -> 11820 bytes
-rwxr-xr-xinstall.sh102
-rwxr-xr-xlib/X.tcl10648
-rwxr-xr-xlib/bottompanel/bottomnotebook.tcl469
-rwxr-xr-xlib/bottompanel/calculator.tcl2071
-rwxr-xr-xlib/bottompanel/cvarsview.tcl1303
-rwxr-xr-xlib/bottompanel/find_in_files.tcl750
-rwxr-xr-xlib/bottompanel/graph.tcl714
-rwxr-xr-xlib/bottompanel/graph_wdg.tcl1115
-rwxr-xr-xlib/bottompanel/messages.tcl632
-rwxr-xr-xlib/bottompanel/terminal.tcl135
-rwxr-xr-xlib/bottompanel/todo.tcl1496
-rwxr-xr-xlib/cli.tcl725
-rwxr-xr-xlib/compiler/assembler.tcl595
-rwxr-xr-xlib/compiler/codelisting.tcl1169
-rwxr-xr-xlib/compiler/compiler.tcl557
-rwxr-xr-xlib/compiler/compilerconsts.tcl873
-rwxr-xr-xlib/compiler/disassembler.tcl664
-rwxr-xr-xlib/compiler/external_compiler.tcl1076
-rwxr-xr-xlib/compiler/preprocessor.tcl5184
-rwxr-xr-xlib/configdialogs/compiler_config.tcl1875
-rwxr-xr-xlib/configdialogs/configdialogs.tcl51
-rwxr-xr-xlib/configdialogs/custom_commands_config.tcl418
-rwxr-xr-xlib/configdialogs/editor_config.tcl2148
-rwxr-xr-xlib/configdialogs/global_config.tcl318
-rwxr-xr-xlib/configdialogs/rightpanel_config.tcl498
-rwxr-xr-xlib/configdialogs/shortcuts_config.tcl1015
-rwxr-xr-xlib/configdialogs/simulator_config.tcl423
-rwxr-xr-xlib/configdialogs/terminal_config.tcl374
-rwxr-xr-xlib/configdialogs/toolbar_config.tcl706
-rwxr-xr-xlib/custom_command.tcl98
-rwxr-xr-xlib/dialogs/errorhandler.tcl172
-rwxr-xr-xlib/dialogs/fsd.tcl2775
-rwxr-xr-xlib/dialogs/my_tk_messageBox.tcl283
-rwxr-xr-xlib/dialogs/selectmcu.tcl1537
-rwxr-xr-xlib/dialogs/tips.tcl375
-rwxr-xr-xlib/editor/ASMsyntaxhighlight.tcl1675
-rwxr-xr-xlib/editor/Csyntaxhighlight.tcl853
-rwxr-xr-xlib/editor/LSTsyntaxhighlight.tcl443
-rwxr-xr-xlib/editor/R_ASMsyntaxhighlight.tcl1232
-rwxr-xr-xlib/editor/autocompletion.tcl838
-rwxr-xr-xlib/editor/commandline.tcl1275
-rwxr-xr-xlib/editor/editor.tcl2786
-rwxr-xr-xlib/editor/eventhandlers.tcl781
-rwxr-xr-xlib/editor/exports.tcl486
-rwxr-xr-xlib/editor/generalproc.tcl2288
-rwxr-xr-xlib/environment.tcl3184
-rwxr-xr-xlib/external_command.tcl143
-rwxr-xr-xlib/leftpanel/filelist.tcl4824
-rwxr-xr-xlib/leftpanel/fsbrowser.tcl1164
-rwxr-xr-xlib/leftpanel/sfrwatches.tcl620
-rwxr-xr-xlib/lib/Math.tcl954
-rwxr-xr-xlib/lib/hexeditor.tcl2705
-rwxr-xr-xlib/lib/ihextools.tcl523
-rwxr-xr-xlib/lib/innerwindow.tcl360
-rwxr-xr-xlib/lib/settings.tcl293
-rwxr-xr-xlib/main.tcl699
-rwxr-xr-xlib/maintab.tcl425
-rwxr-xr-xlib/pale/leddisplay.tcl707
-rwxr-xr-xlib/pale/ledmatrix.tcl982
-rwxr-xr-xlib/pale/ledpanel.tcl543
-rwxr-xr-xlib/pale/matrixkeypad.tcl889
-rwxr-xr-xlib/pale/multiplexedleddisplay.tcl1179
-rwxr-xr-xlib/pale/pale.tcl991
-rwxr-xr-xlib/pale/simplekeypad.tcl670
-rwxr-xr-xlib/pale/virtual_hw_component.tcl423
-rwxr-xr-xlib/project.tcl868
-rwxr-xr-xlib/rightpanel/hwmanager.tcl419
-rwxr-xr-xlib/rightpanel/instructiondetails.tcl1755
-rwxr-xr-xlib/rightpanel/regwatches.tcl2120
-rwxr-xr-xlib/rightpanel/rightpanel.tcl2273
-rwxr-xr-xlib/rightpanel/subprograms.tcl704
-rwxr-xr-xlib/simulator/bitmap.tcl510
-rwxr-xr-xlib/simulator/engine/engine_auxiliary_alo_functions.tcl171
-rwxr-xr-xlib/simulator/engine/engine_backward_stepping.tcl126
-rwxr-xr-xlib/simulator/engine/engine_control.tcl759
-rwxr-xr-xlib/simulator/engine/engine_core.tcl274
-rwxr-xr-xlib/simulator/engine/engine_external_interface_management.tcl1115
-rwxr-xr-xlib/simulator/engine/engine_hibernation.tcl205
-rwxr-xr-xlib/simulator/engine/engine_initialization_cleanup.tcl340
-rwxr-xr-xlib/simulator/engine/engine_instructions.tcl1596
-rwxr-xr-xlib/simulator/engine/engine_mcu_configuration.tcl555
-rwxr-xr-xlib/simulator/engine/engine_memory_management.tcl387
-rwxr-xr-xlib/simulator/engine/engine_opcodes.tcl435
-rwxr-xr-xlib/simulator/engine/engine_virtual_hw_controller.tcl1413
-rwxr-xr-xlib/simulator/hibernate.tcl1051
-rwxr-xr-xlib/simulator/interruptmonitor.tcl1246
-rwxr-xr-xlib/simulator/sfrmap.tcl523
-rwxr-xr-xlib/simulator/simulator.tcl1202
-rwxr-xr-xlib/simulator/simulator_gui.tcl3986
-rwxr-xr-xlib/simulator/stackmonitor.tcl519
-rwxr-xr-xlib/simulator/stopwatch.tcl702
-rwxr-xr-xlib/simulator/virtual_uart_term.tcl646
-rwxr-xr-xlib/utilities/asciichart.tcl752
-rwxr-xr-xlib/utilities/baseconvertor.tcl912
-rwxr-xr-xlib/utilities/eightsegment.tcl509
-rwxr-xr-xlib/utilities/hexeditdlg.tcl1793
-rwxr-xr-xlib/utilities/notes.tcl896
-rwxr-xr-xlib/utilities/rs232debugger.tcl1460
-rwxr-xr-xlib/utilities/speccalc.tcl2390
-rwxr-xr-xlib/utilities/symbol_viewer.tcl837
-rwxr-xr-xmake-launcher59
-rw-r--r--mcu8051ide.desktop21
-rw-r--r--mcu8051ide.pngbin0 -> 1941 bytes
-rwxr-xr-xtest-lib.sh41
-rw-r--r--translations/README1
601 files changed, 132491 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..c8e16d6
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,117 @@
+PROJECT(mcu8051ide)
+
+#
+# INITIALIZE
+#
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.4.2)
+SET(CMAKE_BUILD_TYPE None)
+SET(CMAKE_COLOR_MAKEFILE ON)
+SET(CMAKE_VERBOSE_MAKEFILE ON)
+SET(CMAKE_INCLUDE_CURRENT_DIR TRUE)
+
+# target directory (for data files)
+SET(target_installation_directory /usr/share/mcu8051ide)
+
+#
+# CONFIGURE
+#
+
+MESSAGE("Check for Tcl Interpreter")
+FIND_PACKAGE(TCL)
+IF(NOT TCL_FOUND)
+ MESSAGE("!!! TCL interpreter not found !!!")
+ENDIF(NOT TCL_FOUND)
+
+FOREACH(library
+ "BWidget 1.8"
+ "Itcl 3.4"
+ "Tcl 8.5"
+ "md5 2.0"
+ "Tk 8.5"
+ "img::png 1.3"
+ "tdom 0.8"
+ "Tclx 8.4"
+)
+ STRING(REGEX REPLACE "\t+.*$" "" library_name ${library})
+ MESSAGE("Check for ${library_name}")
+
+ EXECUTE_PROCESS(
+ COMMAND "./test-lib.sh ${library}"
+ RESULT_VARIABLE library_found
+ )
+
+ IF(NOT library_found)
+ MESSAGE(FATAL_ERROR "Unable to find library: ${library}")
+ ENDIF(NOT library_found)
+
+ENDFOREACH(library)
+
+
+#
+# BUILD
+#
+
+# create launcher
+FILE(WRITE mcu8051ide
+ "#!/bin/sh\n"
+ "exec tclsh ${target_installation_directory}/lib/main.tcl \"$@\"\n"
+)
+
+#
+# INSTALL
+#
+
+# Install icons
+FOREACH(subdir mcu other 16x16 22x22 32x32)
+ FILE(GLOB_RECURSE icons icons/${subdir}/*.png)
+ INSTALL(FILES ${icons} DESTINATION ${target_installation_directory}/icons/${subdir})
+ENDFOREACH(subdir)
+
+# Install source code files
+FOREACH(subdir . bottompanel compiler configdialogs dialogs editor leftpanel lib pale rightpanel simulator simulator/engine utilities)
+ FILE(GLOB lib lib/${subdir}/*.tcl)
+ INSTALL(FILES ${lib} DESTINATION ${target_installation_directory}/lib/${subdir})
+ENDFOREACH(subdir)
+
+# Install documentation files
+FOREACH(subdir handbook)
+ FILE(GLOB doc doc/${subdir}/*)
+ INSTALL(FILES ${doc} DESTINATION ${target_installation_directory}/doc/${subdir})
+ENDFOREACH(subdir)
+
+# Install manual page(s)
+FILE(GLOB man doc/man/*)
+INSTALL(FILES ${man} DESTINATION /usr/share/man/man1)
+
+# Install demonstration project files
+FILE(GLOB demo demo/*)
+INSTALL(FILES ${demo} DESTINATION ${target_installation_directory}/demo)
+
+# Install data files
+FILE(GLOB data data/*)
+INSTALL(FILES ${data} DESTINATION ${target_installation_directory}/data)
+
+# Install translation files
+FILE(GLOB translations translations/*)
+INSTALL(FILES ${translations} DESTINATION ${target_installation_directory}/translations)
+
+# Incstall .desktop spec and application icon
+INSTALL(FILES mcu8051ide.png DESTINATION /usr/share/pixmaps/)
+INSTALL(FILES mcu8051ide.desktop DESTINATION /usr/share/applications/)
+
+# Install launcher
+INSTALL(
+ FILES mcu8051ide
+ DESTINATION /usr/bin
+ PERMISSIONS
+ WORLD_EXECUTE WORLD_READ
+ OWNER_WRITE OWNER_READ OWNER_EXECUTE
+ GROUP_EXECUTE GROUP_READ
+)
+
+# Install misc. files
+INSTALL(
+ FILES ChangeLog LICENSE TODO
+ DESTINATION ${target_installation_directory}
+)
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..0138273
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,198 @@
+Change log for MCU 8051 IDE
+
+1.3.7 -> 1.3.7
+ * Bug fixes
+
+1.3.5 -> 1.3.6
+ * Bug fixes
+
+1.3.4 -> 1.3.5
+ * Bug fixes
+
+1.3.3 -> 1.3.4
+ * "Modernized" GUI
+ * Bug fixes
+
+1.3.1 -> 1.3.3
+ * Bug fixes
+
+1.3.1 -> 1.3.2
+ * Bug fixes
+
+1.3 -> 1.3.1
+ * Dependency on TclX is now only optional
+ * Important chage !: Native assembler now expands macro instructions before doing conditional assembly and before defining constants and variables ! Control sequence $NOMACROSFIRST can be used to change this behavior to the state of previous versions.
+ * Added support for AS31 assembler
+ * Added files notepad
+ * Improved instruction help panel
+ * Native assembler was extended to support these directives: "IFN IFDEF IFNDEF BYTE FLAG REPT TIMES" and these constrol sequences: "$NOXR $NOXREF $XR $XREF $NOSB $SB $RESTORE $RS $SA $SAVE $PHILIPS $NOPI $PI $NOTABS $NOMOD51 $NOBUILTIN $NOMO $MO $MOD51 $NOMACRO $NOMR $LI $NOLI $GENONLY $GO $NOGEN $NOGE $GEN $GE $ $EJ $NODB $NODEBUG $DB $DEBUG $CONDONLY $NOCOND $COND $TT $PW $PL $MR $MACRO $INC $WARNING $ERROR $DA $NOMACROSFIRST"
+ * Added stack monitor
+ * Various bug fixes
+
+1.2 -> 1.3
+ * New dependency: TclX (tested with v8.4)
+ * Added RS232/UART debugger
+ * A few changes in assembler
+ * Bug fixes (Thanks to Miroslav Hradílek for many useful bug reports)
+
+1.1.1 -> 1.2
+ * Bug fixes
+ * Added tab bar
+
+1.1 -> 1.1.1
+ * Added "Special calculator"
+ * Added "Base convertor"
+ * Many tiny improvements
+
+1.0.9 -> 1.1
+ * Added support for new MCUs from Intel®: 8031, 8751, 8032, 8752, 80C31, 87C51, 80C52, 87C52, 80C32, 80C54, 87C54, 80C58, 87C58
+ * Added support for simulationg virtual hardware
+ * Improved simulator (Implemented UART (experimental support), improved support for timers, etc.)
+ * Improved register watches
+ * Improved editor (improved autocompletion and many other things)
+ * Improved panel "Instruction details"
+ * Improved 8-segment editor
+ * Bug fixes in assembler, disassembler and simulator engine
+ * Some other bug fixes
+ * Added utility "Scrible notepad"
+ * Improved graph panel
+
+1.0.7 -> 1.0.9
+ * Added support for C language
+ * Added map of bit addressable area
+
+1.0.6 -> 1.0.7
+ * Added Stopwatch
+ * Improved code editor
+ * Some bug fixes
+
+1.0.5 -> 1.0.6
+ * Fixed critical bug in Assembler v1.0.5 (related to peerhole optimalizations)
+ * Added 8 segment LED display editor
+ * Added ASCII chart
+ * Added Assembly symbol table viewer
+
+1.0 -> 1.0.5
+ * Added support for external assemblers ("ASEM-51" and "ASL")
+ * Added support for external editors ("emacs", "gvim", "kwrite" and "gedit")
+ * Added support for embedded editors ("emacs", "vim", "nano", "dav" and "le")
+ * Added embedded terminal emulator (rxvt-unicode)
+ * Added function "File statistics"
+ * Improved assembler
+ * Added syntaxt highlight for code listing (*.lst)
+ * Added search bars for "Messages" and "Todo"
+ * Removed dependency on "tcl-thread" and "tclxml"
+ * Added dependency on "TkImg" and "tdom"
+ * Improved hexeditor
+ * Improved simulator (especialy simulation across multiple files)
+ * Added panel "Find in files"
+ * Modified GUI
+ * New error handling dialog
+ * Some bug fixes (especialy critical bug in disassembler and a few bugs in assembler)
+ * All images are now in PNG (Portable Network Graphics) (Reguires TkImg)
+ * Some more improvements
+
+0.9.5 -> 1.0
+ * MANY BUG FIXES ! (including critical)
+ * Added support for some new MCUs (
+ AT89S52, AT89LS51, AT89LS52, AT89S8253, AT89S2051, AT89S4051,
+ T87C5101, T83C5101, T83C5102, TS80C32X2, TS80C52X2, TS87C52X2,
+ AT80C32X2, AT80C52X2, AT87C52X2, AT80C54X2, AT80C58X2, AT87C54X2,
+ AT87C58X2, TS80C54X2, TS80C58X2, TS87C54X2, TS87C58X2, TS80C31X2,
+ AT80C31X2
+ )
+ * Added supprort for peerhole optimalizations
+ * Faster project opening
+ * Added interrupt monitor
+ * Added subprograms monitor
+ * Added SFR map
+ * Added SFR watches
+ * Extended command line interface
+ * Compiler now checks for valid memory addressing (new CLI options --iram-size, --eram-size, --xram-size, --code-size)
+ * Added program hibernation capability
+ * Added editor commands hibernate, resume, switch-mcu, set-xcode and set-xdata
+ * Added desktop file and application icon
+ * Some more improvements
+
+0.9.1 -> 0.9.5
+ * Implemented support for 80C51, 8052, AT89C2051, AT89C4051, AT89C51, AT89C51RC, AT89C52, AT89C55WD, AT89LV51, AT89LV52 and AT89LV55
+ * Simulator can now step back
+ * Added popup-based completion for editor
+ * Added tooltips for bits in simulator control panel
+ * Added simulator configuration dialog
+ * Added autosave function
+ * Manual page
+ * Added support for multiview (editor can be now splitted verticaly or horizontaly)
+ * Many bug fixes (in compiler, editor, file selection dialog, syntax highlight, simulator, etc.)
+ * Some minor improvements (graph, disassembler, etc.)
+ * Thread extension is no longer required to run this program (but custom commands will won't work without it)
+
+0.9.0 -> 0.9.1
+ * New hexadecimal editor
+ * New file selection dialog
+ * Added filesystem browser tab on left panel
+ * Added tips on startup
+ * Added editor command line
+ * Improved editor configuration dialog
+ * A few bug fixes
+ * Removed dependency on IWidgets and Tix
+ * Some minor improvements
+
+0.8.7 -> 0.9.0
+ * Implemented graph
+ * Many bug fixes (GUI, compiler, memory leaks)
+ * Editable shortcuts
+ * Bookmarks for opened and project files
+ * Search panels in left and right panel
+ * Modified GUI (checkboxes, radio buttons ...)
+ * Support for various encodings and EOLs
+ * Added "Tools" -> "Change letter case", "Normalize HEX" and "SIM -> BIN"
+ * Added editor functions "Lowercase", "Uppercase" and "Capitalize"
+ * Added helpwindows for opened and project files and opened projects
+ * Added popup menus for entry and text widgets (globaly)
+ * Fixed problem with fonts (bad sizes)
+ * Implemented support for line wrapping (experimental)
+ * Added new command line options (see `mcu8051ide --help')
+ * More status tips and tool tips
+ * Added welcome dialog
+ * Added demonstration project
+ * Cleaner, faster and safer compiler
+ * Some more minor improvements
+
+0.8.5 -> 0.8.7
+ * Implemented code validation
+ * Added tab "Instruction details" (on the right panel)
+ * Added Clean Up dialog
+ * Added Right Panel configuration dialog
+ * Added Toolbar configuration dialog
+ * Added support for custom commands
+ * Fixed some bugs (in GUI)
+ * Fixed many memory leaks
+ * Cleaner code
+
+0.8.4 -> 0.8.5
+ * Fixed many bugs in GUI
+ * Improved editor
+ * Extended calculator
+ * Redesigned editor config dialog
+ * Added functions "Tools -> Reformat code" and "Tools -> Sim2Hex"
+ * Extended CLI (--reset-user-settings, --config-file, --compile, --hex2bin ...)
+
+0.8.1 -> 0.8.4
+ * Fixed many bugs ... (including critical)
+ * Added compiler configuration dialog
+ * Added calculator timers preset
+ * Added dialog about
+ * Added support for exporting highlighted source code to LaTeX source
+ * Added many ToolTips
+ * Added StatusBar tips
+ * Added splash screen
+ * Added support for command line options
+ * All images are now *.XPM (X PixMap) (require Tix package)
+ * Changed instalation procedure
+
+0.8.0 -> 0.8.1
+ * Fixed some bugs in compiler (not critical)
+ * Fixed bug in todo list (saving text as SGML)
+ * Fixed bug in project management
+ * Added popup menu to todo list
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bb68321
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,341 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundations software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each authors protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyones free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Programs
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the programs name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c for details.
+
+The hypothetical commands `show w and `show c should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w and `show c; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/MicrosoftWindows_compatibility/external_command.bat b/MicrosoftWindows_compatibility/external_command.bat
new file mode 100644
index 0000000..934e804
--- /dev/null
+++ b/MicrosoftWindows_compatibility/external_command.bat
@@ -0,0 +1 @@
+@tclsh85.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file
diff --git a/MicrosoftWindows_compatibility/mcu8051ide.ico b/MicrosoftWindows_compatibility/mcu8051ide.ico
new file mode 100644
index 0000000..c068526
--- /dev/null
+++ b/MicrosoftWindows_compatibility/mcu8051ide.ico
Binary files differ
diff --git a/MicrosoftWindows_compatibility/mcu8051ide_win_setup.iss b/MicrosoftWindows_compatibility/mcu8051ide_win_setup.iss
new file mode 100644
index 0000000..3ad777b
--- /dev/null
+++ b/MicrosoftWindows_compatibility/mcu8051ide_win_setup.iss
@@ -0,0 +1,66 @@
+; Script generated by the Inno Setup Script Wizard.
+; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
+
+[Setup]
+; NOTE: The value of AppId uniquely identifies this application.
+; Do not use the same AppId value in installers for other applications.
+; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
+AppId={{E0D2EFF2-AF92-403C-88F6-6188F369D6BB}
+AppName=MCU 8051 IDE
+AppVerName=MCU 8051 IDE 1.3.6
+AppPublisher=Martin Omera
+AppPublisherURL=http://mcu8051ide.sf.net/
+AppSupportURL=http://mcu8051ide.sf.net/
+AppUpdatesURL=http://mcu8051ide.sf.net/
+DefaultDirName={pf}\MCU 8051 IDE
+DefaultGroupName=MCU 8051 IDE
+AllowNoIcons=yes
+LicenseFile=W:\mcu8051ide\LICENSE
+OutputDir=W:\
+OutputBaseFilename=mcu8051ide-1.3.6-setup
+Compression=lzma
+SolidCompression=yes
+SetupIconFile="W:\mcu8051ide\MicrosoftWindows_compatibility\mcu8051ide.ico"
+WizardImageFile=compiler:WIZMODERNIMAGE-IS.BMP
+
+[Languages]
+Name: "english"; MessagesFile: "compiler:Default.isl"
+
+[Tasks]
+Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
+Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
+
+[Files]
+Source: "W:\mcu8051ide\lib\*.tcl"; DestDir: "{app}\lib"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\bottompanel\*.tcl"; DestDir: "{app}\lib\bottompanel"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\compiler\*.tcl"; DestDir: "{app}\lib\compiler"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\configdialogs\*.tcl"; DestDir: "{app}\lib\configdialogs"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\dialogs\*.tcl"; DestDir: "{app}\lib\dialogs"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\editor\*.tcl"; DestDir: "{app}\lib\editor"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\leftpanel\*.tcl"; DestDir: "{app}\lib\leftpanel"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\lib\*.tcl"; DestDir: "{app}\lib\lib"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\pale\*.tcl"; DestDir: "{app}\lib\pale"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\rightpanel\*.tcl"; DestDir: "{app}\lib\rightpanel"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\simulator\*.tcl"; DestDir: "{app}\lib\simulator"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\simulator\engine\*.tcl"; DestDir: "{app}\lib\simulator\engine"; Flags: ignoreversion
+Source: "W:\mcu8051ide\lib\utilities\*.tcl"; DestDir: "{app}\lib\utilities"; Flags: ignoreversion
+Source: "W:\mcu8051ide\icons\16x16\*.png"; DestDir: "{app}\icons\16x16"; Flags: ignoreversion
+Source: "W:\mcu8051ide\icons\22x22\*.png"; DestDir: "{app}\icons\22x22"; Flags: ignoreversion
+Source: "W:\mcu8051ide\icons\32x32\*.png"; DestDir: "{app}\icons\32x32"; Flags: ignoreversion
+Source: "W:\mcu8051ide\icons\mcu\*.png"; DestDir: "{app}\icons\mcu"; Flags: ignoreversion
+Source: "W:\mcu8051ide\icons\other\*.png"; DestDir: "{app}\icons\other"; Flags: ignoreversion
+Source: "W:\mcu8051ide\data\*"; DestDir: "{app}\data"; Flags: ignoreversion
+Source: "W:\mcu8051ide\demo\*"; DestDir: "{app}\demo"; Flags: ignoreversion
+Source: "W:\mcu8051ide\translations\*"; DestDir: "{app}\translations"; Flags: ignoreversion
+Source: "W:\mcu8051ide\MicrosoftWindows_compatibility\mcu8051ide.ico"; DestDir: "{app}"; Flags: ignoreversion
+Source: "W:\mcu8051ide\MicrosoftWindows_compatibility\*.bat"; DestDir: "{app}\lib"; Flags: ignoreversion
+; NOTE: Don't use "Flags: ignoreversion" on any shared system files
+
+[Icons]
+Name: "{group}\MCU 8051 IDE"; Filename: "{app}\lib\main.tcl"; IconFilename: "{app}\mcu8051ide.ico"
+Name: "{commondesktop}\MCU 8051 IDE"; Filename: "{app}\lib\main.tcl"; Tasks: desktopicon; IconFilename: "{app}\mcu8051ide.ico"
+Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\MCU 8051 IDE"; Filename: "{app}\lib\main.tcl"; Tasks: quicklaunchicon; IconFilename: "{app}\mcu8051ide.ico"
+
+[Run]
+Filename: "{app}\lib\main.tcl"; Description: "{cm:LaunchProgram,MCU 8051 IDE}"; Flags: shellexec postinstall skipifsilent
+
diff --git a/MicrosoftWindows_compatibility/sdcc.bat b/MicrosoftWindows_compatibility/sdcc.bat
new file mode 100644
index 0000000..ffe50ee
--- /dev/null
+++ b/MicrosoftWindows_compatibility/sdcc.bat
@@ -0,0 +1,2 @@
+@cd %1
+@sdcc --iram-size %2 --xram-size %3 --code-size %4 --nooverlay --noinduction --verbose --debug -V --std-sdcc89 --model-small --pack-iram %5 \ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..c002f60
--- /dev/null
+++ b/README
@@ -0,0 +1,87 @@
+MCU 8051 IDE v1.3.0
+
+DESCRIPTION:
+-------------
+
+Integrated development enviromet for MCS-51 based processors.
+Written in Tcl/Tk, for POSIX Systems (GNU/Linux etc.)
+
+
+
+INSTALLATION:
+--------------
+
+At first make sure than you have all dependencies installed and install the missing ones.
+(http://mcu8051ide.sourceforge.net/dependencies)
+
+1) INSTALL DEPENDENCIES
+
+ -----------------------------------------------------------------------------------------------------
+ Package min. Version Where it's avaible
+ -----------------------------------------------------------------------------------------------------
+ REQUIRED PACKAGES: (Without these packages this program WILL NOT run)
+ tcl 8.5 http://www.tcl.tk/software/tcltk/downloadnow84.html
+ tk 8.5 http://www.tcl.tk/software/tcltk/downloadnow84.html
+ bwidget 1.8 http://sourceforge.net/projects/tcllib
+ itcl 3.4 http://sourceforge.net/projects/incrtcl
+ tdom 0.8 http://www.tdom.org
+ tkimg 1.3 http://sourceforge.net/projects/tkimg
+ tcllib 1.6 http://sourceforge.net/projects/tcllib
+ Tclx 8.4 http://tclx.sourceforge.net
+ -----------------------------------------------------------------------------------------------------
+ OPTIONAL PACKAGES: (Without these packages some features will not be avaliable)
+ cmake 2.4.3 http://www.cmake.org/HTML/Download.html
+ (If you want to install it using "./configure && make && make install")
+ rxvt-unicode 8.3 http://software.schmorp.de/
+ asem-51 1.3 http://plit.de/asem-51/download.htm
+ asl (I don't know. My e-mail is <martin.osmera@mail.com>)
+ vim http://www.vim.org/download.php
+ emacs http://www.gnu.org/software/emacs/
+ nano http://www.nano-editor.org/
+ le http://www.gnu.org/directory/text/editors/le-editor.html
+ -----------------------------------------------------------------------------------------------------
+
+ NOTE:
+ If you had any problems with installation of any of these packages
+ please mention it at http://mcu8051ide.sourceforge.net/dependencies .
+
+2) INSTALL MCU 8051 IDE
+ You can install this program in two ways:
+
+ A) The recomended one (CMake)
+ ./configure
+ make
+ # here you must be root
+ make install
+
+ B) (Bash script)
+ ./install.sh
+
+ Tip:
+ You can check if all needed libraries are properly installed by this command:
+ mcu8051ide --check-libraries
+ If you are upgrading from some previous version and the program won't run, try this:
+ mcu8051ide --reset-user-settings --ignore-last-session
+
+3) If you failed installing this software, plese let me know at the project web page.
+
+
+PROBLEMS & SUGESTIONS:
+-----------------------
+
+ Project web page:
+ http://mcu8051ide.sf.net
+
+ E-mail to the author:
+ martin.osmera@gmail.cz (Only English or Czech please)
+
+
+BUGS:
+------
+ Currently I don't know about any bug.
+ If you find some bug, plese let me know <martin.osmera@gmail.cz>.
+
+NOTE:
+-----
+ You can help me make installation easier by making installation package for your OS.
+ Thank your for trying/using MCU 8051 IDE.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..7fb5b90
--- /dev/null
+++ b/TODO
@@ -0,0 +1,5 @@
+TODO list for MCU 8051 IDE
+
+ (I don't know ...)
+
+Comments and suggestions: http://mcu8051ide.sf.net or martin.osmera@gmail.com
diff --git a/clear_all.sh b/clear_all.sh
new file mode 100755
index 0000000..26b85a7
--- /dev/null
+++ b/clear_all.sh
@@ -0,0 +1,11 @@
+#! /bin/bash
+
+for i in *~ */*~ */*/*~ */*/*/*~; do
+ rm -fv $i
+done
+
+rm -fv CMakeCache.txt
+rm -fv cmake_install.cmake
+rm -fv Makefile
+rm -fv mcu8051ide
+rm -rfv CMakeFiles
diff --git a/configure b/configure
new file mode 100755
index 0000000..11fd4f8
--- /dev/null
+++ b/configure
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ ! -z "$@" ]; then
+ printf "\nThis is not real configure script.\n"
+ printf "This script only calls 'cmake .'\n"
+ printf "All options are ignored.\n"
+fi
+cmake .
diff --git a/data/licence.txt b/data/licence.txt
new file mode 100644
index 0000000..6904999
--- /dev/null
+++ b/data/licence.txt
@@ -0,0 +1,341 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundations software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each authors protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyones free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Programs
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the programs name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c for details.
+
+The hypothetical commands `show w and `show c should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w and `show c; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/data/m5ihib.dtd b/data/m5ihib.dtd
new file mode 100644
index 0000000..7140578
--- /dev/null
+++ b/data/m5ihib.dtd
@@ -0,0 +1,103 @@
+<!-- ROOT ELEMENT -->
+<!ELEMENT m5ihib (currentstate, subprograms, stepback)>
+<!-- Root element Parameters:
+ version - File version
+ datetime - Date and time of creation
+ source_file - Souce code compiled and loaded in simulator before hibernation
+ processor - Processor type
+ xdata - Size of External data memory
+ eeprom - Size of data EEPROM
+ md5 - MD5 hash of the source code file
+-->
+<!ATTLIST m5ihib
+ version CDATA #REQUIRED
+ datetime CDATA #REQUIRED
+ source_file CDATA #REQUIRED
+ processor CDATA #REQUIRED
+ xdata CDATA #REQUIRED
+ eeprom CDATA #REQUIRED
+ md5 CDATA #REQUIRED
+>
+
+
+<!-- Current state of MCU -->
+<!ELEMENT currentstate (iram, eram, xram, eeprom, sfr, special)>
+
+<!-- Internal data memory in decimal -->
+<!ELEMENT iram (#PCDATA)>
+
+<!-- Expanded data memory in decimal -->
+<!ELEMENT eram (#PCDATA)>
+
+<!-- External data memory in decimal -->
+<!ELEMENT xram (#PCDATA)>
+
+<!-- Data EEPROM in decimal -->
+<!ELEMENT eeprom (#PCDATA)>
+
+<!-- Special function registers -->
+<!ELEMENT sfr (addresses, values)>
+
+<!-- SFR decimal addresses in the same order as in tag values -->
+<!ELEMENT addresses (#PCDATA)>
+
+<!-- SFR decimal values in the same order as in tag values -->
+<!ELEMENT values (#PCDATA)>
+
+<!-- Special engine variables -->
+<!ELEMENT special (#PCDATA)>
+
+
+<!-- Content of list of active interrupts -->
+<!ELEMENT subprograms (sub)*>
+<!-- Parameters of tag "subprograms":
+ count - Number of recorded subprograms
+-->
+<!ATTLIST subprograms
+ count CDATA #REQUIRED
+>
+
+<!-- Active interrupt -->
+<!ELEMENT sub EMPTY>
+<!-- Parameters of tag "sub":
+ source - Source address
+ target - Target address
+ type - Type
+-->
+<!ATTLIST sub
+ source CDATA #REQUIRED
+ target CDATA #REQUIRED
+ type CDATA #REQUIRED
+>
+
+
+<!-- Stack for stepback function (backward stepping) -->
+<!ELEMENT stepback (step)*>
+<!-- Parameters of tag "stepback":
+ stacklength - Number of recorded program steps
+-->
+<!ATTLIST stepback
+ stacklength CDATA #REQUIRED
+>
+
+<!-- One program step -->
+<!ELEMENT step (spec, normal)>
+
+<!-- Special engine variables -->
+<!ELEMENT spec (#PCDATA)>
+
+<!-- Ordinary registers -->
+<!ELEMENT normal (reg)*>
+
+<!-- One register -->
+<!ELEMENT reg EMPTY>
+<!-- Parameters of tag "reg":
+ type - Memory type (E == ERAM; I == IDATA; X == XDATA; S == SFR)
+ addr - Register address
+ val - Previous register value
+-->
+<!ATTLIST reg
+ type CDATA #REQUIRED
+ addr CDATA #REQUIRED
+ val CDATA #REQUIRED
+>
diff --git a/data/mcus.xml b/data/mcus.xml
new file mode 100644
index 0000000..3c75a4a
--- /dev/null
+++ b/data/mcus.xml
@@ -0,0 +1,1968 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE mcus [
+ <!-- Root element -->
+ <!ELEMENT mcus (mcu)*>
+ <!--
+ lastupdate - Date of the last update of this file (format: %D, e.g. 11/18/07)
+ -->
+ <!ATTLIST mcus
+ lastupdate CDATA #IMPLIED
+ >
+
+ <!-- MCU definition tag -->
+ <!ELEMENT mcu (timers, more, bits, writeonly, sfr)>
+
+ <!-- Detailed specification of MCU parameters (all of them must not be an empty string)
+ vendor - Vendor name
+ name - Processor type
+ xdata - External data memory connectable
+ xcode - External program memoryconnectable
+ code - Capacity of internal program memory in kilo bytes (not bytes !)
+ frequency - Operating oscilator frequency (e.g "0 to 24 MHz")
+ ram - Capacity of internal data memory in bytes
+ portbits - Number of IO lines
+ uart - UART avaliable
+ interrupts - Number of interrupts
+ voltage - Oprating voltage (e.g "2.7 to 5.5 V")
+ timer2 - Timer 2 avaliable
+ watchdog - Watchdog timer avaliable
+ eram - Size of ERAM (0 means no eram avaliable) (> 0 requires intelpe="no")
+ dualdtpr - Dual Data Pointer (includes register AUXR1 if wdtcon="no")
+ auxr - Register AUXR
+ t2mod - Register T2MOD
+ portN - Implemented bits for port N (N < 6) (empty list means port is not implemented)
+ 0 - Bit not implemented
+ 1 - Bit implemented
+ e.g. port0="11110011" means:
+ P0.0 - implemented
+ P0.1 - implemented
+ P0.2 - implemented
+ P0.3 - implemented
+ P0.4 - not implemented
+ P0.5 - not implemented
+ P0.6 - implemented
+ P0.7 - implemented
+ pof - Power Off Flag implemented
+ gf0 - PCON.3 (General purpose flag) implemented
+ gf1 - PCON.4 (General purpose flag) implemented
+ pd - Power Down flag implemented
+ idl - IDLe mode flag implemented
+ smod0 - PCON.6 (SMOD0) implemented (requires uart="yes")
+ iph - IPH register implemented
+ acomparator - Analog comparator
+ euart - Extended UART (registers SADDR and SADEN)
+ clkreg - Register CLKREG implemented
+ pwdex - Bit PWDEX (CLKREG.1) implemented (requires clkreg="yes")
+ spi - SPI controller implemented
+ wdtcon - Register WDTCON implemented (removes AUXR.WDIDLE and AUXR.DISRTO) (requires watchdog="yes")
+ eeprom - Size of internal data EEPROM in bytes
+ intelpe - Register Intel_Pwd_Exit (AUXR.1) implemented (requires eram="0")
+ pwm - Pulse with modulation controller implemented (PCON.PWMEN)
+ x2reset - Is CLKREG.X2 untouched by reset (requires clkreg="yes" or ckcon="yes")
+ ckcon - SFR 0x8F is CKCON instead of CLKREG (requires clkreg="no")
+ auxr1gf3 - Bit GF3 in AUXR1 present
+ ao - Use AUXR.AO instead of AUXR.DISALE (requires auxr="yes")
+ wdtprg - WDTPRG (T4 T3 T2 T1 T0 S2 S1 S0) 0xA7 (requires watchdog="yes")
+ hddptr - Hidden Dual Data PoiTeR (That means than there is no DP0L, DP0H and DP1L, DP1H) (requires dualdtpr="yes")
+ auxrwdidle - Bit WDIDLE in register AUXR (requires auxr="yes")
+ auxrdisrto - Bit DISRTO in register AUXR (requires auxr="yes")
+ -->
+ <!ATTLIST mcu
+ vendor CDATA #REQUIRED
+ name NMTOKEN #REQUIRED
+ xdata (yes|no) #REQUIRED
+ xcode (yes|no) #REQUIRED
+ code CDATA #REQUIRED
+ frequency CDATA #REQUIRED
+ ram CDATA #REQUIRED
+ portbits CDATA #REQUIRED
+ uart (yes|no) #REQUIRED
+ interrupts CDATA #REQUIRED
+ voltage CDATA #REQUIRED
+ timer2 (yes|no) #REQUIRED
+ watchdog (yes|no) #REQUIRED
+ eram CDATA #REQUIRED
+ dualdtpr (yes|no) #REQUIRED
+ auxr (yes|no) #REQUIRED
+ t2mod (yes|no) #REQUIRED
+ port0 CDATA #REQUIRED
+ port1 CDATA #REQUIRED
+ port2 CDATA #REQUIRED
+ port3 CDATA #REQUIRED
+ port4 CDATA #REQUIRED
+ pof (yes|no) #REQUIRED
+ gf0 (yes|no) #REQUIRED
+ gf1 (yes|no) #REQUIRED
+ pd (yes|no) #REQUIRED
+ idl (yes|no) #REQUIRED
+ smod0 (yes|no) #REQUIRED
+ iph (yes|no) #REQUIRED
+ acomparator (yes|no) #REQUIRED
+ euart (yes|no) #REQUIRED
+ clkreg (yes|no) #REQUIRED
+ pwdex (yes|no) #REQUIRED
+ spi (yes|no) #REQUIRED
+ wdtcon (yes|no) #REQUIRED
+ eeprom CDATA #REQUIRED
+ intelpe (yes|no) #REQUIRED
+ pwm (yes|no) #REQUIRED
+ x2reset (yes|no) #REQUIRED
+ ckcon (yes|no) #REQUIRED
+ auxr1gf3 (yes|no) #REQUIRED
+ ao (yes|no) #REQUIRED
+ wdtprg (yes|no) #REQUIRED
+ hddptr (yes|no) #REQUIRED
+ auxrwdidle (yes|no) #REQUIRED
+ auxrdisrto (yes|no) #REQUIRED
+ >
+
+ <!-- Details about timers/counters (for slection dialog only) -->
+ <!ELEMENT timers (#PCDATA)>
+
+ <!-- More informations about uC (for slection dialog only) -->
+ <!ELEMENT more (#PCDATA)>
+
+ <!-- Map of implemented SFR bits (register not mentionded here have mask "FF")
+ AAMM AAMM ...
+ | |
+ | +- Mask (2 hex digits, 1 == implemented; 0 == not implemented (WRITE ONLY) )
+ +- Address (2 hex digits)
+ -->
+ <!ELEMENT bits (#PCDATA)>
+
+ <!-- Hexadecimal addresses of write only registers (e.g. AF 85 4B) -->
+ <!ELEMENT writeonly (#PCDATA)>
+
+ <!-- List of SFR and SFB which are avaliable on the choosen MCU
+ Implicit SFR and SFB:
+ B ACC A TMOD TH0 TH1 SP DPL DPH PCON
+ TL0 TL1 AB
+
+ PSW C CY AC F0 RS1 RS0 OV P
+ IE EA ET1 EX1 ET0 EX0
+ IP PT1 PX1 PT0 PX0
+ TCON TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
+ -->
+ <!ELEMENT sfr (#PCDATA)>
+]>
+<mcus lastupdate="02/10/09">
+ <mcu
+ vendor="Intel" name="8051"
+ xdata="yes" xcode="yes"
+ code="4" frequency="0 to 12 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="no"
+ gf1="no" pd="no"
+ idl="no" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ </more><bits>
+ 878F B81F A89F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="8031"
+ xdata="yes" xcode="yes"
+ code="0" frequency="0 to 12 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="no"
+ gf1="no" pd="no"
+ idl="no" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ </more><bits>
+ 878F B81F A89F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="8751"
+ xdata="yes" xcode="yes"
+ code="4" frequency="0 to 12 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="no"
+ gf1="no" pd="no"
+ idl="no" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ </more><bits>
+ 878F B81F A89F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="80C51"
+ xdata="yes" xcode="yes"
+ code="4" frequency="0 to 12 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ </more><bits>
+ 878F B81F A89F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="80C31"
+ xdata="yes" xcode="yes"
+ code="0" frequency="0 to 12 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ </more><bits>
+ 878F B81F A89F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="87C51"
+ xdata="yes" xcode="yes"
+ code="4" frequency="0 to 12 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ </more><bits>
+ 878F B81F A89F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="8052"
+ xdata="yes" xcode="yes"
+ code="8" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="no"
+ gf1="no" pd="no"
+ idl="no" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ RCAP2L RCAP2H TL2 TH2
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="8032"
+ xdata="yes" xcode="yes"
+ code="0" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="no"
+ gf1="no" pd="no"
+ idl="no" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ RCAP2L RCAP2H TL2 TH2
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="8752"
+ xdata="yes" xcode="yes"
+ code="8" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="no"
+ gf1="no" pd="no"
+ idl="no" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ RCAP2L RCAP2H TL2 TH2
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="80C52"
+ xdata="yes" xcode="yes"
+ code="8" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Timer 2
+ — CaptureTimer/Counter
+ — Up/Down Timer/Counter
+ — Baud Rate Generator
+ Full-Duplex Programma Serial Interface with
+ — Framing Error Detection
+ — Automatic Address Recognition
+ 6 InterruptSources
+ Enhanced Power Down Mode
+ Power Off Flag
+ ONCE Mode
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ SADEN SADDR RCAP2L RCAP2H TL2 TH2 T2MOD IPH FE
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="87C52"
+ xdata="yes" xcode="yes"
+ code="8" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Timer 2
+ — CaptureTimer/Counter
+ — Up/Down Timer/Counter
+ — Baud Rate Generator
+ Full-Duplex Programma Serial Interface with
+ — Framing Error Detection
+ — Automatic Address Recognition
+ 6 InterruptSources
+ Enhanced Power Down Mode
+ Power Off Flag
+ ONCE Mode
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ SADEN SADDR RCAP2L RCAP2H TL2 TH2 T2MOD IPH FE
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="80C32"
+ xdata="yes" xcode="yes"
+ code="0" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Timer 2
+ — CaptureTimer/Counter
+ — Up/Down Timer/Counter
+ — Baud Rate Generator
+ Full-Duplex Programma Serial Interface with
+ — Framing Error Detection
+ — Automatic Address Recognition
+ 6 InterruptSources
+ Enhanced Power Down Mode
+ Power Off Flag
+ ONCE Mode
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ SADEN SADDR RCAP2L RCAP2H TL2 TH2 T2MOD IPH FE
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="80C54"
+ xdata="yes" xcode="yes"
+ code="16" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Timer 2
+ — CaptureTimer/Counter
+ — Up/Down Timer/Counter
+ — Baud Rate Generator
+ Full-Duplex Programma Serial Interface with
+ — Framing Error Detection
+ — Automatic Address Recognition
+ 6 InterruptSources
+ Enhanced Power Down Mode
+ Power Off Flag
+ ONCE Mode
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ SADEN SADDR RCAP2L RCAP2H TL2 TH2 T2MOD IPH FE
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="87C54"
+ xdata="yes" xcode="yes"
+ code="16" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Timer 2
+ — CaptureTimer/Counter
+ — Up/Down Timer/Counter
+ — Baud Rate Generator
+ Full-Duplex Programma Serial Interface with
+ — Framing Error Detection
+ — Automatic Address Recognition
+ 6 InterruptSources
+ Enhanced Power Down Mode
+ Power Off Flag
+ ONCE Mode
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ SADEN SADDR RCAP2L RCAP2H TL2 TH2 T2MOD IPH FE
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="80C58"
+ xdata="yes" xcode="yes"
+ code="32" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Timer 2
+ — CaptureTimer/Counter
+ — Up/Down Timer/Counter
+ — Baud Rate Generator
+ Full-Duplex Programma Serial Interface with
+ — Framing Error Detection
+ — Automatic Address Recognition
+ 6 InterruptSources
+ Enhanced Power Down Mode
+ Power Off Flag
+ ONCE Mode
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ SADEN SADDR RCAP2L RCAP2H TL2 TH2 T2MOD IPH FE
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Intel" name="87C58"
+ xdata="yes" xcode="yes"
+ code="32" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage=" " timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Timer 2
+ — CaptureTimer/Counter
+ — Up/Down Timer/Counter
+ — Baud Rate Generator
+ Full-Duplex Programma Serial Interface with
+ — Framing Error Detection
+ — Automatic Address Recognition
+ 6 InterruptSources
+ Enhanced Power Down Mode
+ Power Off Flag
+ ONCE Mode
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ SADEN SADDR RCAP2L RCAP2H TL2 TH2 T2MOD IPH FE
+
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89C2051"
+ xdata="no" xcode="no"
+ code="2" frequency="0 to 24 MHz"
+ ram="128" portbits="15"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 6 V" timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0=""
+ port1="11111111" port2=""
+ port3="11111101" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Direct LED Drive Outputs
+ On-chip Analog Comparator
+ Low-power Idle and Power-down Modes
+ Two-level Program Memory Lock
+ </more><bits>
+ 878F B81F A89F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P1 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89C4051"
+ xdata="no" xcode="no"
+ code="4" frequency="0 to 24 MHz"
+ ram="128" portbits="15"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 6 V" timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0=""
+ port1="11111111" port2=""
+ port3="11111101" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Direct LED Drive Outputs
+ On-chip Analog Comparator
+ Low-power Idle and Power-down Modes
+ Two-level Program Memory Lock
+ </more><bits>
+ 878F B81F A89F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P1 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89C51"
+ xdata="yes" xcode="yes"
+ code="4" frequency="0 to 24 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="max. 6.6 V" timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ </more><bits>
+ 878F B81F A89F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89C51RC"
+ xdata="yes" xcode="yes"
+ code="32" frequency="0 to 33 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage="4 to 5.5 V" timer2="yes"
+ watchdog="yes" eram="256"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="yes" auxrdisrto="yes">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ Interrupt Recovery from Power-down Mode
+ Hardware Watchdog Timer
+ Dual Data Pointer
+ Power-off Flag
+ </more><bits>
+ C903 B83F A8BF A201 8E1B 878F
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD AUXR AUXR1 WDTRST RCAP2L RCAP2H TL2 TH2
+ DP0H DP0L DP1H DP1L
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89C52"
+ xdata="yes" xcode="yes"
+ code="8" frequency="0 to 24 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage="max. 6.6 V" timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD RCAP2L RCAP2H TL2 TH2
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89C55WD"
+ xdata="yes" xcode="yes"
+ code="20" frequency="0 to 33 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage="4 to 5.5 V" timer2="yes"
+ watchdog="yes" eram="256"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="yes" auxrdisrto="yes">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ Interrupt Recovery from Power-down Mode
+ Hardware Watchdog Timer
+ Dual Data Pointer
+ Power-off Flag
+ </more><bits>
+ C903 B83F A8BF A201
+ 8E1B 878F
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD AUXR AUXR1 WDTRST RCAP2L RCAP2H TL2 TH2
+ DP0H DP0L DP1H DP1L
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89LV51"
+ xdata="yes" xcode="yes"
+ code="4" frequency="0 to 12 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 6 V" timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Three-Level Program Memory Lock
+ Low Power Idle and Power Down Modes
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89LV52"
+ xdata="yes" xcode="yes"
+ code="8" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage="2.7 to 6" timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-Level Program Memory Lock
+ Low Power Idle and Power Down Modes
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2 T2MOD
+ RCAP2L RCAP2H TL2 TH2
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89LV55"
+ xdata="yes" xcode="yes"
+ code="20" frequency="0 to 12 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage="2.7 to 6" timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ </more><bits>
+ C903 B83F A8BF 878F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD RCAP2L RCAP2H TL2 TH2
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89S52"
+ xdata="yes" xcode="yes"
+ code="8" frequency="0 to 33 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage="4 to 5.5 V" timer2="yes"
+ watchdog="yes" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="yes" auxrdisrto="yes">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ Interrupt Recovery from Power-down Mode
+ Watchdog Timer
+ Dual Data Pointer
+ Power-off Flag
+ Fast Programming Time
+ Flexible ISP Programming (Byte and Page Mode)
+ </more><bits>
+ C903 B83F A8BF A201 8E19 878F
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD AUXR AUXR1 WDTRST RCAP2L RCAP2H TL2 TH2
+ DP0H DP0L DP1H DP1L
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89LS51"
+ xdata="yes" xcode="yes"
+ code="4" frequency="0 to 16 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 4" timer2="no"
+ watchdog="yes" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="yes" auxrdisrto="yes">
+ <timers>Two 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ Interrupt Recovery from Power-down Mode
+ Watchdog Timer
+ Dual Data Pointer
+ Power-off Flag
+ Flexible ISP Programming (Byte and Page Mode)
+ </more><bits>
+ B83F A8BF A201 8E19 878F
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS
+ DP0H DP0L DP1H DP1L AUXR AUXR1 WDTRST
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89LS52"
+ xdata="yes" xcode="yes"
+ code="8" frequency="0 to 16 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="8"
+ voltage="2.7 to 4" timer2="yes"
+ watchdog="yes" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="no" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="no"
+ iph="no" acomparator="no"
+ euart="no" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="yes" auxrdisrto="yes">
+ <timers>Three 16-bit</timers>
+ <more>
+ Three-level Program Memory Lock
+ Low-power Idle and Power-down Modes
+ Interrupt Recovery from Power-down Mode
+ Watchdog Timer
+ Dual Data Pointer
+ Power-off Flag
+ Flexible ISP Programming (Byte and Page Modes)
+ </more><bits>
+ C903 B83F A8BF A201 8E19 878F
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD AUXR AUXR1 WDTRST RCAP2L RCAP2H TL2 TH2
+ DP0H DP0L DP1H DP1L
+ SCON SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89S2051"
+ xdata="no" xcode="no"
+ code="2" frequency="0 to 24 MHz"
+ ram="256" portbits="15"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0=""
+ port1="11111111" port2=""
+ port3="11111101" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="yes"
+ euart="yes" clkreg="yes"
+ pwdex="yes" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="yes"
+ x2reset="yes" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Two-level Program Memory Lock
+ Direct LED Drive Outputs
+ On-chip Analog Comparator with Selectable Interrupt
+ 8-bit PWM (Pulse-width Modulation)
+ Low Power Idle and Power-down Modes
+ Brownout Reset
+ Enhanced UART Serial Port with Framing Error Detection and Automatic
+ Address Recognition
+ Internal Power-on Reset
+ Interrupt Recovery from Power-down Mode
+ Programmable and Fuseable x2 Clock Option
+ Four-level Enhanced Interrupt Controller
+ Power-off Flag
+ Flexible Programming (Byte and Page Modes)
+ User Serviceable Signature Page (32 Bytes)
+ </more><bits>
+ 8F03 971F A8DF B75F B85F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P1 P3 IPH ACSR CLKREG SADEN SADDR SBUF
+ EC PC ES PS FE
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89S4051"
+ xdata="no" xcode="no"
+ code="4" frequency="0 to 24 MHz"
+ ram="256" portbits="15"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="no" auxr="no"
+ t2mod="no" port0=""
+ port1="11111111" port2=""
+ port3="11111101" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="yes"
+ euart="yes" clkreg="yes"
+ pwdex="yes" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="yes"
+ x2reset="yes" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ Two-level Program Memory Lock
+ Direct LED Drive Outputs
+ On-chip Analog Comparator with Selectable Interrupt
+ 8-bit PWM (Pulse-width Modulation)
+ Low Power Idle and Power-down Modes
+ Brownout Reset
+ Enhanced UART Serial Port with Framing Error Detection and Automatic
+ Address Recognition
+ Internal Power-on Reset
+ Interrupt Recovery from Power-down Mode
+ Programmable and Fuseable x2 Clock Option
+ Four-level Enhanced Interrupt Controller
+ Power-off Flag
+ Flexible Programming (Byte and Page Modes)
+ User Serviceable Signature Page (32 Bytes)
+ </more><bits>
+ 8F03 971F A8DF B75F B85F
+ </bits><writeonly>
+ </writeonly><sfr>
+ P1 P3 IPH ACSR CLKREG SADEN SADDR SBUF
+ EC PC ES PS FE
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="AT89S8253"
+ xdata="yes" xcode="yes"
+ code="12" frequency="0 to 24 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="9"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="yes" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="yes"
+ pwdex="no" spi="yes"
+ wdtcon="yes" eeprom="2048"
+ intelpe="yes" pwm="no"
+ x2reset="no" ckcon="no"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="no"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ 2K Bytes EEPROM Data Memory
+ 64-byte User Signature Array
+ Three-level Program Memory Lock
+ Enhanced UART Serial Port with Framing Error Detection and Automatic Address Recognition
+ Enhanced SPI (Double Write/Read Buffered) Serial Interface
+ Low-power Idle and Power-down Modes
+ Interrupt Recovery from Power-down Mode
+ Programmable Watchdog Timer
+ Dual Data Pointer
+ Power-off Flag
+ Flexible ISP Programming (Byte and Page Modes)
+ Four-level Enhanced Interrupt Controller
+ Programmable and Fuseable x2 Clock Option
+ Internal Power-on Reset
+ 42-pin PDIP Package Option for Reduced EMC Emission
+ </more><bits>
+ 87DF 8E01 8F01 963F AAE3 B73F C903
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD IPH SADEN SADDR SPSD AUXR WDTRST EECON SPCR
+ SPSR WDTCON CLKREG RCAP2L RCAP2H TL2 TH2 SPDR FE
+ DP0H DP0L DP1H DP1L
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="T87C5101"
+ xdata="no" xcode="no"
+ code="16" frequency="0 to 66 MHz"
+ ram="256" portbits="16"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="no" eram="256"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0=""
+ port1="11111111" port2=""
+ port3="11111100" port4="00000011"
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="no" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Program memory: EEPROM
+ High-speed Architecture
+ Dual Data Pointer
+ On-chip eXpanded RAM (256 bytes)
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Asynchronous Port Reset
+ 4-Level Priority Interrupt System
+ Full-duplex Enhanced UART
+ Low EMI (no ALE)
+ Idle Mode
+ Power-down Mode
+ </more><bits>
+ C903 C03F B83F B73F A8BF A209 8E03 8F01 87DF
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON FE
+ RCAP2L RCAP2H TL2 TH2 DP0H DP0L DP1H DP1L
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="T83C5101"
+ xdata="no" xcode="no"
+ code="8" frequency="0 to 66 MHz"
+ ram="256" portbits="16"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="no" eram="256"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0=""
+ port1="11111111" port2=""
+ port3="11111100" port4="00000011"
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="no" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Program memory: ROM
+ High-speed Architecture
+ Dual Data Pointer
+ On-chip eXpanded RAM (256 bytes)
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Asynchronous Port Reset
+ 4-Level Priority Interrupt System
+ Full-duplex Enhanced UART
+ Low EMI (no ALE)
+ Idle Mode
+ Power-down Mode
+ </more><bits>
+ C903 C03F B83F B73F A8BF A209 8E03 8F01 87DF
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON FE
+ RCAP2L RCAP2H TL2 TH2
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="T83C5102"
+ xdata="no" xcode="no"
+ code="8" frequency="0 to 66 MHz"
+ ram="256" portbits="16"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="no" eram="256"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0=""
+ port1="11111111" port2=""
+ port3="11111100" port4="00000011"
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="no" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Program memory: ROM
+ High-speed Architecture
+ Dual Data Pointer
+ On-chip eXpanded RAM (256 bytes)
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Asynchronous Port Reset
+ 4-Level Priority Interrupt System
+ Full-duplex Enhanced UART
+ Low EMI (no ALE)
+ Idle Mode
+ Power-down Mode
+ </more><bits>
+ C903 C03F B83F B73F A8BF A209 8E03 8F01 87DF
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON FE
+ RCAP2L RCAP2H TL2 TH2
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="80C32X2"
+ xdata="yes" xcode="yes"
+ code="0" frequency="20 - 60 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="no" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ ROMLess
+ High-speed Architecture
+ X2 Speed Improvement Capability
+ Dual Data Pointer
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Asynchronous Port Reset
+ 4 Level Priority Interrupt System
+ Full Duplex Enhanced UART
+ Low EMI (Inhibit ALE)
+ Idle Mode
+ Power-down Mode
+ Power-off Flag
+ Once Mode (On-chip Emulation)
+ </more><bits>
+ C903 B83F B73F A8BF A209 8E01 8F01 87DF
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON FE
+ RCAP2L RCAP2H TL2 TH2
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="80C52X2"
+ xdata="yes" xcode="yes"
+ code="8" frequency="20 - 60 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="no" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Program memory: ROM
+ High-speed Architecture
+ X2 Speed Improvement Capability
+ Dual Data Pointer
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Asynchronous Port Reset
+ 4 Level Priority Interrupt System
+ Full Duplex Enhanced UART
+ Low EMI (Inhibit ALE)
+ Idle Mode
+ Power-down Mode
+ Power-off Flag
+ Once Mode (On-chip Emulation)
+ </more><bits>
+ C903 B83F B73F A8BF A209 8E01 8F01 87DF
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON FE
+ RCAP2L RCAP2H TL2 TH2
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="87C52X2"
+ xdata="yes" xcode="yes"
+ code="8" frequency="20 - 60 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="no" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="no" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Program memory: OTP
+ High-speed Architecture
+ X2 Speed Improvement Capability
+ Dual Data Pointer
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Asynchronous Port Reset
+ 4 Level Priority Interrupt System
+ Full Duplex Enhanced UART
+ Low EMI (Inhibit ALE)
+ Idle Mode
+ Power-down Mode
+ Power-off Flag
+ Once Mode (On-chip Emulation)
+ </more><bits>
+ C903 B83F B73F A8BF A209 8E01 8F01 87DF
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON FE
+ RCAP2L RCAP2H TL2 TH2
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="80C31X2"
+ xdata="yes" xcode="yes"
+ code="0" frequency="20 - 40 MHz"
+ ram="128" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="no"
+ watchdog="no" eram="0"
+ dualdtpr="yes" auxr="no"
+ t2mod="no" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="no" ao="no"
+ wdtprg="no" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Two 16-bit</timers>
+ <more>
+ ROMLess
+ High-Speed Architecture
+ X2 Speed Improvement capability
+ Dual Data Pointer
+ Asynchronous port reset
+ 4 priority level interrupt system
+ Full duplex Enhanced UART
+ Framing error detection
+ Automatic address recognition
+ Idle mode
+ Power-down mode
+ Power-off Flag
+ Once mode (On-chip Emulation)
+ </more><bits>
+ B81F B71F A89F A201 8E01 8F01 87DF
+ </bits><writeonly>
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS FE
+ SADEN SADDR AUXR1 IPH CKCON
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="80C54X2"
+ xdata="yes" xcode="yes"
+ code="16" frequency="20 - 60 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="yes" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="yes" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Program memory: ROM
+ High-Speed Architecture
+ X2 Speed Improvement capability
+ Dual Data Pointer
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Hardware Watchdog Timer
+ Asynchronous port reset
+ 4 level priority interrupt system
+ Full duplex Enhanced UART
+ Framing error detection
+ Automatic address recognition
+ Low EMI (inhibit ALE)
+ Idle mode
+ Power-down mode
+ Power-off Flag
+ Once mode (On-chip Emulation)
+ </more><bits>
+ C903 B83F B73F A8BF A209 A707 8E01 8F01 87DF
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON WDTPRG WDTRST
+ RCAP2L RCAP2H TL2 TH2 FE
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="80C58X2"
+ xdata="yes" xcode="yes"
+ code="32" frequency="20 - 60 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="yes" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="yes" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Program memory: ROM
+ High-Speed Architecture
+ X2 Speed Improvement capability
+ Dual Data Pointer
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Hardware Watchdog Timer
+ Asynchronous port reset
+ 4 level priority interrupt system
+ Full duplex Enhanced UART
+ Framing error detection
+ Automatic address recognition
+ Low EMI (inhibit ALE)
+ Idle mode
+ Power-down mode
+ Power-off Flag
+ Once mode (On-chip Emulation)
+ </more><bits>
+ C903 B83F B73F A8BF A209 A707 8E01 8F01 87DF
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON WDTPRG WDTRST
+ RCAP2L RCAP2H TL2 TH2 FE
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="87C54X2"
+ xdata="yes" xcode="yes"
+ code="16" frequency="20 - 60 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="yes" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="yes" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Program memory: EPROM
+ High-Speed Architecture
+ X2 Speed Improvement capability
+ Dual Data Pointer
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Hardware Watchdog Timer
+ Asynchronous port reset
+ 4 level priority interrupt system
+ Full duplex Enhanced UART
+ Framing error detection
+ Automatic address recognition
+ Low EMI (inhibit ALE)
+ Idle mode
+ Power-down mode
+ Power-off Flag
+ Once mode (On-chip Emulation)
+ </more><bits>
+ C903 B83F B73F A8BF A209 A707 8E01 8F01 87DF
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON WDTPRG WDTRST
+ RCAP2L RCAP2H TL2 TH2 FE
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu><mcu
+ vendor="Atmel" name="87C58X2"
+ xdata="yes" xcode="yes"
+ code="32" frequency="20 - 60 MHz"
+ ram="256" portbits="32"
+ uart="yes" interrupts="6"
+ voltage="2.7 to 5.5V" timer2="yes"
+ watchdog="yes" eram="0"
+ dualdtpr="yes" auxr="yes"
+ t2mod="yes" port0="11111111"
+ port1="11111111" port2="11111111"
+ port3="11111111" port4=""
+ pof="yes" gf0="yes"
+ gf1="yes" pd="yes"
+ idl="yes" smod0="yes"
+ iph="yes" acomparator="no"
+ euart="yes" clkreg="no"
+ pwdex="no" spi="no"
+ wdtcon="no" eeprom="0"
+ intelpe="no" pwm="no"
+ x2reset="no" ckcon="yes"
+ auxr1gf3="yes" ao="yes"
+ wdtprg="yes" hddptr="yes"
+ auxrwdidle="no" auxrdisrto="no">
+ <timers>Three 16-bit</timers>
+ <more>
+ Program memory: EPROM
+ High-Speed Architecture
+ X2 Speed Improvement capability
+ Dual Data Pointer
+ Programmable Clock Out and Up/Down Timer/Counter 2
+ Hardware Watchdog Timer
+ Asynchronous port reset
+ 4 level priority interrupt system
+ Full duplex Enhanced UART
+ Framing error detection
+ Automatic address recognition
+ Low EMI (inhibit ALE)
+ Idle mode
+ Power-down mode
+ Power-off Flag
+ Once mode (On-chip Emulation)
+ </more><bits>
+ C903 B83F B73F A8BF A209 A707 8E01 8F01 87DF
+ </bits><writeonly>
+ A6
+ </writeonly><sfr>
+ P0 P1 P2 P3 SBUF ES PS ET2 PT2
+ T2MOD SADEN SADDR AUXR AUXR1 IPH CKCON WDTPRG WDTRST
+ RCAP2L RCAP2H TL2 TH2 FE
+ SCON FE SM0 SM1 SM2 REN TB8 RB8 TI RI
+ T2CON TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2
+ </sfr>
+ </mcu>
+</mcus>
diff --git a/data/project.dtd b/data/project.dtd
new file mode 100644
index 0000000..8663e17
--- /dev/null
+++ b/data/project.dtd
@@ -0,0 +1,220 @@
+<!-- Declare entities -->
+<!ENTITY quot "&#34;">
+<!ENTITY amp "&#38;">
+<!ENTITY lt "&#60;">
+<!ENTITY gt "&#62;">
+
+<!-- ROOT ELEMENT -->
+<!ELEMENT tk_mcuide_project (general, other_options, compiler_options, files)>
+<!-- Root element Parameters:
+ version - Project version (user defined)
+ date - Project last update (user defined)
+ creator_ver - MCU 8051 IDE version (hardcoded in program)
+-->
+<!ATTLIST tk_mcuide_project
+ version CDATA #IMPLIED
+ date CDATA #IMPLIED
+ creator_ver CDATA #IMPLIED
+>
+
+<!-- General information about the project -->
+<!ELEMENT general (authors, copyright, licence, processor, options, graph, description, todo, calculator)>
+
+<!-- List of project authors, one name per line -->
+<!ELEMENT authors (#PCDATA)>
+
+<!-- Copyrigh information -->
+<!ELEMENT copyright (#PCDATA)>
+
+<!-- Project licence -->
+<!ELEMENT licence (#PCDATA)>
+
+<!-- Processor type and configuration -->
+<!ELEMENT processor EMPTY>
+
+<!-- Parameters of tag "processor":
+ type - Processor type (e.g. AT89C51RC or 80C51)
+ clock - Clock frequency in kHz
+ xdata - Size of connected XDATA memory (0 means disconnected)
+ xcode - Size of connected XCODE memory (0 means disconnected)
+-->
+<!ATTLIST processor
+ type CDATA #IMPLIED
+ clock CDATA #IMPLIED
+ xdata CDATA #IMPLIED
+ xcode CDATA #IMPLIED
+>
+
+<!-- Various project options -->
+<!ELEMENT options EMPTY>
+
+<!-- Parameters of tag "options":
+ watches_file - Relative or absolute path to definition file of register watches
+ scheme - Relative or absolute path to scheme file
+ main_file - Main project source code file (e.g. main.c)
+ auto_sw_enabled - Automatic file switching during simulation locked
+-->
+<!ATTLIST options
+ watches_file CDATA #IMPLIED
+ scheme CDATA #IMPLIED
+ main_file CDATA #IMPLIED
+ auto_sw_enabled (0|1) #IMPLIED
+>
+
+<!-- Ports graph definition -->
+<!ELEMENT graph EMPTY>
+
+<!-- Parameters of tag "graph":
+ grid - Grid mode
+ magnification - Magnification level (must be an integer between 0 and 3)
+ enabled - Graph enable flag (Boolean value 0 or 1)
+ marks_s - List of state graph marks (String of zeros and ones, e.g. 00100110)
+ marks_l - List of laches graph marks (String of zeros and ones, e.g. 00100110)
+ marks_o - List of output graph marks (String of zeros and ones, e.g. 00100110)
+ active_page - Active page
+-->
+<!ATTLIST graph
+ grid (n|b|x|y) #IMPLIED
+ magnification (0|1|2|3) #IMPLIED
+ enabled (0|1) #IMPLIED
+ marks_s CDATA #IMPLIED
+ marks_l CDATA #IMPLIED
+ marks_o CDATA #IMPLIED
+ active_page CDATA #IMPLIED
+>
+
+<!-- Project description text (plain text only) -->
+<!ELEMENT description (#PCDATA)>
+
+<!-- Project to do list (SGML format) -->
+<!ELEMENT todo (#PCDATA)>
+
+<!-- Calculator configuration -->
+<!ELEMENT calculator EMPTY>
+
+<!-- Parameters of tag "calculator":
+ radix - Radix (one of {Dec Hex Bin Oct})
+ angle_unit - Angle unit (one of {deg rad grad})
+ display0 - Primary display
+ display1 - Opereator display
+ display2 - Secondary display
+ memory0 - Content of memory bank 0
+ memory1 - Content of memory bank 1
+ memory2 - Content of memory bank 2
+ freq - Timers preset calculator: Frequency
+ time - Timers preset calculator: Desired time
+ mode - Timers preset calculator: Timer mode (one of {0 1 2})
+-->
+<!ATTLIST calculator
+ radix (Dec|Hex|Bin|Oct) #IMPLIED
+ angle_unit (deg|rad|grad) #IMPLIED
+ display0 CDATA #IMPLIED
+ display1 CDATA #IMPLIED
+ display2 CDATA #IMPLIED
+ memory0 CDATA #IMPLIED
+ memory1 CDATA #IMPLIED
+ memory2 CDATA #IMPLIED
+ freq CDATA #IMPLIED
+ time CDATA #IMPLIED
+ mode (0|1|2) #IMPLIED
+>
+
+<!-- Other options (it can contain anything) -->
+<!ELEMENT other_options (#PCDATA)>
+
+<!-- Compiler options -->
+<!ELEMENT compiler_options (#PCDATA)>
+
+<!-- Project files -->
+<!ELEMENT files (file)*>
+
+<!-- Parameters of tag "files":
+ count - Number of project files
+ current_file - Current file in left/top view
+ current_file2 - Current file in right/bottom view (if it's less than zero then editor won't be splitted)
+ pwin_sash - Position of paned window sash (has meaning only if editor was splitted)
+ selected_view - Active view; 0 == left/top, 1 == right/bottom
+ pwin_orient - Orientation of paned window for multiview (one of {horizontal vertical})
+-->
+<!ATTLIST files
+ count CDATA #IMPLIED
+ current_file CDATA #IMPLIED
+ current_file2 CDATA #IMPLIED
+ pwin_sash CDATA #IMPLIED
+ selected_view (0|1) #IMPLIED
+ pwin_orient (horizontal|vertical) #IMPLIED
+>
+
+<!-- Project file description -->
+<!ELEMENT file (actual_line, md5_hash, path, bookmarks, breakpoints, eol, encoding, notes)>
+
+<!-- Parameters of tag "file":
+ name - File name without path
+ active - "yes" == opended; "no" == closed
+ o_bookmark - Bookmark in list of opened files
+ p_bookmark - Bookmark in list of project files
+ file_index - File index in the list
+ read_only - Read only flag
+ highlight - Syntax highlight
+-->
+<!ATTLIST file
+ name CDATA #IMPLIED
+ active (yes|no) #IMPLIED
+ o_bookmark (1|0) #IMPLIED
+ p_bookmark (1|0) #IMPLIED
+ file_index CDATA #IMPLIED
+ read_only (1|0) #IMPLIED
+ highlight CDATA #IMPLIED
+>
+
+<!-- Current line -->
+<!ELEMENT actual_line EMPTY>
+
+<!-- Parameters of tag "actual_line":
+ value - Current line in the file
+-->
+<!ATTLIST actual_line
+ value CDATA #IMPLIED
+>
+
+<!-- MD5 hash for the file -->
+<!ELEMENT md5_hash EMPTY>
+
+<!-- Parameters of tag "md5_hash":
+ value - Last MD5 hash
+-->
+<!ATTLIST md5_hash
+ value CDATA #IMPLIED
+>
+
+<!-- File path -->
+<!ELEMENT path (#PCDATA)>
+
+<!-- Bookmarks: string of zeros and ones -->
+<!ELEMENT bookmarks (#PCDATA)>
+
+<!-- Breakpoints: string of zeros and ones -->
+<!ELEMENT breakpoints (#PCDATA)>
+
+<!-- End Of Line character name -->
+<!ELEMENT eol EMPTY>
+
+<!-- Parameters of tag "eol":
+ value - EOL character (lf == "Line feed" 0x0A; cr == "Carriage return" 0x0D)
+-->
+<!ATTLIST eol
+ value (lf|cr|crlf) #IMPLIED
+>
+
+<!-- File encoding (we strongly recomend to use utf-8 only) -->
+<!ELEMENT encoding EMPTY>
+
+<!-- File notes -->
+<!ELEMENT notes (#PCDATA)>
+
+<!-- Parameters of tag "encoding":
+ value - Name of choosen encoding
+-->
+<!ATTLIST encoding
+ value CDATA #IMPLIED
+> \ No newline at end of file
diff --git a/data/tips.xml b/data/tips.xml
new file mode 100644
index 0000000..3fca882
--- /dev/null
+++ b/data/tips.xml
@@ -0,0 +1,191 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE tips [
+ <!-- ROOT ELEMENT -->
+ <!ELEMENT tips (tip)*>
+
+ <!-- Tip text (Text must be in CDATA section)
+ <b>Bold text</b> normal text
+ -->
+ <!ELEMENT tip EMPTY>
+
+ <!-- Parameters for tag "tip":
+ lang - Text language
+ -->
+ <!ATTLIST tip
+ lang CDATA #REQUIRED
+ >
+]>
+<tips>
+ <tip lang="en">
+ <![CDATA[
+ You can cycle through all opened documents by pressing <b>Alt+Left</b> or <b>Alt+Right</b>. The next/previous document will immediately be displayed in the active frame.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ Graph (tab "IO Ports") significantly slows down MCU simulation ! It is a good to keep it off unless you need it.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can repeat your last search by just pressing <b>F3</b>, or <b>Shift+F3</b> if you want to search backwards.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can swap the characters on each side of the cursor just by pressing <b>Ctrl+T</b>
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can configure syntax highlighting in <b>Editor configuration dialog</b>.
+ <b>Configure</b> -> <b>Editor Configuration</b>
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can easily switch between tabs on Bottom and Right panel.
+ <b>Ctrl+1</b> -> <b>Simulator</b> (Bottom panel)
+ <b>Ctrl+2</b> -> <b>Graph</b> (Bottom panel)
+ <b>Ctrl+3</b> -> <b>Messages</b> (Bottom panel)
+ <b>Ctrl+4</b> -> <b>Todo</b> (Bottom panel)
+ <b>Ctrl+5</b> -> <b>Calculator</b> (Bottom panel)
+ <b>Ctrl+6</b> -> <b>Graph</b> (Bottom panel)
+ <b>Ctrl+7</b> -> <b>Bookmarks</b> (Right panel)
+ <b>Ctrl+8</b> -> <b>Breakpoints</b> (Right panel)
+ <b>Ctrl+9</b> -> <b>Register watches</b> (Right panel)
+ <b>Ctrl+0</b> -> <b>Instruction</b> (Right panel)
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ Sometimes you can make your work easier with editor command line. Inkove it by <b>F10</b> and type <b>help list</b> to get list of avaliable commands.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ Use <b>quick search bars</b>. For instance you need to find a file in list of opened file. Write the name of that file to entrybox below the list and it's done.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ Burn your MSC51 manual (or better colleague's manual). Tab <b>"Instruction details"</b> (<b>Ctrl+0</b>) in the right panel gives you a list of all possible operands for instruction on current line in the editor.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can use function <b>Auto-indent</b> to make badly formated code more readable.
+
+ main: mov A, #55h
+ mov R0,#20h
+ movx @R0, A
+ sjmp main
+ <b>Tools</b> -> <b>Auto indent</b>
+ main: mov A, #55h
+ mov R0, #20h
+ movx @R0, A
+ sjmp main
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ Almost all shortcuts can be redefined in <b>Shortcuts configuration</b> dialog
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can edit content of external data memory and program memory with embedded hexadecimal editor. <b>Simulator</b> -> <b>Show ... memory</b>. So you can write programs directly in machine code (but is's better to use compiler).
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can quickly open files using <b>Filesystem browser</b> on left panel.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ This program have also supprot for command line interaface (CLI). Run <b>mcu8051ide --help</b> to get list of possible options.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ Sometimes you might need to run an external program (e.g program uploader). In MCU 8051 IDE it can be accomplished by <b>Custom commands</b> ( <b>Configure</b> -> <b>Custom commands</b> ).
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can export current document (assembly language source) as XHTML-1.1 or LaTeX.
+ <b>Tools</b> -> <b>Export as ...</b>
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can convert between Intel® HEX 8 and binary files.
+ <b>Tools</b> -> <b>... -> ...</b>
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ Right panel provides list of bookmarks and breakpoints defined in the editor.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can use various encodings and EOLs (End Of Line).
+ <b>Tools</b> -> <b>Encoding/EOL</b>
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ <b>Register watches</b> can make your work much easier. You can find them in the Right panel. Enter hexadecimal address of register which you want to watch to entry box with label "Addr" and press Enter. (1 or 2 hexadecimal digits means <b>IDATA</b> and 3 or 4 digits means <b>XDATA</b>)
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can discuss this project at <b>http://mcu8051ide.sourceforge.net</b>.
+
+ If you do find a bug, please report it either via <b>http://sourceforge.net/tracker/?func=add&group_id=185864&atid=914981</b> or via mail <b>martin.osmera@gmail.com</b>.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can customize compiler behavior in <b>Compiler config</b> dialog.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can enable/disable <b>popup-based completion</b> in editor configuration dialog.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can significantly improve simulator speed by:
+ <b>1)</b> Disabling <b>Step back function</b>
+ <b>2)</b> Disabling <b>Graph</b>
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ Editor can be splitted vertical or horizontal. It Right click on editor status bar and choose split.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can step your program back, default key shortcut is: <b>Ctrl+F7</b>. Behavior of this capability can be modified in simulator configuration dialog.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ MCU 8051 IDE can "hibernate" running program into a file. Later you can resume the hibernated program excatly from the same point where it was hibernated.
+ <b>Simulator</b> -> <b> Hibernate program </b>
+ <b>Simulator</b> -> <b> Resume hibernated program </b>
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ You can navigate simulator to certain line in your source code. Press <b>Ctrl+G</b> in simulator mode and choose line. Simulator will set PC (Program Counter) to address in program memory coresponding to your choosen line.
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ MCU 8051 IDE assembler can perform certain code optimalizations. They are enabled by default but you can disable the in compiler configuration dialog.
+
+ More about optimalizations:
+ LJMP code11 --> AJMP code11
+ LJMP code8 --> SJMP code11
+ LJMP code8 --> SJMP code8
+ AJMP code8 --> SJMP code8
+ LCALL code11 --> ACALL code11
+ MOV 224d, ... --> MOV A, ...
+ MOV ..., 224d --> MOV ..., A
+ SETB 215 --> SETB C
+ CLR 215 --> CLR C
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ Sometimes it is not easy to track subprograms and interrupts invocations. In this IDE you can track them quite easily usining "Interrupt monitor" (<b>Simulator -> Interrupt Monitor</b>) and "List of subprograms" (<b>Ctrl+0</b>).
+ ]]>
+ </tip><tip lang="en">
+ <![CDATA[
+ <b>Map of SFR</b> (<b>Simulator -> Map of SFR</b>) can provide you a transparent view of all special function registers avaliable on your choosen MCU.
+ ]]>
+ </tip>
+<!--
+ <tip lang="en">
+ <![CDATA[
+ ]]>
+ </tip>
+-->
+</tips>
diff --git a/demo/Demo project.mcu8051ide b/demo/Demo project.mcu8051ide
new file mode 100644
index 0000000..21f2ef6
--- /dev/null
+++ b/demo/Demo project.mcu8051ide
@@ -0,0 +1,441 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE tk_mcuide_project [
+
+ <!-- Declare entities -->
+ <!ENTITY quot "&#34;">
+ <!ENTITY amp "&#38;">
+ <!ENTITY lt "&#60;">
+ <!ENTITY gt "&#62;">
+
+ <!-- ROOT ELEMENT -->
+ <!ELEMENT tk_mcuide_project (general, other_options, compiler_options, files)>
+ <!-- Root element Parameters:
+ version - Project version (user defined)
+ date - Project last update (user defined)
+ creator_ver - MCU 8051 IDE version (hardcoded in program)
+ -->
+ <!ATTLIST tk_mcuide_project
+ version CDATA #IMPLIED
+ date CDATA #IMPLIED
+ creator_ver CDATA #IMPLIED
+ >
+
+ <!-- General information about the project -->
+ <!ELEMENT general (authors, copyright, licence, processor, options, graph, description, todo, calculator)>
+
+ <!-- List of project authors, one name per line -->
+ <!ELEMENT authors (#PCDATA)>
+
+ <!-- Copyrigh information -->
+ <!ELEMENT copyright (#PCDATA)>
+
+ <!-- Project licence -->
+ <!ELEMENT licence (#PCDATA)>
+
+ <!-- Processor type and configuration -->
+ <!ELEMENT processor EMPTY>
+
+ <!-- Parameters of tag "processor":
+ type - Processor type (e.g. AT89C51RC or 80C51)
+ clock - Clock frequency in kHz
+ xdata - Size of connected XDATA memory (0 means disconnected)
+ xcode - Size of connected XCODE memory (0 means disconnected)
+ -->
+ <!ATTLIST processor
+ type CDATA #IMPLIED
+ clock CDATA #IMPLIED
+ xdata CDATA #IMPLIED
+ xcode CDATA #IMPLIED
+ >
+
+ <!-- Various project options -->
+ <!ELEMENT options EMPTY>
+
+ <!-- Parameters of tag "options":
+ watches_file - Relative or absolute path to definition file of register watches
+ scheme - Relative or absolute path to scheme file
+ main_file - Main project source code file (e.g. main.c)
+ auto_sw_enabled - Automatic file switching during simulation locked
+ -->
+ <!ATTLIST options
+ watches_file CDATA #IMPLIED
+ scheme CDATA #IMPLIED
+ main_file CDATA #IMPLIED
+ auto_sw_enabled (0|1) #IMPLIED
+ >
+
+ <!-- Ports graph definition -->
+ <!ELEMENT graph EMPTY>
+
+ <!-- Parameters of tag "graph":
+ grid - Grid mode
+ magnification - Magnification level (must be an integer between 0 and 3)
+ enabled - Graph enable flag (Boolean value 0 or 1)
+ marks_s - List of state graph marks (String of zeros and ones, e.g. 00100110)
+ marks_l - List of laches graph marks (String of zeros and ones, e.g. 00100110)
+ marks_o - List of output graph marks (String of zeros and ones, e.g. 00100110)
+ active_page - Active page
+ -->
+ <!ATTLIST graph
+ grid (n|b|x|y) #IMPLIED
+ magnification (0|1|2|3) #IMPLIED
+ enabled (0|1) #IMPLIED
+ marks_s CDATA #IMPLIED
+ marks_l CDATA #IMPLIED
+ marks_o CDATA #IMPLIED
+ active_page CDATA #IMPLIED
+ >
+
+ <!-- Project description text (plain text only) -->
+ <!ELEMENT description (#PCDATA)>
+
+ <!-- Project to do list (SGML format) -->
+ <!ELEMENT todo (#PCDATA)>
+
+ <!-- Calculator configuration -->
+ <!ELEMENT calculator EMPTY>
+
+ <!-- Parameters of tag "calculator":
+ radix - Radix (one of {Dec Hex Bin Oct})
+ angle_unit - Angle unit (one of {deg rad grad})
+ display0 - Primary display
+ display1 - Opereator display
+ display2 - Secondary display
+ memory0 - Content of memory bank 0
+ memory1 - Content of memory bank 1
+ memory2 - Content of memory bank 2
+ freq - Timers preset calculator: Frequency
+ time - Timers preset calculator: Desired time
+ mode - Timers preset calculator: Timer mode (one of {0 1 2})
+ -->
+ <!ATTLIST calculator
+ radix (Dec|Hex|Bin|Oct) #IMPLIED
+ angle_unit (deg|rad|grad) #IMPLIED
+ display0 CDATA #IMPLIED
+ display1 CDATA #IMPLIED
+ display2 CDATA #IMPLIED
+ memory0 CDATA #IMPLIED
+ memory1 CDATA #IMPLIED
+ memory2 CDATA #IMPLIED
+ freq CDATA #IMPLIED
+ time CDATA #IMPLIED
+ mode (0|1|2) #IMPLIED
+ >
+
+ <!-- Other options (it can contain anything) -->
+ <!ELEMENT other_options (#PCDATA)>
+
+ <!-- Compiler options -->
+ <!ELEMENT compiler_options (#PCDATA)>
+
+ <!-- Project files -->
+ <!ELEMENT files (file)*>
+
+ <!-- Parameters of tag "files":
+ count - Number of project files
+ current_file - Current file in left/top view
+ current_file2 - Current file in right/bottom view (if it's less than zero then editor won't be splitted)
+ pwin_sash - Position of paned window sash (has meaning only if editor was splitted)
+ selected_view - Active view; 0 == left/top, 1 == right/bottom
+ pwin_orient - Orientation of paned window for multiview (one of {horizontal vertical})
+ -->
+ <!ATTLIST files
+ count CDATA #IMPLIED
+ current_file CDATA #IMPLIED
+ current_file2 CDATA #IMPLIED
+ pwin_sash CDATA #IMPLIED
+ selected_view (0|1) #IMPLIED
+ pwin_orient (horizontal|vertical) #IMPLIED
+ >
+
+ <!-- Project file description -->
+ <!ELEMENT file (actual_line, md5_hash, path, bookmarks, breakpoints, eol, encoding, notes)>
+
+ <!-- Parameters of tag "file":
+ name - File name without path
+ active - "yes" == opended; "no" == closed
+ o_bookmark - Bookmark in list of opened files
+ p_bookmark - Bookmark in list of project files
+ file_index - File index in the list
+ read_only - Read only flag
+ highlight - Syntax highlight
+ -->
+ <!ATTLIST file
+ name CDATA #IMPLIED
+ active (yes|no) #IMPLIED
+ o_bookmark (1|0) #IMPLIED
+ p_bookmark (1|0) #IMPLIED
+ file_index CDATA #IMPLIED
+ read_only (1|0) #IMPLIED
+ highlight CDATA #IMPLIED
+ >
+
+ <!-- Current line -->
+ <!ELEMENT actual_line EMPTY>
+
+ <!-- Parameters of tag "actual_line":
+ value - Current line in the file
+ -->
+ <!ATTLIST actual_line
+ value CDATA #IMPLIED
+ >
+
+ <!-- MD5 hash for the file -->
+ <!ELEMENT md5_hash EMPTY>
+
+ <!-- Parameters of tag "md5_hash":
+ value - Last MD5 hash
+ -->
+ <!ATTLIST md5_hash
+ value CDATA #IMPLIED
+ >
+
+ <!-- File path -->
+ <!ELEMENT path (#PCDATA)>
+
+ <!-- Bookmarks: string of zeros and ones -->
+ <!ELEMENT bookmarks (#PCDATA)>
+
+ <!-- Breakpoints: string of zeros and ones -->
+ <!ELEMENT breakpoints (#PCDATA)>
+
+ <!-- End Of Line character name -->
+ <!ELEMENT eol EMPTY>
+
+ <!-- Parameters of tag "eol":
+ value - EOL character (lf == "Line feed" 0x0A; cr == "Carriage return" 0x0D)
+ -->
+ <!ATTLIST eol
+ value (lf|cr|crlf) #IMPLIED
+ >
+
+ <!-- File encoding (we strongly recomend to use utf-8 only) -->
+ <!ELEMENT encoding EMPTY>
+
+ <!-- File notes -->
+ <!ELEMENT notes (#PCDATA)>
+
+ <!-- Parameters of tag "encoding":
+ value - Name of choosen encoding
+ -->
+ <!ATTLIST encoding
+ value CDATA #IMPLIED
+ >
+]>
+<tk_mcuide_project version="0.9.5" date="03/02/09" creator_ver="1.3.3">
+ <general>
+ <authors><![CDATA[Martin Osmera &lt;martin.osmera@gmail.com&gt;
+]]></authors>
+ <copyright><![CDATA[]]></copyright>
+ <licence><![CDATA[GPLv2]]></licence>
+ <processor type="AT89S2051" clock="12000" xdata="0" xcode="0"/>
+ <options
+ watches_file="demo.wtc"
+ scheme=""
+ main_file=""
+ auto_sw_enabled="1"
+ />
+ <graph
+ grid="y"
+ magnification="0"
+ enabled="1"
+ marks_s="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ marks_l="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ marks_o="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ active_page="output"
+ />
+ <description><![CDATA[This is demonstration project for MCU 8051 IDE and nothing more.
+
+Thank you for using MCU 8051 IDE.
+]]></description>
+ <todo><![CDATA[ <u><b>WELCOME TO MCU 8051 IDE</u></b>
+
+<u>What does it consist of:</u> <u>Basic key shortcuts:</u>
+ LEFT: <b>F2</b> - <i>Initialize simulator</i>
+<i> 1. List of opened files </i><b>F7</b> - <i>Step program</i>
+<i> 2. List of project files </i><b>F6</b> - <i>Animate program</i>
+<i> 3. Filesystem browser </i><b>F4</b> - <i>Reset simulator</i>
+<i> 4. SFR watches </i><b>CTRL+F7</b> - Step back
+ RIGHT: <bookmark/> Thank you for trying MCU 8051 IDE
+<i> 1. Bookmarks
+ 2. Breakpoints
+ 3. Symbol list
+ 4. Instruction details
+ 5. Register watches
+ 6. Subprograms monitor
+</i> 7. HW plug-ins
+ BOTTOM:
+<i> 1. Simulator panel
+ 2. C code debugger
+ 3. Graph of voltage levels on processor ports
+ 4. Messages text (Compiler output)
+ 5. This text editor
+ 6. Scientific calculator and calculator for computing timer preset
+ 7. Terminal emulator
+</i> 8. Tool for searching in files
+
+]]></todo>
+ <calculator
+ radix="Dec"
+ angle_unit="rad"
+ display0="88"
+ display1="add"
+ display2="99"
+ memory0="88"
+ memory1="66"
+ memory2="45"
+ freq="12000"
+ time="565"
+ mode="0"
+ />
+ </general>
+ <other_options><![CDATA[]]></other_options>
+ <compiler_options><![CDATA[{_title 0 _list 0 _print 0 _nomod 0 max_ihex_rec_length 255 _object 0 _pagelength 0 QUIET 0 _symbols 0 CREATE_SIM_FILE 1 CREATE_BIN_FILE 1 _pagewidth 0 optim_ena 0 _date 0 _paging 0 WARNING_LEVEL 0} 0 {--verbose 1 -i {} custom {} --columns 0 --omf-51 0} {adf 1} {-L 1 -M 0 custom {} -n 0 -P 0 -A 0 -a 0 -r {} -C 0 -c 0 -s 1 -U 0 -u 0 -g MAP -w 0 -cpu 8051 -x 0 -h 0 -quiet 0 -i {} -I 1} {ihex 1 adf 1} {--out-fmt-s19 0 --fdollars-in-identifiers 0 --nogcse 0 --nooverlay 1 --no-peep-comments 0 --no-c-code-in-asm 0 --print-search-dirs 0 --nostdlib 0 --peep-asm 0 --nolabelopt 0 --short-is-8bits 0 --cyclomatic 0 --compile-only 0 --no-reg-params 0 --noinvariant 0 --profile 0 --out-fmt-ihx 0 --noinduction 1 --opt-code-size 0 --nojtbound 0 --no-peep 0 --less-pedantic 0 --no-xinit-opt 0 --xstack 0 --funsigned-char 0 --verbose 1 -S 0 --debug 1 --preprocessonly 0 --opt-code-speed 0 --parms-in-bank1 0 --float-reent 0 -V 1 --c1mode 0 --fverbose-asm 0 --fommit-frame-pointer 0 --xram-movc 0 --main-return 0 --nostdinc 0 --noloopreverse 0 --stack-probe 0 --all-callee-saves 0 --int-long-reent 0 --stack-auto 0 --use-stdout 0} {standard --std-sdcc89 model --model-small stack --pack-iram custom {}} {--stack-size {} --code-loc {} --constseg {} --codeseg {} --xram-loc {} --data-loc {} --stack-loc {} --xstack-loc {} --lib-path {}} {--disable-warning {} -L {} -l {} -I {}} {} {}]]></compiler_options>
+ <files
+ count="9"
+ current_file="8"
+ current_file2="-1"
+ pwin_sash="304"
+ selected_view="0"
+ pwin_orient="horizontal">
+
+ <file name="demo0.asm" active="yes" o_bookmark="0" p_bookmark="0" file_index="0" read_only="0" highlight="0">
+ <actual_line value="1"/>
+ <md5_hash value="433B30D0A7A37EA31EA1FC96F9A63294"/>
+ <path><![CDATA[]]></path>
+ <bookmarks>
+ 00000000000000001000000000000
+ </bookmarks>
+ <breakpoints>
+ 00000000000000000100000000000
+ </breakpoints>
+ <eol value="lf"/>
+ <encoding value="utf-8"/>
+ <notes><![CDATA[Basic demonstration code ...
+]]></notes>
+ </file>
+
+ <file name="demo1.asm" active="yes" o_bookmark="0" p_bookmark="0" file_index="1" read_only="0" highlight="0">
+ <actual_line value="1"/>
+ <md5_hash value="D9C47EC024BB961B1F86B2A2C82D6D7A"/>
+ <path><![CDATA[]]></path>
+ <bookmarks>
+ 00000000000000000000000000000000000000000000000000000000000000000
+ </bookmarks>
+ <breakpoints>
+ 00000000000000000000000000000000000000000000000000000000000000000
+ </breakpoints>
+ <eol value="lf"/>
+ <encoding value="utf-8"/>
+ <notes><![CDATA[Quite more advance demonstration code ...
+]]></notes>
+ </file>
+
+ <file name="demo2.asm" active="yes" o_bookmark="0" p_bookmark="0" file_index="2" read_only="0" highlight="0">
+ <actual_line value="1"/>
+ <md5_hash value="016FCF566042EC66EE9118BAFA4D4A35"/>
+ <path><![CDATA[]]></path>
+ <bookmarks>
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000
+ </bookmarks>
+ <breakpoints>
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000
+ </breakpoints>
+ <eol value="lf"/>
+ <encoding value="utf-8"/>
+ <notes><![CDATA[Next demonstration code ...
+]]></notes>
+ </file>
+
+ <file name="demo3.asm" active="yes" o_bookmark="0" p_bookmark="0" file_index="3" read_only="0" highlight="0">
+ <actual_line value="1"/>
+ <md5_hash value="6180D365C7F535CABD42C3E78A0798B9"/>
+ <path><![CDATA[]]></path>
+ <bookmarks>
+ 00000000000000000000000000000000000000000000000000000000000000000000000000
+ </bookmarks>
+ <breakpoints>
+ 00000000000000000000000000000000000000000000000000000000000000000000000000
+ </breakpoints>
+ <eol value="lf"/>
+ <encoding value="utf-8"/>
+ <notes><![CDATA[]]></notes>
+ </file>
+
+ <file name="demo5.asm" active="yes" o_bookmark="0" p_bookmark="0" file_index="4" read_only="0" highlight="0">
+ <actual_line value="13"/>
+ <md5_hash value="8A77C444C26BA55C5A8AC82FE0C8CFA9"/>
+ <path><![CDATA[]]></path>
+ <bookmarks>
+ 000000000000000000000000000000000000
+ </bookmarks>
+ <breakpoints>
+ 000000000000000000000000000000000000
+ </breakpoints>
+ <eol value="lf"/>
+ <encoding value="utf-8"/>
+ <notes><![CDATA[]]></notes>
+ </file>
+
+ <file name="demo_c_0.c" active="yes" o_bookmark="0" p_bookmark="0" file_index="5" read_only="0" highlight="1">
+ <actual_line value="1"/>
+ <md5_hash value="79C98C5ADE29831807D59F6BC438063A"/>
+ <path><![CDATA[]]></path>
+ <bookmarks>
+ 0000000000000000000000000000000000000000000
+ </bookmarks>
+ <breakpoints>
+ 0000000000000000000000000000000000000000000
+ </breakpoints>
+ <eol value="lf"/>
+ <encoding value="utf-8"/>
+ <notes><![CDATA[]]></notes>
+ </file>
+
+ <file name="ledmatrix.c" active="yes" o_bookmark="0" p_bookmark="0" file_index="6" read_only="0" highlight="1">
+ <actual_line value="1"/>
+ <md5_hash value="517133F895352F3918C3E1250EA990A5"/>
+ <path><![CDATA[]]></path>
+ <bookmarks>
+ 000000000000000000000000000000000000000000000
+ </bookmarks>
+ <breakpoints>
+ 000000000000000000000000000000000000000000000
+ </breakpoints>
+ <eol value="lf"/>
+ <encoding value="utf-8"/>
+ <notes><![CDATA[]]></notes>
+ </file>
+
+ <file name="keypad_display.c" active="yes" o_bookmark="0" p_bookmark="0" file_index="7" read_only="0" highlight="1">
+ <actual_line value="10"/>
+ <md5_hash value="E44E4DC2094E8EB729FE653002B40A33"/>
+ <path><![CDATA[]]></path>
+ <bookmarks>
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ </bookmarks>
+ <breakpoints>
+ 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ </breakpoints>
+ <eol value="lf"/>
+ <encoding value="utf-8"/>
+ <notes><![CDATA[]]></notes>
+ </file>
+
+ <file name="mleddisplay.asm" active="yes" o_bookmark="0" p_bookmark="0" file_index="8" read_only="0" highlight="0">
+ <actual_line value="15"/>
+ <md5_hash value="BFC1B21D558BFAE2B1E43162DAEFE347"/>
+ <path><![CDATA[]]></path>
+ <bookmarks>
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ </bookmarks>
+ <breakpoints>
+ 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ </breakpoints>
+ <eol value="lf"/>
+ <encoding value="utf-8"/>
+ <notes><![CDATA[]]></notes>
+ </file>
+
+ </files>
+</tk_mcuide_project> \ No newline at end of file
diff --git a/demo/demo.wtc b/demo/demo.wtc
new file mode 100644
index 0000000..505abd2
--- /dev/null
+++ b/demo/demo.wtc
@@ -0,0 +1,15 @@
+# Watches definition file -- MCU 8051 IDE v1.3.1
+# Date: 10/27/2009
+ FF Register watches
+00FF Some XRAM reg
+ 0FF Some ERAM reg
+ 00 ----------------
+ 80 IDATA reg not SFR
+ 90 IDATA reg not SFR
+ A0 IDATA reg not SFR
+ B0 IDATA reg not SFR
+ D0 ----------------
+ .20 Some bit
+ .21 Another bit
+ 20 DATA_PTR
+ 0F COUNTER \ No newline at end of file
diff --git a/demo/demo0.adf b/demo/demo0.adf
new file mode 100644
index 0000000..7de7de2
--- /dev/null
+++ b/demo/demo0.adf
@@ -0,0 +1,9 @@
+# Assembler debug file for MCU 8051 IDE v1.1
+# Used assembler: MCU 8051 IDE
+# Date: 03/02/09
+87B0FFA871A3B2978A4FD4309AE5D3D4 "demo0.asm"
+0 8 0 8
+0 9 1 6
+0 10 2 184 127 251
+0 11 5 120 0
+0 12 7 128 247 \ No newline at end of file
diff --git a/demo/demo0.asm b/demo/demo0.asm
new file mode 100644
index 0000000..f44ee47
--- /dev/null
+++ b/demo/demo0.asm
@@ -0,0 +1,27 @@
+; MCU 8051 IDE - Demostration code
+; Very simple code
+
+; Press F2 and F6 to run the program (start simulator and animate)
+
+ org 0h
+
+main: inc R0
+ inc @R0
+ cjne R0, #07Fh, main
+ mov R0, #0d
+ sjmp main
+
+ end
+
+; <-- Bookmark (try Alt+PgUp/Alt+PgDown)
+; <-- Breakpoint
+
+; -----------------------------------------
+; NOTICE:
+; Simulator limitations:
+; * SPI
+; * Access to external code memory
+; * Power down modes
+; -----------------------------------------
+
+; IF YOU HAVE FOUND SOME BUG IN THIS IDE , PLEASE LET ME KNOW
diff --git a/demo/demo0.bin b/demo/demo0.bin
new file mode 100644
index 0000000..5511873
--- /dev/null
+++ b/demo/demo0.bin
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/demo/demo0.hex b/demo/demo0.hex
new file mode 100644
index 0000000..d34107a
--- /dev/null
+++ b/demo/demo0.hex
@@ -0,0 +1,2 @@
+:090000000806B87FFB780080F7C8
+:00000001FF \ No newline at end of file
diff --git a/demo/demo0.lst b/demo/demo0.lst
new file mode 100644
index 0000000..2a87958
--- /dev/null
+++ b/demo/demo0.lst
@@ -0,0 +1,198 @@
+demo0 PAGE 1
+ 1 ; MCU 8051 IDE - Demostration code
+ 2 ; Very simple code
+ 3
+ 4 ; Press F2 and F6 to run the program (start simulator and animate)
+ 5
+ 6 org 0h
+ 7
+0000 06 8 main: inc R0
+0001 B87FFB 9 inc @R0
+0002 7800 10 cjne R0, #07Fh, main
+0005 80F7 11 mov R0, #0d
+ 12 sjmp main
+ 13
+ 14 end
+ASSEMBLY COMPLETE, NO ERRORS FOUND, NO WARNINGS
+
+
+SYMBOL TABLE:
+AC . . . . . . . . . . . . . . . . . B ADDR 00D6H NOT USED
+ACC. . . . . . . . . . . . . . . . . D ADDR 00E0H NOT USED
+ACSR . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+ADCF . . . . . . . . . . . . . . . . D ADDR 00F6H NOT USED
+ADCLK. . . . . . . . . . . . . . . . D ADDR 00F2H NOT USED
+ADCON. . . . . . . . . . . . . . . . D ADDR 00F3H NOT USED
+ADDH . . . . . . . . . . . . . . . . D ADDR 00F5H NOT USED
+ADDL . . . . . . . . . . . . . . . . D ADDR 00F4H NOT USED
+AUXR . . . . . . . . . . . . . . . . D ADDR 008EH NOT USED
+AUXR1. . . . . . . . . . . . . . . . D ADDR 00A2H NOT USED
+B. . . . . . . . . . . . . . . . . . D ADDR 00F0H NOT USED
+BDRCON . . . . . . . . . . . . . . . D ADDR 009BH NOT USED
+BDRCON_1 . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+BRL. . . . . . . . . . . . . . . . . D ADDR 009AH NOT USED
+CCAP0H . . . . . . . . . . . . . . . D ADDR 00FAH NOT USED
+CCAP0L . . . . . . . . . . . . . . . D ADDR 00EAH NOT USED
+CCAP1H . . . . . . . . . . . . . . . D ADDR 00FBH NOT USED
+CCAP1L . . . . . . . . . . . . . . . D ADDR 00EBH NOT USED
+CCAP2H . . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAP3H . . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAP4H . . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL2H. . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAPL2L. . . . . . . . . . . . . . . D ADDR 00ECH NOT USED
+CCAPL3H. . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAPL3L. . . . . . . . . . . . . . . D ADDR 00EDH NOT USED
+CCAPL4H. . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL4L. . . . . . . . . . . . . . . D ADDR 00EEH NOT USED
+CCAPM0 . . . . . . . . . . . . . . . D ADDR 00DAH NOT USED
+CCAPM1 . . . . . . . . . . . . . . . D ADDR 00DBH NOT USED
+CCAPM2 . . . . . . . . . . . . . . . D ADDR 00DCH NOT USED
+CCAPM3 . . . . . . . . . . . . . . . D ADDR 00DDH NOT USED
+CCAPM4 . . . . . . . . . . . . . . . D ADDR 00DEH NOT USED
+CCF0 . . . . . . . . . . . . . . . . B ADDR 00D8H NOT USED
+CCF1 . . . . . . . . . . . . . . . . B ADDR 00D9H NOT USED
+CCF2 . . . . . . . . . . . . . . . . B ADDR 00DAH NOT USED
+CCF3 . . . . . . . . . . . . . . . . B ADDR 00DBH NOT USED
+CCF4 . . . . . . . . . . . . . . . . B ADDR 00DCH NOT USED
+CCON . . . . . . . . . . . . . . . . D ADDR 00D8H NOT USED
+CFINT. . . . . . . . . . . . . . . . C ADDR 0033H NOT USED
+CH . . . . . . . . . . . . . . . . . D ADDR 00F9H NOT USED
+CKCON. . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKCON0 . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKRL . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+CKSEL. . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+CL . . . . . . . . . . . . . . . . . D ADDR 00E9H NOT USED
+CLKREG . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CMOD . . . . . . . . . . . . . . . . D ADDR 00D9H NOT USED
+CPRL2. . . . . . . . . . . . . . . . B ADDR 00C8H NOT USED
+CR . . . . . . . . . . . . . . . . . B ADDR 00DEH NOT USED
+CT2. . . . . . . . . . . . . . . . . B ADDR 00C9H NOT USED
+CY . . . . . . . . . . . . . . . . . B ADDR 00D7H NOT USED
+DP0H . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DP0L . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+DP1H . . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+DP1L . . . . . . . . . . . . . . . . D ADDR 0084H NOT USED
+DPH. . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DPL. . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+EA . . . . . . . . . . . . . . . . . B ADDR 00AFH NOT USED
+EC . . . . . . . . . . . . . . . . . B ADDR 00AEH NOT USED
+EECON. . . . . . . . . . . . . . . . D ADDR 0096H NOT USED
+ES . . . . . . . . . . . . . . . . . B ADDR 00ACH NOT USED
+ET0. . . . . . . . . . . . . . . . . B ADDR 00A9H NOT USED
+ET1. . . . . . . . . . . . . . . . . B ADDR 00ABH NOT USED
+ET2. . . . . . . . . . . . . . . . . B ADDR 00ADH NOT USED
+EX0. . . . . . . . . . . . . . . . . B ADDR 00A8H NOT USED
+EX1. . . . . . . . . . . . . . . . . B ADDR 00AAH NOT USED
+EXEN2. . . . . . . . . . . . . . . . B ADDR 00CBH NOT USED
+EXF2 . . . . . . . . . . . . . . . . B ADDR 00CEH NOT USED
+EXTI0. . . . . . . . . . . . . . . . C ADDR 0003H NOT USED
+EXTI1. . . . . . . . . . . . . . . . C ADDR 0013H NOT USED
+F0 . . . . . . . . . . . . . . . . . B ADDR 00D5H NOT USED
+FE . . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+IE . . . . . . . . . . . . . . . . . D ADDR 00A8H NOT USED
+IE0. . . . . . . . . . . . . . . . . B ADDR 0089H NOT USED
+IE1. . . . . . . . . . . . . . . . . B ADDR 008BH NOT USED
+INT0 . . . . . . . . . . . . . . . . B ADDR 00B2H NOT USED
+INT1 . . . . . . . . . . . . . . . . B ADDR 00B3H NOT USED
+IP . . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPH. . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH0 . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH1 . . . . . . . . . . . . . . . . D ADDR 00B3H NOT USED
+IPL0 . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPL1 . . . . . . . . . . . . . . . . D ADDR 00B2H NOT USED
+IT0. . . . . . . . . . . . . . . . . B ADDR 0088H NOT USED
+IT1. . . . . . . . . . . . . . . . . B ADDR 008AH NOT USED
+KBE. . . . . . . . . . . . . . . . . D ADDR 009DH NOT USED
+KBF. . . . . . . . . . . . . . . . . D ADDR 009EH NOT USED
+KBLS . . . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+MAIN . . . . . . . . . . . . . . . . C ADDR 0000H
+OSCCON . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+OV . . . . . . . . . . . . . . . . . B ADDR 00D2H NOT USED
+P. . . . . . . . . . . . . . . . . . B ADDR 00D0H NOT USED
+P0 . . . . . . . . . . . . . . . . . D ADDR 0080H NOT USED
+P1 . . . . . . . . . . . . . . . . . D ADDR 0090H NOT USED
+P1M1 . . . . . . . . . . . . . . . . D ADDR 00D4H NOT USED
+P1M2 . . . . . . . . . . . . . . . . D ADDR 00E2H NOT USED
+P2 . . . . . . . . . . . . . . . . . D ADDR 00A0H NOT USED
+P3 . . . . . . . . . . . . . . . . . D ADDR 00B0H NOT USED
+P3M1 . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+P3M2 . . . . . . . . . . . . . . . . D ADDR 00E3H NOT USED
+P4 . . . . . . . . . . . . . . . . . D ADDR 00C0H NOT USED
+P4M1 . . . . . . . . . . . . . . . . D ADDR 00D6H NOT USED
+P4M2 . . . . . . . . . . . . . . . . D ADDR 00E4H NOT USED
+P5 . . . . . . . . . . . . . . . . . D ADDR 00E8H NOT USED
+PC . . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PCON . . . . . . . . . . . . . . . . D ADDR 0087H NOT USED
+PPCL . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PS . . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSL. . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSW. . . . . . . . . . . . . . . . . D ADDR 00D0H NOT USED
+PT0. . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT0L . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT1. . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT1L . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT2. . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PT2L . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PX0. . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX0L . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX1. . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+PX1L . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+RB8. . . . . . . . . . . . . . . . . B ADDR 009AH NOT USED
+RCAP2H . . . . . . . . . . . . . . . D ADDR 00CBH NOT USED
+RCAP2L . . . . . . . . . . . . . . . D ADDR 00CAH NOT USED
+RCLK . . . . . . . . . . . . . . . . B ADDR 00CDH NOT USED
+RD . . . . . . . . . . . . . . . . . B ADDR 00B7H NOT USED
+REN. . . . . . . . . . . . . . . . . B ADDR 009CH NOT USED
+RESET. . . . . . . . . . . . . . . . C ADDR 0000H NOT USED
+RI . . . . . . . . . . . . . . . . . B ADDR 0098H NOT USED
+RS0. . . . . . . . . . . . . . . . . B ADDR 00D3H NOT USED
+RS1. . . . . . . . . . . . . . . . . B ADDR 00D4H NOT USED
+RXD. . . . . . . . . . . . . . . . . B ADDR 00B0H NOT USED
+SADDR. . . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_0. . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_1. . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SADEN. . . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_0. . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_1. . . . . . . . . . . . . . . D ADDR 00BAH NOT USED
+SBUF . . . . . . . . . . . . . . . . D ADDR 0099H NOT USED
+SCON . . . . . . . . . . . . . . . . D ADDR 0098H NOT USED
+SINT . . . . . . . . . . . . . . . . C ADDR 0023H NOT USED
+SM0. . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+SM1. . . . . . . . . . . . . . . . . B ADDR 009EH NOT USED
+SM2. . . . . . . . . . . . . . . . . B ADDR 009DH NOT USED
+SP . . . . . . . . . . . . . . . . . D ADDR 0081H NOT USED
+SPCON. . . . . . . . . . . . . . . . D ADDR 00C3H NOT USED
+SPCR . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+SPDAT. . . . . . . . . . . . . . . . D ADDR 00C5H NOT USED
+SPDR . . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+SPSR . . . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SPSTA. . . . . . . . . . . . . . . . D ADDR 00C4H NOT USED
+T0 . . . . . . . . . . . . . . . . . B ADDR 00B4H NOT USED
+T1 . . . . . . . . . . . . . . . . . B ADDR 00B5H NOT USED
+T2CON. . . . . . . . . . . . . . . . D ADDR 00C8H NOT USED
+T2MOD. . . . . . . . . . . . . . . . D ADDR 00C9H NOT USED
+TB8. . . . . . . . . . . . . . . . . B ADDR 009BH NOT USED
+TCLK . . . . . . . . . . . . . . . . B ADDR 00CCH NOT USED
+TCON . . . . . . . . . . . . . . . . D ADDR 0088H NOT USED
+TF0. . . . . . . . . . . . . . . . . B ADDR 008DH NOT USED
+TF1. . . . . . . . . . . . . . . . . B ADDR 008FH NOT USED
+TF2. . . . . . . . . . . . . . . . . B ADDR 00CFH NOT USED
+TH0. . . . . . . . . . . . . . . . . D ADDR 008CH NOT USED
+TH1. . . . . . . . . . . . . . . . . D ADDR 008DH NOT USED
+TH2. . . . . . . . . . . . . . . . . D ADDR 00CDH NOT USED
+TI . . . . . . . . . . . . . . . . . B ADDR 0099H NOT USED
+TIMER0 . . . . . . . . . . . . . . . C ADDR 000BH NOT USED
+TIMER1 . . . . . . . . . . . . . . . C ADDR 001BH NOT USED
+TIMER2 . . . . . . . . . . . . . . . C ADDR 002BH NOT USED
+TL0. . . . . . . . . . . . . . . . . D ADDR 008AH NOT USED
+TL1. . . . . . . . . . . . . . . . . D ADDR 008BH NOT USED
+TL2. . . . . . . . . . . . . . . . . D ADDR 00CCH NOT USED
+TMOD . . . . . . . . . . . . . . . . D ADDR 0089H NOT USED
+TR0. . . . . . . . . . . . . . . . . B ADDR 008CH NOT USED
+TR1. . . . . . . . . . . . . . . . . B ADDR 008EH NOT USED
+TR2. . . . . . . . . . . . . . . . . B ADDR 00CAH NOT USED
+TXD. . . . . . . . . . . . . . . . . B ADDR 00B1H NOT USED
+WDTCON . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTPRG . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTRST . . . . . . . . . . . . . . . D ADDR 00A6H NOT USED
+WR . . . . . . . . . . . . . . . . . B ADDR 00B6H NOT USED \ No newline at end of file
diff --git a/demo/demo0.sim b/demo/demo0.sim
new file mode 100644
index 0000000..a2482bc
--- /dev/null
+++ b/demo/demo0.sim
@@ -0,0 +1,6 @@
+458DB610414A7EC882B8DFA06C1D6748 12/21/07 demo0.asm
+8 0 8
+9 1 6
+10 2 184 127 251
+11 5 120 0
+12 7 128 247 \ No newline at end of file
diff --git a/demo/demo1.adf b/demo/demo1.adf
new file mode 100644
index 0000000..e4387cf
--- /dev/null
+++ b/demo/demo1.adf
@@ -0,0 +1,19 @@
+# Assembler debug file for MCU 8051 IDE v1.1
+# Used assembler: MCU 8051 IDE
+# Date: 03/02/09
+D9C47EC024BB961B1F86B2A2C82D6D7A "demo1.asm"
+0 48 0 128 0
+0 52 2 117 144 15
+0 53 5 117 176 30
+0 54 8 128 0
+0 58 10 229 15
+0 58 12 4
+0 58 13 245 15
+0 58 15 133 144 176
+0 58 18 133 176 144
+0 58 21 211
+0 58 22 229 144
+0 58 24 35
+0 58 25 245 144
+0 59 27 128 237
+0 17 29 4 \ No newline at end of file
diff --git a/demo/demo1.asm b/demo/demo1.asm
new file mode 100644
index 0000000..3ba82dd
--- /dev/null
+++ b/demo/demo1.asm
@@ -0,0 +1,63 @@
+; MCU 8051 IDE - Demostration code
+; Macro instructions, conditional compilation and constants
+; Try tab "Graph" on bottom panel
+
+; Press F2 and F6 to run the program (start simulator and animate)
+
+$TITLE('DEMO 2') ; Set title for code listing
+$DATE(36/-4/1907) ; Set date for code listing
+
+; Constant definitions
+; --------------------
+counter idata 00Fh ; Counter of Px shifts
+x set 100 ; Some variable
+inc_dec equ 100 / X ; Flag: Increment/Decrement counter
+
+ cseg at 1FFh ; Code segment starts at 0x1FF
+something: db 4d ; Reserve 4 bytes in this segment
+
+; Macro instructions
+; --------------------
+
+;; Shift the given registeres
+shift macro reg0, reg1
+
+ ; Increment / Decrement counter
+ mov A, counter
+ if inc_dec <> 0
+ inc A
+ else
+ dec A
+ endif
+ $nolist ; <- Disable code listing
+ mov counter, A
+ $list ; <- Enable code listing
+
+ ; Shift
+ mov reg1, reg0
+ mov reg0, reg1
+ setb C
+ mov A, reg0
+ rl A
+ mov reg0, A
+endm
+
+; Program initilization
+; --------------------
+ org 0h
+ sjmp start
+
+; Program start
+; --------------------
+start: mov P1, #00Fh
+ mov P3, #01Eh
+ sjmp main
+
+; Main loop
+; --------------------
+main: shift P1, P3
+ sjmp main
+
+; Program end
+; --------------------
+ end
diff --git a/demo/demo1.bin b/demo/demo1.bin
new file mode 100644
index 0000000..4f74af1
--- /dev/null
+++ b/demo/demo1.bin
Binary files differ
diff --git a/demo/demo1.hex b/demo/demo1.hex
new file mode 100644
index 0000000..f83cb51
--- /dev/null
+++ b/demo/demo1.hex
@@ -0,0 +1,2 @@
+:1E000000800075900F75B01E8000E50F04F50F8590B085B090D3E59023F59080ED04A4
+:00000001FF \ No newline at end of file
diff --git a/demo/demo1.lst b/demo/demo1.lst
new file mode 100644
index 0000000..25d0ef4
--- /dev/null
+++ b/demo/demo1.lst
@@ -0,0 +1,262 @@
+demo1 DEMO 2 36/-4/1907 PAGE 1
+ 1 ; MCU 8051 IDE - Demostration code
+ 2 ; Macro instructions, conditional compilation and constants
+ 3 ; Try tab "Graph" on bottom panel
+ 4
+ 5 ; Press F2 and F6 to run the program (start simulator and animate)
+ 6
+ 7 $TITLE('DEMO 2') ; Set title for code listing
+ 8 $DATE(36/-4/1907) ; Set date for code listing
+ 9
+ 10 ; Constant definitions
+ 11 ; --------------------
+ 000F 12 counter idata 00Fh ; Counter of Px shifts
+ 0064 13 x set 100 ; Some variable
+ 0001 14 inc_dec equ 100 / X ; Flag: Increment/Decrement counter
+ 15
+ 16 cseg at 1FFh ; Code segment starts at 0x1FF
+ 17 something: db 4d ; Reserve 4 bytes in this segment
+ 18
+ 19 ; Macro instructions
+ 20 ; --------------------
+ 21
+ 22 ;; Shift the given registeres
+ 23 shift macro reg0, reg1
+ 24
+ 25 ; Increment / Decrement counter
+ 26 mov A, counter
+ 27 if inc_dec <> 0
+ 28 inc A
+ 29 else
+ 30 dec A
+ 31 endif
+ 33 mov counter, A
+ 34 $list ; <- Enable code listing
+ 35
+ 36 ; Shift
+ 37 mov reg1, reg0
+ 38 mov reg0, reg1
+ 39 setb C
+ 40 mov A, reg0
+ 41 rl A
+ 42 mov reg0, A
+ 43 endm
+ 44
+ 45 ; Program initilization
+ 46 ; --------------------
+0000 75900F 47 org 0h
+0002 75B01E 48 sjmp start
+ 49
+ 50 ; Program start
+ 51 ; --------------------
+0005 8000 52 start: mov P1, #00Fh
+0008 E50F 53 mov P3, #01Eh
+ 54 +1 sjmp main
+ 55 +1
+000A 04 56 +1 mov a, counter
+000C F50F 57 +1 inc a
+000D 8590B0 58 +1 mov counter, a
+ 59 +1
+000F 85B090 60 +1 mov p3, p1
+0012 D3 61 +1 mov p1, p3
+0015 E590 62 +1 setb c
+0016 23 63 +1 mov a, p1
+0018 F590 64 +1 rl a
+0019 80ED 65 +1 mov p1, a
+ 66
+ 67 ; Main loop
+ 68 ; --------------------
+ 69 main: shift P1, P3
+ 70 sjmp main
+ 71
+ 72 ; Program end
+ 73 ; --------------------
+ 74 end
+ASSEMBLY COMPLETE, NO ERRORS FOUND, NO WARNINGS
+
+
+SYMBOL TABLE:
+AC . . . . . . . . . . . . . . . . . B ADDR 00D6H NOT USED
+ACC. . . . . . . . . . . . . . . . . D ADDR 00E0H NOT USED
+ACSR . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+ADCF . . . . . . . . . . . . . . . . D ADDR 00F6H NOT USED
+ADCLK. . . . . . . . . . . . . . . . D ADDR 00F2H NOT USED
+ADCON. . . . . . . . . . . . . . . . D ADDR 00F3H NOT USED
+ADDH . . . . . . . . . . . . . . . . D ADDR 00F5H NOT USED
+ADDL . . . . . . . . . . . . . . . . D ADDR 00F4H NOT USED
+AUXR . . . . . . . . . . . . . . . . D ADDR 008EH NOT USED
+AUXR1. . . . . . . . . . . . . . . . D ADDR 00A2H NOT USED
+B. . . . . . . . . . . . . . . . . . D ADDR 00F0H NOT USED
+BDRCON . . . . . . . . . . . . . . . D ADDR 009BH NOT USED
+BDRCON_1 . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+BRL. . . . . . . . . . . . . . . . . D ADDR 009AH NOT USED
+CCAP0H . . . . . . . . . . . . . . . D ADDR 00FAH NOT USED
+CCAP0L . . . . . . . . . . . . . . . D ADDR 00EAH NOT USED
+CCAP1H . . . . . . . . . . . . . . . D ADDR 00FBH NOT USED
+CCAP1L . . . . . . . . . . . . . . . D ADDR 00EBH NOT USED
+CCAP2H . . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAP3H . . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAP4H . . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL2H. . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAPL2L. . . . . . . . . . . . . . . D ADDR 00ECH NOT USED
+CCAPL3H. . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAPL3L. . . . . . . . . . . . . . . D ADDR 00EDH NOT USED
+CCAPL4H. . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL4L. . . . . . . . . . . . . . . D ADDR 00EEH NOT USED
+CCAPM0 . . . . . . . . . . . . . . . D ADDR 00DAH NOT USED
+CCAPM1 . . . . . . . . . . . . . . . D ADDR 00DBH NOT USED
+CCAPM2 . . . . . . . . . . . . . . . D ADDR 00DCH NOT USED
+CCAPM3 . . . . . . . . . . . . . . . D ADDR 00DDH NOT USED
+CCAPM4 . . . . . . . . . . . . . . . D ADDR 00DEH NOT USED
+CCF0 . . . . . . . . . . . . . . . . B ADDR 00D8H NOT USED
+CCF1 . . . . . . . . . . . . . . . . B ADDR 00D9H NOT USED
+CCF2 . . . . . . . . . . . . . . . . B ADDR 00DAH NOT USED
+CCF3 . . . . . . . . . . . . . . . . B ADDR 00DBH NOT USED
+CCF4 . . . . . . . . . . . . . . . . B ADDR 00DCH NOT USED
+CCON . . . . . . . . . . . . . . . . D ADDR 00D8H NOT USED
+CFINT. . . . . . . . . . . . . . . . C ADDR 0033H NOT USED
+CH . . . . . . . . . . . . . . . . . D ADDR 00F9H NOT USED
+CKCON. . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKCON0 . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKRL . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+CKSEL. . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+CL . . . . . . . . . . . . . . . . . D ADDR 00E9H NOT USED
+CLKREG . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CMOD . . . . . . . . . . . . . . . . D ADDR 00D9H NOT USED
+COUNTER. . . . . . . . . . . . . . . I ADDR 000FH
+CPRL2. . . . . . . . . . . . . . . . B ADDR 00C8H NOT USED
+CR . . . . . . . . . . . . . . . . . B ADDR 00DEH NOT USED
+CT2. . . . . . . . . . . . . . . . . B ADDR 00C9H NOT USED
+CY . . . . . . . . . . . . . . . . . B ADDR 00D7H NOT USED
+DP0H . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DP0L . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+DP1H . . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+DP1L . . . . . . . . . . . . . . . . D ADDR 0084H NOT USED
+DPH. . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DPL. . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+EA . . . . . . . . . . . . . . . . . B ADDR 00AFH NOT USED
+EC . . . . . . . . . . . . . . . . . B ADDR 00AEH NOT USED
+EECON. . . . . . . . . . . . . . . . D ADDR 0096H NOT USED
+ES . . . . . . . . . . . . . . . . . B ADDR 00ACH NOT USED
+ET0. . . . . . . . . . . . . . . . . B ADDR 00A9H NOT USED
+ET1. . . . . . . . . . . . . . . . . B ADDR 00ABH NOT USED
+ET2. . . . . . . . . . . . . . . . . B ADDR 00ADH NOT USED
+EX0. . . . . . . . . . . . . . . . . B ADDR 00A8H NOT USED
+EX1. . . . . . . . . . . . . . . . . B ADDR 00AAH NOT USED
+EXEN2. . . . . . . . . . . . . . . . B ADDR 00CBH NOT USED
+EXF2 . . . . . . . . . . . . . . . . B ADDR 00CEH NOT USED
+EXTI0. . . . . . . . . . . . . . . . C ADDR 0003H NOT USED
+EXTI1. . . . . . . . . . . . . . . . C ADDR 0013H NOT USED
+F0 . . . . . . . . . . . . . . . . . B ADDR 00D5H NOT USED
+FE . . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+IE . . . . . . . . . . . . . . . . . D ADDR 00A8H NOT USED
+IE0. . . . . . . . . . . . . . . . . B ADDR 0089H NOT USED
+IE1. . . . . . . . . . . . . . . . . B ADDR 008BH NOT USED
+INC_DEC. . . . . . . . . . . . . . . N NUMB 0001H NOT USED
+INT0 . . . . . . . . . . . . . . . . B ADDR 00B2H NOT USED
+INT1 . . . . . . . . . . . . . . . . B ADDR 00B3H NOT USED
+IP . . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPH. . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH0 . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH1 . . . . . . . . . . . . . . . . D ADDR 00B3H NOT USED
+IPL0 . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPL1 . . . . . . . . . . . . . . . . D ADDR 00B2H NOT USED
+IT0. . . . . . . . . . . . . . . . . B ADDR 0088H NOT USED
+IT1. . . . . . . . . . . . . . . . . B ADDR 008AH NOT USED
+KBE. . . . . . . . . . . . . . . . . D ADDR 009DH NOT USED
+KBF. . . . . . . . . . . . . . . . . D ADDR 009EH NOT USED
+KBLS . . . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+MAIN . . . . . . . . . . . . . . . . C ADDR 000AH
+OSCCON . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+OV . . . . . . . . . . . . . . . . . B ADDR 00D2H NOT USED
+P. . . . . . . . . . . . . . . . . . B ADDR 00D0H NOT USED
+P0 . . . . . . . . . . . . . . . . . D ADDR 0080H NOT USED
+P1 . . . . . . . . . . . . . . . . . D ADDR 0090H
+P1M1 . . . . . . . . . . . . . . . . D ADDR 00D4H NOT USED
+P1M2 . . . . . . . . . . . . . . . . D ADDR 00E2H NOT USED
+P2 . . . . . . . . . . . . . . . . . D ADDR 00A0H NOT USED
+P3 . . . . . . . . . . . . . . . . . D ADDR 00B0H
+P3M1 . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+P3M2 . . . . . . . . . . . . . . . . D ADDR 00E3H NOT USED
+P4 . . . . . . . . . . . . . . . . . D ADDR 00C0H NOT USED
+P4M1 . . . . . . . . . . . . . . . . D ADDR 00D6H NOT USED
+P4M2 . . . . . . . . . . . . . . . . D ADDR 00E4H NOT USED
+P5 . . . . . . . . . . . . . . . . . D ADDR 00E8H NOT USED
+PC . . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PCON . . . . . . . . . . . . . . . . D ADDR 0087H NOT USED
+PPCL . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PS . . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSL. . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSW. . . . . . . . . . . . . . . . . D ADDR 00D0H NOT USED
+PT0. . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT0L . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT1. . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT1L . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT2. . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PT2L . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PX0. . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX0L . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX1. . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+PX1L . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+RB8. . . . . . . . . . . . . . . . . B ADDR 009AH NOT USED
+RCAP2H . . . . . . . . . . . . . . . D ADDR 00CBH NOT USED
+RCAP2L . . . . . . . . . . . . . . . D ADDR 00CAH NOT USED
+RCLK . . . . . . . . . . . . . . . . B ADDR 00CDH NOT USED
+RD . . . . . . . . . . . . . . . . . B ADDR 00B7H NOT USED
+REN. . . . . . . . . . . . . . . . . B ADDR 009CH NOT USED
+RESET. . . . . . . . . . . . . . . . C ADDR 0000H NOT USED
+RI . . . . . . . . . . . . . . . . . B ADDR 0098H NOT USED
+RS0. . . . . . . . . . . . . . . . . B ADDR 00D3H NOT USED
+RS1. . . . . . . . . . . . . . . . . B ADDR 00D4H NOT USED
+RXD. . . . . . . . . . . . . . . . . B ADDR 00B0H NOT USED
+SADDR. . . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_0. . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_1. . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SADEN. . . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_0. . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_1. . . . . . . . . . . . . . . D ADDR 00BAH NOT USED
+SBUF . . . . . . . . . . . . . . . . D ADDR 0099H NOT USED
+SCON . . . . . . . . . . . . . . . . D ADDR 0098H NOT USED
+SINT . . . . . . . . . . . . . . . . C ADDR 0023H NOT USED
+SM0. . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+SM1. . . . . . . . . . . . . . . . . B ADDR 009EH NOT USED
+SM2. . . . . . . . . . . . . . . . . B ADDR 009DH NOT USED
+SOMETHING. . . . . . . . . . . . . . C ADDR 001DH NOT USED
+SP . . . . . . . . . . . . . . . . . D ADDR 0081H NOT USED
+SPCON. . . . . . . . . . . . . . . . D ADDR 00C3H NOT USED
+SPCR . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+SPDAT. . . . . . . . . . . . . . . . D ADDR 00C5H NOT USED
+SPDR . . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+SPSR . . . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SPSTA. . . . . . . . . . . . . . . . D ADDR 00C4H NOT USED
+START. . . . . . . . . . . . . . . . C ADDR 0002H
+T0 . . . . . . . . . . . . . . . . . B ADDR 00B4H NOT USED
+T1 . . . . . . . . . . . . . . . . . B ADDR 00B5H NOT USED
+T2CON. . . . . . . . . . . . . . . . D ADDR 00C8H NOT USED
+T2MOD. . . . . . . . . . . . . . . . D ADDR 00C9H NOT USED
+TB8. . . . . . . . . . . . . . . . . B ADDR 009BH NOT USED
+TCLK . . . . . . . . . . . . . . . . B ADDR 00CCH NOT USED
+TCON . . . . . . . . . . . . . . . . D ADDR 0088H NOT USED
+TF0. . . . . . . . . . . . . . . . . B ADDR 008DH NOT USED
+TF1. . . . . . . . . . . . . . . . . B ADDR 008FH NOT USED
+TF2. . . . . . . . . . . . . . . . . B ADDR 00CFH NOT USED
+TH0. . . . . . . . . . . . . . . . . D ADDR 008CH NOT USED
+TH1. . . . . . . . . . . . . . . . . D ADDR 008DH NOT USED
+TH2. . . . . . . . . . . . . . . . . D ADDR 00CDH NOT USED
+TI . . . . . . . . . . . . . . . . . B ADDR 0099H NOT USED
+TIMER0 . . . . . . . . . . . . . . . C ADDR 000BH NOT USED
+TIMER1 . . . . . . . . . . . . . . . C ADDR 001BH NOT USED
+TIMER2 . . . . . . . . . . . . . . . C ADDR 002BH NOT USED
+TL0. . . . . . . . . . . . . . . . . D ADDR 008AH NOT USED
+TL1. . . . . . . . . . . . . . . . . D ADDR 008BH NOT USED
+TL2. . . . . . . . . . . . . . . . . D ADDR 00CCH NOT USED
+TMOD . . . . . . . . . . . . . . . . D ADDR 0089H NOT USED
+TR0. . . . . . . . . . . . . . . . . B ADDR 008CH NOT USED
+TR1. . . . . . . . . . . . . . . . . B ADDR 008EH NOT USED
+TR2. . . . . . . . . . . . . . . . . B ADDR 00CAH NOT USED
+TXD. . . . . . . . . . . . . . . . . B ADDR 00B1H NOT USED
+WDTCON . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTPRG . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTRST . . . . . . . . . . . . . . . D ADDR 00A6H NOT USED
+WR . . . . . . . . . . . . . . . . . B ADDR 00B6H NOT USED
+X. . . . . . . . . . . . . . . . . . NUMB 0064H NOT USED REDEFINABLE \ No newline at end of file
diff --git a/demo/demo1.sim b/demo/demo1.sim
new file mode 100644
index 0000000..1d235f3
--- /dev/null
+++ b/demo/demo1.sim
@@ -0,0 +1,16 @@
+C4FD5C3C2DF98DDEE6FE5ACA0FD745A8 12/21/07 demo1.asm
+48 0 128 0
+52 2 117 144 15
+53 5 117 176 30
+54 8 128 0
+58 10 229 15
+58 12 4
+58 13 245 15
+58 15 133 176 144
+58 18 133 144 176
+58 21 211
+58 22 229 144
+58 24 35
+58 25 245 144
+59 27 128 237
+17 511 4 \ No newline at end of file
diff --git a/demo/demo2.adf b/demo/demo2.adf
new file mode 100644
index 0000000..f542c32
--- /dev/null
+++ b/demo/demo2.adf
@@ -0,0 +1,50 @@
+# Assembler debug file for MCU 8051 IDE v1.3.1
+# Used assembler: MCU 8051 IDE
+# Date: 10/27/2009
+016FCF566042EC66EE9118BAFA4D4A35 "demo2.asm"
+0 47 0 128 28
+0 50 11 128 0
+0 56 13 127 26
+0 57 15 126 0
+0 58 17 238
+0 58 18 144 0 47
+0 58 21 147
+0 58 22 141 130
+0 58 24 240
+0 58 25 13
+0 58 26 14
+0 59 27 223 244
+0 60 29 50
+0 65 30 125 0
+0 66 32 117 168 255
+0 67 35 117 138 255
+0 68 38 117 137 3
+0 69 41 210 140
+0 70 43 128 0
+0 74 45 128 254
+0 28 47 87
+0 28 48 101
+0 28 49 108
+0 28 50 99
+0 28 51 111
+0 28 52 109
+0 28 53 101
+0 28 54 32
+0 28 55 105
+0 28 56 110
+0 28 57 32
+0 28 58 77
+0 28 59 67
+0 28 60 85
+0 28 61 32
+0 28 62 56
+0 28 63 48
+0 28 64 53
+0 28 65 49
+0 28 66 32
+0 28 67 73
+0 28 68 68
+0 28 69 69
+0 28 70 32
+0 28 71 33
+0 28 72 32 \ No newline at end of file
diff --git a/demo/demo2.asm b/demo/demo2.asm
new file mode 100644
index 0000000..d3f595d
--- /dev/null
+++ b/demo/demo2.asm
@@ -0,0 +1,78 @@
+; MCU 8051 IDE - Demostration code
+; Interrupts, hexadecimal editor and code validator
+; ------------------------------------------------------
+; THIS REQUIRES ANOTHER MCU THAN AT89C2051 BECAUSE
+; AT89C2051 HAS NO XDATA MENORY. CLICK ON
+; [Main menu] -> [Project] -> [Edit project] AND SELECT
+; FOR INSTANCE AT89C51 AND SET XDATA TO SOME VALUE
+; ------------------------------------------------------
+
+; * Click on [Main menu] -> [Simulator] -> [Show XDATA memory]
+; * Press F2 and F6 (start simulator and animate)
+
+
+
+; Code with syntax errors
+ nolist ; Disable code listing
+if 0
+ mov A, #55d, B ; too many operands
+ inc 0FFh,, 04x4h ; invalid operands
+ db (4 *** 5) ; invalid expression
+label?: mul B ; ivalid label and invalid operand
+endif
+ list ; Enable code listing
+
+; Constants
+; --------------------
+ cseg at 0D0h
+string: db 'Welcome in MCU 8051 IDE ! '
+
+string_legth equ 26d
+
+; Macro instructions
+; --------------------
+write_to_xdata macro str, code_ptr, xdata_ptr
+ mov A, code_ptr
+ mov DPTR, #str
+ movc A, @A+DPTR
+ mov DPL, xdata_ptr
+ movx @DPTR, A
+ inc xdata_ptr
+ inc code_ptr
+endm
+
+; Program initilization
+; --------------------
+ org 0h ; Reset vector
+ sjmp start
+
+ org 0Bh ; Interrupt vector - T0
+ sjmp T0_int
+
+; Subprograms
+; --------------------
+
+;; Hadnle interrupt from TF0
+T0_int: mov R7, #string_legth
+ mov R6, #0h
+loop: write_to_xdata string, R6, R5
+ djnz R7, loop
+ reti
+
+; Program start
+; --------------------
+start: ; Start timer 0 in mode 2
+ mov R5, #0h
+ mov IE, #0FFh
+ mov TL0, #255d
+ mov TMOD, #03h
+ setb TR0
+ sjmp main
+
+; Main loop
+; --------------------
+main: sjmp $ ; Inifinite loop
+
+; Program end
+; --------------------
+ end
diff --git a/demo/demo2.bin b/demo/demo2.bin
new file mode 100644
index 0000000..031c85b
--- /dev/null
+++ b/demo/demo2.bin
Binary files differ
diff --git a/demo/demo2.hex b/demo/demo2.hex
new file mode 100644
index 0000000..1139f92
--- /dev/null
+++ b/demo/demo2.hex
@@ -0,0 +1,3 @@
+:02000000801C62
+:3E000B0080007F1A7E00EE90002F938D82F00D0EDFF4327D0075A8FF758AFF758903D28C800080FE57656C636F6D6520696E204D4355203830353120494445202120C4
+:00000001FF \ No newline at end of file
diff --git a/demo/demo2.lst b/demo/demo2.lst
new file mode 100644
index 0000000..4ce2673
--- /dev/null
+++ b/demo/demo2.lst
@@ -0,0 +1,270 @@
+demo2 PAGE 1
+0048 80FE 1 ; MCU 8051 IDE - Demostration code
+ 2 ; Interrupts, hexadecimal editor and code validator
+ 3 ; ------------------------------------------------------
+ 4 ; THIS REQUIRES ANOTHER MCU THAN AT89C2051 BECAUSE
+ 5 ; AT89C2051 HAS NO XDATA MENORY. CLICK ON
+ 6 ; [Main menu] -> [Project] -> [Edit project] AND SELECT
+ 7 ; FOR INSTANCE AT89C51 AND SET XDATA TO SOME VALUE
+ 8 ; ------------------------------------------------------
+ 9
+ 10 ; * Click on [Main menu] -> [Simulator] -> [Show XDATA memory]
+ 11 ; * Press F2 and F6 (start simulator and animate)
+ 12
+ 13
+ 14
+ 15 ; Code with syntax errors
+ 16 nolist ; Disable code listing
+ 23 list ; Enable code listing
+ 24
+ 25 ; Constants
+ 26 ; --------------------
+ 27 cseg at 0D0h
+ 28 string: db 'Welcome in MCU 8051 IDE ! '
+ 29
+ 001A 30 string_legth equ 26d
+ 31
+ 32 ; Macro instructions
+ 33 ; --------------------
+ 34 write_to_xdata macro str, code_ptr, xdata_ptr
+ 35 mov A, code_ptr
+ 36 mov DPTR, #str
+ 37 movc A, @A+DPTR
+ 38 mov DPL, xdata_ptr
+ 39 movx @DPTR, A
+ 40 inc xdata_ptr
+ 41 inc code_ptr
+ 42 endm
+ 43
+ 44 ; Program initilization
+ 45 ; --------------------
+0000 801C 46 org 0h ; Reset vector
+ 47 sjmp start
+ 48
+ 49 org 0Bh ; Interrupt vector - T0
+ 50 sjmp T0_int
+ 51
+ 52 ; Subprograms
+ 53 ; --------------------
+ 54
+ 55 ;; Hadnle interrupt from TF0
+ 56 T0_int: mov R7, #string_legth
+ 57 mov R6, #0h
+ 58 +1 loop: write_to_xdata string, R6, R5
+ 59 +1 mov a, r6
+ 60 +1 mov dptr, #string
+ 61 +1 movc a, @a+dptr
+ 62 +1 mov dpl, r5
+ 63 +1 movx @dptr, a
+ 64 +1 inc r5
+ 65 +1 inc r6
+ 66 djnz R7, loop
+ 67 reti
+ 68
+ 69 ; Program start
+ 70 ; --------------------
+ 71 start: ; Start timer 0 in mode 2
+ 72 mov R5, #0h
+ 73 mov IE, #0FFh
+ 74 mov TL0, #255d
+ 75 mov TMOD, #03h
+ 76 setb TR0
+ 77 sjmp main
+ 78
+ 79 ; Main loop
+ 80 ; --------------------
+ 81 main: sjmp $ ; Inifinite loop
+ 82
+ 83 ; Program end
+ 84 ; --------------------
+ 85 end
+ASSEMBLY COMPLETE, NO ERRORS FOUND, NO WARNINGS
+
+
+SYMBOL TABLE:
+??MCU_8051_IDE . . . . . . . . . . . N NUMB 8051H NOT USED
+??VERSION. . . . . . . . . . . . . . N NUMB 0131H NOT USED
+AC . . . . . . . . . . . . . . . . . B ADDR 00D6H NOT USED
+ACC. . . . . . . . . . . . . . . . . D ADDR 00E0H NOT USED
+ACSR . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+ADCF . . . . . . . . . . . . . . . . D ADDR 00F6H NOT USED
+ADCLK. . . . . . . . . . . . . . . . D ADDR 00F2H NOT USED
+ADCON. . . . . . . . . . . . . . . . D ADDR 00F3H NOT USED
+ADDH . . . . . . . . . . . . . . . . D ADDR 00F5H NOT USED
+ADDL . . . . . . . . . . . . . . . . D ADDR 00F4H NOT USED
+AUXR . . . . . . . . . . . . . . . . D ADDR 008EH NOT USED
+AUXR1. . . . . . . . . . . . . . . . D ADDR 00A2H NOT USED
+B. . . . . . . . . . . . . . . . . . D ADDR 00F0H NOT USED
+BDRCON . . . . . . . . . . . . . . . D ADDR 009BH NOT USED
+BDRCON_1 . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+BRL. . . . . . . . . . . . . . . . . D ADDR 009AH NOT USED
+CCAP0H . . . . . . . . . . . . . . . D ADDR 00FAH NOT USED
+CCAP0L . . . . . . . . . . . . . . . D ADDR 00EAH NOT USED
+CCAP1H . . . . . . . . . . . . . . . D ADDR 00FBH NOT USED
+CCAP1L . . . . . . . . . . . . . . . D ADDR 00EBH NOT USED
+CCAP2H . . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAP3H . . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAP4H . . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL2H. . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAPL2L. . . . . . . . . . . . . . . D ADDR 00ECH NOT USED
+CCAPL3H. . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAPL3L. . . . . . . . . . . . . . . D ADDR 00EDH NOT USED
+CCAPL4H. . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL4L. . . . . . . . . . . . . . . D ADDR 00EEH NOT USED
+CCAPM0 . . . . . . . . . . . . . . . D ADDR 00DAH NOT USED
+CCAPM1 . . . . . . . . . . . . . . . D ADDR 00DBH NOT USED
+CCAPM2 . . . . . . . . . . . . . . . D ADDR 00DCH NOT USED
+CCAPM3 . . . . . . . . . . . . . . . D ADDR 00DDH NOT USED
+CCAPM4 . . . . . . . . . . . . . . . D ADDR 00DEH NOT USED
+CCF0 . . . . . . . . . . . . . . . . B ADDR 00D8H NOT USED
+CCF1 . . . . . . . . . . . . . . . . B ADDR 00D9H NOT USED
+CCF2 . . . . . . . . . . . . . . . . B ADDR 00DAH NOT USED
+CCF3 . . . . . . . . . . . . . . . . B ADDR 00DBH NOT USED
+CCF4 . . . . . . . . . . . . . . . . B ADDR 00DCH NOT USED
+CCON . . . . . . . . . . . . . . . . D ADDR 00D8H NOT USED
+CFINT. . . . . . . . . . . . . . . . C ADDR 0033H NOT USED
+CH . . . . . . . . . . . . . . . . . D ADDR 00F9H NOT USED
+CKCON. . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKCON0 . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKRL . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+CKSEL. . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+CL . . . . . . . . . . . . . . . . . D ADDR 00E9H NOT USED
+CLKREG . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CMOD . . . . . . . . . . . . . . . . D ADDR 00D9H NOT USED
+CPRL2. . . . . . . . . . . . . . . . B ADDR 00C8H NOT USED
+CR . . . . . . . . . . . . . . . . . B ADDR 00DEH NOT USED
+CT2. . . . . . . . . . . . . . . . . B ADDR 00C9H NOT USED
+CY . . . . . . . . . . . . . . . . . B ADDR 00D7H NOT USED
+DP0H . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DP0L . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+DP1H . . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+DP1L . . . . . . . . . . . . . . . . D ADDR 0084H NOT USED
+DPH. . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DPL. . . . . . . . . . . . . . . . . D ADDR 0082H
+EA . . . . . . . . . . . . . . . . . B ADDR 00AFH NOT USED
+EC . . . . . . . . . . . . . . . . . B ADDR 00AEH NOT USED
+EECON. . . . . . . . . . . . . . . . D ADDR 0096H NOT USED
+ES . . . . . . . . . . . . . . . . . B ADDR 00ACH NOT USED
+ET0. . . . . . . . . . . . . . . . . B ADDR 00A9H NOT USED
+ET1. . . . . . . . . . . . . . . . . B ADDR 00ABH NOT USED
+ET2. . . . . . . . . . . . . . . . . B ADDR 00ADH NOT USED
+EX0. . . . . . . . . . . . . . . . . B ADDR 00A8H NOT USED
+EX1. . . . . . . . . . . . . . . . . B ADDR 00AAH NOT USED
+EXEN2. . . . . . . . . . . . . . . . B ADDR 00CBH NOT USED
+EXF2 . . . . . . . . . . . . . . . . B ADDR 00CEH NOT USED
+EXTI0. . . . . . . . . . . . . . . . C ADDR 0003H NOT USED
+EXTI1. . . . . . . . . . . . . . . . C ADDR 0013H NOT USED
+F0 . . . . . . . . . . . . . . . . . B ADDR 00D5H NOT USED
+FE . . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+IE . . . . . . . . . . . . . . . . . D ADDR 00A8H
+IE0. . . . . . . . . . . . . . . . . B ADDR 0089H NOT USED
+IE1. . . . . . . . . . . . . . . . . B ADDR 008BH NOT USED
+INT0 . . . . . . . . . . . . . . . . B ADDR 00B2H NOT USED
+INT1 . . . . . . . . . . . . . . . . B ADDR 00B3H NOT USED
+IP . . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPH. . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH0 . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH1 . . . . . . . . . . . . . . . . D ADDR 00B3H NOT USED
+IPL0 . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPL1 . . . . . . . . . . . . . . . . D ADDR 00B2H NOT USED
+IT0. . . . . . . . . . . . . . . . . B ADDR 0088H NOT USED
+IT1. . . . . . . . . . . . . . . . . B ADDR 008AH NOT USED
+KBE. . . . . . . . . . . . . . . . . D ADDR 009DH NOT USED
+KBF. . . . . . . . . . . . . . . . . D ADDR 009EH NOT USED
+KBLS . . . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+LOOP . . . . . . . . . . . . . . . . C ADDR 0011H
+MAIN . . . . . . . . . . . . . . . . C ADDR 002DH
+OSCCON . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+OV . . . . . . . . . . . . . . . . . B ADDR 00D2H NOT USED
+P. . . . . . . . . . . . . . . . . . B ADDR 00D0H NOT USED
+P0 . . . . . . . . . . . . . . . . . D ADDR 0080H NOT USED
+P1 . . . . . . . . . . . . . . . . . D ADDR 0090H NOT USED
+P1M1 . . . . . . . . . . . . . . . . D ADDR 00D4H NOT USED
+P1M2 . . . . . . . . . . . . . . . . D ADDR 00E2H NOT USED
+P2 . . . . . . . . . . . . . . . . . D ADDR 00A0H NOT USED
+P3 . . . . . . . . . . . . . . . . . D ADDR 00B0H NOT USED
+P3M1 . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+P3M2 . . . . . . . . . . . . . . . . D ADDR 00E3H NOT USED
+P4 . . . . . . . . . . . . . . . . . D ADDR 00C0H NOT USED
+P4M1 . . . . . . . . . . . . . . . . D ADDR 00D6H NOT USED
+P4M2 . . . . . . . . . . . . . . . . D ADDR 00E4H NOT USED
+P5 . . . . . . . . . . . . . . . . . D ADDR 00E8H NOT USED
+PC . . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PCON . . . . . . . . . . . . . . . . D ADDR 0087H NOT USED
+PPCL . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PS . . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSL. . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSW. . . . . . . . . . . . . . . . . D ADDR 00D0H NOT USED
+PT0. . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT0L . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT1. . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT1L . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT2. . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PT2L . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PX0. . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX0L . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX1. . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+PX1L . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+RB8. . . . . . . . . . . . . . . . . B ADDR 009AH NOT USED
+RCAP2H . . . . . . . . . . . . . . . D ADDR 00CBH NOT USED
+RCAP2L . . . . . . . . . . . . . . . D ADDR 00CAH NOT USED
+RCLK . . . . . . . . . . . . . . . . B ADDR 00CDH NOT USED
+RD . . . . . . . . . . . . . . . . . B ADDR 00B7H NOT USED
+REN. . . . . . . . . . . . . . . . . B ADDR 009CH NOT USED
+RESET. . . . . . . . . . . . . . . . C ADDR 0000H NOT USED
+RI . . . . . . . . . . . . . . . . . B ADDR 0098H NOT USED
+RS0. . . . . . . . . . . . . . . . . B ADDR 00D3H NOT USED
+RS1. . . . . . . . . . . . . . . . . B ADDR 00D4H NOT USED
+RXD. . . . . . . . . . . . . . . . . B ADDR 00B0H NOT USED
+SADDR. . . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_0. . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_1. . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SADEN. . . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_0. . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_1. . . . . . . . . . . . . . . D ADDR 00BAH NOT USED
+SBUF . . . . . . . . . . . . . . . . D ADDR 0099H NOT USED
+SCON . . . . . . . . . . . . . . . . D ADDR 0098H NOT USED
+SINT . . . . . . . . . . . . . . . . C ADDR 0023H NOT USED
+SM0. . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+SM1. . . . . . . . . . . . . . . . . B ADDR 009EH NOT USED
+SM2. . . . . . . . . . . . . . . . . B ADDR 009DH NOT USED
+SP . . . . . . . . . . . . . . . . . D ADDR 0081H NOT USED
+SPCON. . . . . . . . . . . . . . . . D ADDR 00C3H NOT USED
+SPCR . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+SPDAT. . . . . . . . . . . . . . . . D ADDR 00C5H NOT USED
+SPDR . . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+SPSR . . . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SPSTA. . . . . . . . . . . . . . . . D ADDR 00C4H NOT USED
+START. . . . . . . . . . . . . . . . C ADDR 001EH
+STRING . . . . . . . . . . . . . . . C ADDR 002FH
+STRING_LEGTH . . . . . . . . . . . . N NUMB 001AH
+T0 . . . . . . . . . . . . . . . . . B ADDR 00B4H NOT USED
+T0_INT . . . . . . . . . . . . . . . C ADDR 000DH
+T1 . . . . . . . . . . . . . . . . . B ADDR 00B5H NOT USED
+T2CON. . . . . . . . . . . . . . . . D ADDR 00C8H NOT USED
+T2MOD. . . . . . . . . . . . . . . . D ADDR 00C9H NOT USED
+TB8. . . . . . . . . . . . . . . . . B ADDR 009BH NOT USED
+TCLK . . . . . . . . . . . . . . . . B ADDR 00CCH NOT USED
+TCON . . . . . . . . . . . . . . . . D ADDR 0088H NOT USED
+TF0. . . . . . . . . . . . . . . . . B ADDR 008DH NOT USED
+TF1. . . . . . . . . . . . . . . . . B ADDR 008FH NOT USED
+TF2. . . . . . . . . . . . . . . . . B ADDR 00CFH NOT USED
+TH0. . . . . . . . . . . . . . . . . D ADDR 008CH NOT USED
+TH1. . . . . . . . . . . . . . . . . D ADDR 008DH NOT USED
+TH2. . . . . . . . . . . . . . . . . D ADDR 00CDH NOT USED
+TI . . . . . . . . . . . . . . . . . B ADDR 0099H NOT USED
+TIMER0 . . . . . . . . . . . . . . . C ADDR 000BH NOT USED
+TIMER1 . . . . . . . . . . . . . . . C ADDR 001BH NOT USED
+TIMER2 . . . . . . . . . . . . . . . C ADDR 002BH NOT USED
+TL0. . . . . . . . . . . . . . . . . D ADDR 008AH
+TL1. . . . . . . . . . . . . . . . . D ADDR 008BH NOT USED
+TL2. . . . . . . . . . . . . . . . . D ADDR 00CCH NOT USED
+TMOD . . . . . . . . . . . . . . . . D ADDR 0089H
+TR0. . . . . . . . . . . . . . . . . B ADDR 008CH
+TR1. . . . . . . . . . . . . . . . . B ADDR 008EH NOT USED
+TR2. . . . . . . . . . . . . . . . . B ADDR 00CAH NOT USED
+TXD. . . . . . . . . . . . . . . . . B ADDR 00B1H NOT USED
+WDTCON . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTPRG . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTRST . . . . . . . . . . . . . . . D ADDR 00A6H NOT USED
+WR . . . . . . . . . . . . . . . . . B ADDR 00B6H NOT USED \ No newline at end of file
diff --git a/demo/demo2.sim b/demo/demo2.sim
new file mode 100644
index 0000000..4230f05
--- /dev/null
+++ b/demo/demo2.sim
@@ -0,0 +1,47 @@
+3E5C5EAE0BA81D024AAE08DD4B210650 12/21/07 demo2.asm
+47 0 128 28
+50 11 128 0
+56 13 127 26
+57 15 126 0
+58 17 238
+58 18 144 0 208
+58 21 147
+58 22 141 130
+58 24 240
+58 25 13
+58 26 14
+59 27 223 244
+60 29 50
+65 30 125 0
+66 32 117 168 255
+67 35 117 138 255
+68 38 117 137 3
+69 41 210 140
+70 43 128 0
+74 45 128 254
+28 208 87
+28 209 101
+28 210 108
+28 211 99
+28 212 111
+28 213 109
+28 214 101
+28 215 32
+28 216 105
+28 217 110
+28 218 32
+28 219 77
+28 220 67
+28 221 85
+28 222 32
+28 223 56
+28 224 48
+28 225 53
+28 226 49
+28 227 32
+28 228 73
+28 229 68
+28 230 69
+28 231 32
+28 232 33
+28 233 32 \ No newline at end of file
diff --git a/demo/demo3.adf b/demo/demo3.adf
new file mode 100644
index 0000000..64c2b62
--- /dev/null
+++ b/demo/demo3.adf
@@ -0,0 +1,9 @@
+# Assembler debug file for MCU 8051 IDE v1.1
+# Used assembler: MCU 8051 IDE
+# Date: 03/02/09
+6180D365C7F535CABD42C3E78A0798B9 "demo3.asm"
+0 67 0 128 254
+0 35 2 51
+0 35 3 52
+0 36 4 51
+0 36 5 52 \ No newline at end of file
diff --git a/demo/demo3.asm b/demo/demo3.asm
new file mode 100644
index 0000000..d93d260
--- /dev/null
+++ b/demo/demo3.asm
@@ -0,0 +1,72 @@
+; MCU 8051 IDE - Demostration code
+; Compiler directives
+
+
+$DATE(32/13/1907)   ; Places date in page header
+; $EJECT ; Places a form feed in listing
+; $INCLUDE(file.asm) ; Inserts file in source program
+; $LIST ; Allows listing to be output
+; $NOLIST ; Stops outputting the listing
+; $NOMOD ; No predefined symbols used
+$OBJECT(file.hex) ; Places object output in file
+; $NOOBJECT ; No object file is generated
+$PAGING ; Break output listing into pages
+; $NOPAGING ; Print listing w/o page breaks
+$PAGELENGTH(10) ; No. of lines on a listing page
+$PAGEWIDTH(20)    ; No. of columns on a listing page
+$PRINT(file.lst) ; Places listing output in file
+; $NOPRINT ; Listing will not be output
+; $SYMBOLS ; Append symbol table to listing
+; $NOSYMBOLS ; Symbol table will not be output
+$TITLE('demo - 3') ; Places string in page header
+
+
+;; Summary of Cross Assembler Directives
+;; -------------------------------------
+
+a EQU 54d ; Define symbol
+b0 DATA a / 2 ; Define internal memory symbol
+c IDATA (b0*2-5) ; Define indirectly addressed internal memory
+d BIT 070Q ; Define internal bit memory symbol
+e CODE 0FFA5h ; Define program memory symbol
+var SET (A * 44) MOD 9 - 14 ; Variable defined by an expression
+
+ CSEG at 20h ; Select program memory space
+x: DB '34' ; Store byte values in program memory
+y: DW 3334h ; Store word values in program memory
+
+ DSEG at 5d ; Select internal memory data space
+m: DS 1 ; Reserve bytes of data memory
+
+ xseg ; Select external memory data space
+n: DS 1 ; Reserve bytes of data memory
+
+ ISEG ; Select indirectly addressed internal memory space
+o: DS 1 ; Reserve bytes of data memory
+
+ NOLIST ; Disable code listing
+ BSEG ; Select bit addressable memory space
+r: DBIT 4 ; Reserve bits of bit memory
+ LIST ; Enable code listing
+
+
+mc macro label ; Define macro instruction
+ IF 2 <> 2 OR 1 = 4
+ EXITM ; Exit macro
+ ENDIF
+ sjmp label
+endm ; End of definition
+
+main: ORG 0 ; Set segment location counter
+ IF 0 ; Begin conditional assembly block
+ USING 2 ; Select register bank (define AR0..7)
+ ELSE ; Alternative conditional assembly block
+ USING 2 ; Select register bank (define AR0..7)
+ ENDIF ; End conditional assembly block
+
+ mc main ; Macro instuction
+
+ END ; End of assembly language source file
+
+
+; This is a very long line, try to avoid them. This is a very long line, try to avoid them. This is a very long line, try to avoid them. This is a very long line, try to avoid them. This is a very long line, try to avoid them. This is a very long line, try to avoid them. This is a very long line, try to avoid them.This is a very long line, try to avoid them. This is a very long line, try to avoid them.This is a very long line, try to avoid them. This is a very long line, try to avoid them. This is a very long line, try to avoid them. This is a very long line, try to avoid them.
diff --git a/demo/demo3.bin b/demo/demo3.bin
new file mode 100644
index 0000000..45d3d20
--- /dev/null
+++ b/demo/demo3.bin
@@ -0,0 +1 @@
+3 \ No newline at end of file
diff --git a/demo/demo3.sim b/demo/demo3.sim
new file mode 100644
index 0000000..ef0cd1f
--- /dev/null
+++ b/demo/demo3.sim
@@ -0,0 +1,6 @@
+6180D365C7F535CABD42C3E78A0798B9 12/21/07 demo3.asm
+67 0 128 254
+35 32 51
+35 33 52
+36 34 51
+36 35 52 \ No newline at end of file
diff --git a/demo/demo4.adf b/demo/demo4.adf
new file mode 100644
index 0000000..fb6a934
--- /dev/null
+++ b/demo/demo4.adf
@@ -0,0 +1,45 @@
+# Assembler Debug File created by MCU 8051 IDE v1.0.5
+# Used assembler: MCU 8051 IDE
+# Date: 04/30/08
+7E1BFADD8BDB7A40D6B8CA5161E3113A "demo4.asm"
+0 27 0 128 64
+0 30 3 210 152
+0 30 5 210 153
+0 30 7 17 58
+0 30 9 50
+0 33 11 210 152
+0 33 13 210 153
+0 33 15 17 58
+0 33 17 50
+0 36 19 210 152
+0 36 21 210 153
+0 36 23 17 58
+0 36 25 50
+0 39 27 210 152
+0 39 29 210 153
+0 39 31 17 58
+0 39 33 50
+0 42 35 210 152
+0 42 37 210 153
+0 42 39 17 58
+0 42 41 50
+0 45 43 210 152
+0 45 45 210 153
+0 45 47 17 58
+0 45 49 50
+0 48 51 210 152
+0 48 53 210 153
+0 48 55 17 58
+0 48 57 50
+0 53 58 127 16
+0 54 60 17 63
+0 55 62 34
+0 58 63 223 254
+0 59 65 34
+0 66 66 210 141
+0 67 68 210 143
+0 68 70 210 137
+0 69 72 210 139
+0 72 74 117 168 255
+0 73 77 210 188
+0 76 79 128 254 \ No newline at end of file
diff --git a/demo/demo4.asm b/demo/demo4.asm
new file mode 100644
index 0000000..662c740
--- /dev/null
+++ b/demo/demo4.asm
@@ -0,0 +1,81 @@
+; MCU 8051 IDE - Demostration code
+; Interrupt monitor and list of active subprograms
+
+; 1) Press Ctrl+0 to show tab "List of subprograms" on righ panel
+; 2) Run interrupt monitor
+; (Main menu: Simulator -> Interrupt monitor)
+; 3) Press F2 to start simulator and F6 to run animation mode
+
+; Macro instructions
+; ------------------
+
+;; Handle interrupt
+intr macro
+ ; Set UART interrupt flags
+ setb RI
+ setb TI
+
+ ; Wait a while and return from interrupt
+ acall wait
+ reti
+endm
+
+
+; Interrupt vectors
+; -----------------
+ org 00h ; Reset
+ ajmp start
+
+ org 03h ; External 0
+ intr
+
+ org 0Bh ; Timer 0
+ intr
+
+ org 13h ; External 0
+ intr
+
+ org 1Bh ; Timer 1
+ intr
+
+ org 23h ; UART and SPI
+ intr
+
+ org 2Bh ; Timer 2
+ intr
+
+ org 33h ; Analog comparator
+ intr
+
+; Subprograms
+; -----------------
+wait: ; Wait for 24 cycles
+ mov R7, #10h
+ acall wait_aux
+ ret
+
+wait_aux:
+ djnz R7, $
+ ret
+
+
+; Program start
+; -----------------
+start:
+ ; Set some interrupt bits
+ setb TF0
+ setb TF1
+ setb IE0
+ setb IE1
+
+ ; Enable all interrupts and set priorities
+ mov IE, #0FFh
+ setb PS
+
+ ; Infinite loop
+ sjmp $
+
+
+; End of code
+; -----------------
+ end
diff --git a/demo/demo4.bin b/demo/demo4.bin
new file mode 100644
index 0000000..413b6f7
--- /dev/null
+++ b/demo/demo4.bin
Binary files differ
diff --git a/demo/demo4.hex b/demo/demo4.hex
new file mode 100644
index 0000000..20def10
--- /dev/null
+++ b/demo/demo4.hex
@@ -0,0 +1,9 @@
+:0200000080403E
+:07000300D298D299113A32A4
+:07000B00D298D299113A329C
+:07001300D298D299113A3294
+:07001B00D298D299113A328C
+:07002300D298D299113A3284
+:07002B00D298D299113A327C
+:1E003300D298D299113A327F10113F22DFFE22D28DD28FD289D28B75A8FFD2BC80FEBD
+:00000001FF \ No newline at end of file
diff --git a/demo/demo4.lst b/demo/demo4.lst
new file mode 100644
index 0000000..867750e
--- /dev/null
+++ b/demo/demo4.lst
@@ -0,0 +1,228 @@
+demo4 PAGE 1
+ 1 ; MCU 8051 IDE - Demostration code
+ 2 ; Interrupt monitor and list of active subprograms
+ 3
+ 4 ; 1) Press Ctrl+0 to show tab "List of subprograms" on righ panel
+ 5 ; 2) Run interrupt monitor
+ 6 ; (Main menu: Simulator -> Interrupt monitor)
+ 7 ; 3) Press F2 to start simulator and F6 to run animation mode
+ 8
+ 9 ; Macro instructions
+ 10 ; ------------------
+ 11
+ 12 ;; Handle interrupt
+ 13 intr macro
+ 14 ; Set UART interrupt flags
+ 15 setb RI
+ 16 setb TI
+ 17
+ 18 ; Wait a while and return from interrupt
+ 19 acall wait
+ 20 reti
+ 21 endm
+ 22
+ 23
+ 24 ; Interrupt vectors
+ 25 ; -----------------
+ 26 org 00h ; Reset
+0000 D298 27 ajmp start
+ 28
+ 29 +1 org 03h ; External 0
+ 30 +2
+ 31 +3
+ 32 +4
+ 33 +5
+ 34 +6
+ 35 +7
+ 36 +7
+ 37 +7 setb RI
+000B 113F 38 +7 setb TI
+000D 22 39 +7
+ 40 +7 acall wait
+000F DFFE 41 +7 reti
+ 42 +6 setb RI
+0011 22 43 +6 setb TI
+ 44 +6
+ 45 +6 acall wait
+0013 D28F 46 +6 reti
+ 47 +5 setb RI
+0015 D289 48 +5 setb TI
+ 49 +5
+0017 D28B 50 +5 acall wait
+0019 75A8FF 51 +5 reti
+ 52 +4 setb RI
+ 53 +4 setb TI
+ 54 +4
+001B 80FE 55 +4 acall wait
+ 56 +4 reti
+ 57 +3 setb RI
+ 58 +3 setb TI
+ 59 +3
+ 60 +3 acall wait
+ 61 +3 reti
+ 62 +2 setb RI
+ 63 +2 setb TI
+ 64 +2
+ 65 +2 acall wait
+ 66 +2 reti
+ 67 +1 setb RI
+ 68 +1 setb TI
+ 69 +1
+ 70 +1 acall wait
+ 71 +1 reti
+ 72 intr
+ 73
+ 74 org 0Bh ; Timer 0
+ 75 intr
+ 76
+ 77 org 13h ; External 0
+ 78 intr
+ 79
+ 80 org 1Bh ; Timer 1
+ 81 intr
+ 82
+ 83 org 23h ; UART and SPI
+ 84 intr
+ 85
+ 86 org 2Bh ; Timer 2
+ 87 intr
+ 88
+ 89 org 33h ; Analog comparator
+ 90 intr
+ 91
+ 92 ; Subprograms
+ 93 ; -----------------
+ 94 wait: ; Wait for 24 cycles
+ 95 mov R7, #10h
+ 96 acall wait_aux
+ 97 ret
+ 98
+ 99 wait_aux:
+ 100 djnz R7, $
+ 101 ret
+ 102
+ 103
+ 104 ; Program start
+ 105 ; -----------------
+ 106 start:
+ 107 ; Set some interrupt bits
+ 108 setb TF0
+ 109 setb TF1
+ 110 setb IE0
+ 111 setb IE1
+ 112
+ 113 ; Enable all interrupts and set priorities
+ 114 mov IE, #0FFh
+ 115 setb PS
+ 116
+ 117 ; Infinite loop
+ 118 sjmp $
+ 119
+ 120
+ 121 ; End of code
+ 122 ; -----------------
+ 123 end
+ASSEMBLY COMPLETE, NO ERRORS FOUND, NO WARNINGS
+
+
+SYMBOL TABLE:
+AC . . . . . . . . . . . . . . . . . B ADDR 00D6H NOT USED
+ACC. . . . . . . . . . . . . . . . . D ADDR 00E0H NOT USED
+ACSR . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+AUXR . . . . . . . . . . . . . . . . D ADDR 008EH NOT USED
+AUXR1. . . . . . . . . . . . . . . . D ADDR 00A2H NOT USED
+B. . . . . . . . . . . . . . . . . . D ADDR 00F0H NOT USED
+CKCON. . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CLKREG . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CPRL2. . . . . . . . . . . . . . . . B ADDR 00C8H NOT USED
+CT2. . . . . . . . . . . . . . . . . B ADDR 00C9H NOT USED
+CY . . . . . . . . . . . . . . . . . B ADDR 00D7H NOT USED
+DP0H . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DP0L . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+DP1H . . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+DP1L . . . . . . . . . . . . . . . . D ADDR 0084H NOT USED
+DPH. . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DPL. . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+EA . . . . . . . . . . . . . . . . . B ADDR 00AFH NOT USED
+EECON. . . . . . . . . . . . . . . . D ADDR 0096H NOT USED
+ES . . . . . . . . . . . . . . . . . B ADDR 00ACH NOT USED
+ET0. . . . . . . . . . . . . . . . . B ADDR 00A9H NOT USED
+ET1. . . . . . . . . . . . . . . . . B ADDR 00ABH NOT USED
+EX0. . . . . . . . . . . . . . . . . B ADDR 00A8H NOT USED
+EX1. . . . . . . . . . . . . . . . . B ADDR 00AAH NOT USED
+EXEN2. . . . . . . . . . . . . . . . B ADDR 00CBH NOT USED
+EXF2 . . . . . . . . . . . . . . . . B ADDR 00CEH NOT USED
+F0 . . . . . . . . . . . . . . . . . B ADDR 00D5H NOT USED
+IE . . . . . . . . . . . . . . . . . D ADDR 00A8H NOT USED
+IE0. . . . . . . . . . . . . . . . . B ADDR 0089H NOT USED
+IE1. . . . . . . . . . . . . . . . . B ADDR 008BH NOT USED
+INT0 . . . . . . . . . . . . . . . . B ADDR 00B2H NOT USED
+INT1 . . . . . . . . . . . . . . . . B ADDR 00B3H NOT USED
+IP . . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPH. . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IT0. . . . . . . . . . . . . . . . . B ADDR 0088H NOT USED
+IT1. . . . . . . . . . . . . . . . . B ADDR 008AH NOT USED
+OV . . . . . . . . . . . . . . . . . B ADDR 00D2H NOT USED
+P. . . . . . . . . . . . . . . . . . B ADDR 00D0H NOT USED
+P0 . . . . . . . . . . . . . . . . . D ADDR 0080H NOT USED
+P1 . . . . . . . . . . . . . . . . . D ADDR 0090H NOT USED
+P2 . . . . . . . . . . . . . . . . . D ADDR 00A0H NOT USED
+P3 . . . . . . . . . . . . . . . . . D ADDR 00B0H NOT USED
+P4 . . . . . . . . . . . . . . . . . D ADDR 00C0H NOT USED
+PCON . . . . . . . . . . . . . . . . D ADDR 0087H NOT USED
+PS . . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSW. . . . . . . . . . . . . . . . . D ADDR 00D0H NOT USED
+PT0. . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT1. . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PX0. . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX1. . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+RB8. . . . . . . . . . . . . . . . . B ADDR 009AH NOT USED
+RCAP2H . . . . . . . . . . . . . . . D ADDR 00CBH NOT USED
+RCAP2L . . . . . . . . . . . . . . . D ADDR 00CAH NOT USED
+RCLK . . . . . . . . . . . . . . . . B ADDR 00CDH NOT USED
+RD . . . . . . . . . . . . . . . . . B ADDR 00B7H NOT USED
+REN. . . . . . . . . . . . . . . . . B ADDR 009CH NOT USED
+RI . . . . . . . . . . . . . . . . . B ADDR 0098H NOT USED
+RS0. . . . . . . . . . . . . . . . . B ADDR 00D3H NOT USED
+RS1. . . . . . . . . . . . . . . . . B ADDR 00D4H NOT USED
+RXD. . . . . . . . . . . . . . . . . B ADDR 00B0H NOT USED
+SADDR. . . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADEN. . . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SBUF . . . . . . . . . . . . . . . . D ADDR 0099H NOT USED
+SCON . . . . . . . . . . . . . . . . D ADDR 0098H NOT USED
+SM0. . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+SM1. . . . . . . . . . . . . . . . . B ADDR 009EH NOT USED
+SM2. . . . . . . . . . . . . . . . . B ADDR 009DH NOT USED
+SP . . . . . . . . . . . . . . . . . D ADDR 0081H NOT USED
+SPCR . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+SPDR . . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+SPSR . . . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+START. . . . . . . . . . . . . . . . C ADDR 0042H NOT USED
+T0 . . . . . . . . . . . . . . . . . B ADDR 00B4H NOT USED
+T1 . . . . . . . . . . . . . . . . . B ADDR 00B5H NOT USED
+T2CON. . . . . . . . . . . . . . . . D ADDR 00C8H NOT USED
+T2MOD. . . . . . . . . . . . . . . . D ADDR 00C9H NOT USED
+TB8. . . . . . . . . . . . . . . . . B ADDR 009BH NOT USED
+TCLK . . . . . . . . . . . . . . . . B ADDR 00CCH NOT USED
+TCON . . . . . . . . . . . . . . . . D ADDR 0088H NOT USED
+TF0. . . . . . . . . . . . . . . . . B ADDR 008DH NOT USED
+TF1. . . . . . . . . . . . . . . . . B ADDR 008FH NOT USED
+TF2. . . . . . . . . . . . . . . . . B ADDR 00CFH NOT USED
+TH0. . . . . . . . . . . . . . . . . D ADDR 008CH NOT USED
+TH1. . . . . . . . . . . . . . . . . D ADDR 008DH NOT USED
+TH2. . . . . . . . . . . . . . . . . D ADDR 00CDH NOT USED
+TI . . . . . . . . . . . . . . . . . B ADDR 0099H NOT USED
+TL0. . . . . . . . . . . . . . . . . D ADDR 008AH NOT USED
+TL1. . . . . . . . . . . . . . . . . D ADDR 008BH NOT USED
+TL2. . . . . . . . . . . . . . . . . D ADDR 00CCH NOT USED
+TMOD . . . . . . . . . . . . . . . . D ADDR 0089H NOT USED
+TR0. . . . . . . . . . . . . . . . . B ADDR 008CH NOT USED
+TR1. . . . . . . . . . . . . . . . . B ADDR 008EH NOT USED
+TR2. . . . . . . . . . . . . . . . . B ADDR 00CAH NOT USED
+TXD. . . . . . . . . . . . . . . . . B ADDR 00B1H NOT USED
+WAIT . . . . . . . . . . . . . . . . C ADDR 003AH NOT USED
+WAIT_AUX . . . . . . . . . . . . . . C ADDR 003FH NOT USED
+WDTCON . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTPRG . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTRST . . . . . . . . . . . . . . . D ADDR 00A6H NOT USED
+WR . . . . . . . . . . . . . . . . . B ADDR 00B6H NOT USED \ No newline at end of file
diff --git a/demo/demo4.sim b/demo/demo4.sim
new file mode 100644
index 0000000..52643cc
--- /dev/null
+++ b/demo/demo4.sim
@@ -0,0 +1,42 @@
+7E1BFADD8BDB7A40D6B8CA5161E3113A 01/14/08 demo4.asm
+27 0 128 64
+30 3 210 152
+30 5 210 153
+30 7 17 58
+30 9 50
+33 11 210 152
+33 13 210 153
+33 15 17 58
+33 17 50
+36 19 210 152
+36 21 210 153
+36 23 17 58
+36 25 50
+39 27 210 152
+39 29 210 153
+39 31 17 58
+39 33 50
+42 35 210 152
+42 37 210 153
+42 39 17 58
+42 41 50
+45 43 210 152
+45 45 210 153
+45 47 17 58
+45 49 50
+48 51 210 152
+48 53 210 153
+48 55 17 58
+48 57 50
+53 58 127 16
+54 60 17 63
+55 62 34
+58 63 223 254
+59 65 34
+66 66 210 141
+67 68 210 143
+68 70 210 137
+69 72 210 139
+72 74 117 168 255
+73 77 210 188
+76 79 128 254 \ No newline at end of file
diff --git a/demo/demo5.adf b/demo/demo5.adf
new file mode 100644
index 0000000..de35ed8
--- /dev/null
+++ b/demo/demo5.adf
@@ -0,0 +1,5 @@
+# Assembler debug file for MCU 8051 IDE v1.1
+# Used assembler: MCU 8051 IDE
+# Date: 03/02/09
+8A77C444C26BA55C5A8AC82FE0C8CFA9 "demo5.asm"
+0 32 0 128 254 \ No newline at end of file
diff --git a/demo/demo5.asm b/demo/demo5.asm
new file mode 100644
index 0000000..9c3bc68
--- /dev/null
+++ b/demo/demo5.asm
@@ -0,0 +1,35 @@
+; Dissassebler
+; --------------------
+; [Main menu] -> [Tools] -> [Dissasseble]
+; Choose some hex file and see result
+
+; Custom commands
+; --------------------
+; They can be used for instance to load your program into a
+; real processor.
+; [Main menu] -> [Configure] -> [Edit cutom commands]
+; [Main menu] -> [Tools] -> [Cutom command N]
+
+; Tip of the day
+; --------------------
+; You may find some useful advices how to use this
+; IDE more efficiently
+; [Main menu] -> [Help] -> [Tip of the day]
+
+; Project web page:
+; --------------------
+; http://mcu8051ide.sf.net
+
+
+
+; AND NOW YOU ARE READY !
+; Click on [Main menu] -> [Project] -> [New] and create your own 8051 project ...
+
+
+; !!! HAVE A GOOD LUCK WITH THIS IDE !!!
+
+ org 0
+ sjmp $
+ end
+
+; !!! HAVE A GOOD LUCK WITH THIS IDE !!! \ No newline at end of file
diff --git a/demo/demo5.bin b/demo/demo5.bin
new file mode 100644
index 0000000..5416677
--- /dev/null
+++ b/demo/demo5.bin
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/demo/demo5.hex b/demo/demo5.hex
new file mode 100644
index 0000000..0df57c5
--- /dev/null
+++ b/demo/demo5.hex
@@ -0,0 +1,2 @@
+:0200000080FE80
+:00000001FF \ No newline at end of file
diff --git a/demo/demo5.lst b/demo/demo5.lst
new file mode 100644
index 0000000..3468d65
--- /dev/null
+++ b/demo/demo5.lst
@@ -0,0 +1,216 @@
+demo5 PAGE 1
+ 1 ; Dissassebler
+ 2 ; --------------------
+ 3 ; [Main menu] -> [Tools] -> [Dissasseble]
+ 4 ; Choose some hex file and see result
+ 5
+ 6 ; Custom commands
+ 7 ; --------------------
+ 8 ; They can be used for instance to load your program into a
+ 9 ; real processor.
+ 10 ; [Main menu] -> [Configure] -> [Edit cutom commands]
+ 11 ; [Main menu] -> [Tools] -> [Cutom command N]
+ 12
+ 13 ; Tip of the day
+ 14 ; --------------------
+ 15 ; You may find some useful advices how to use this
+ 16 ; IDE more efficiently
+ 17 ; [Main menu] -> [Help] -> [Tip of the day]
+ 18
+ 19 ; Project web page:
+ 20 ; --------------------
+ 21 ; http://mcu8051ide.sf.net
+ 22
+ 23
+ 24
+ 25 ; AND NOW YOU ARE READY !
+ 26 ; Click on [Main menu] -> [Project] -> [New] and create your own 8051 project ...
+ 27
+ 28
+ 29 ; !!! HAVE A GOOD LUCK WITH THIS IDE !!!
+ 30
+ 31 org 0
+ 32 sjmp $
+ 33 end
+ASSEMBLY COMPLETE, NO ERRORS FOUND, NO WARNINGS
+
+
+SYMBOL TABLE:
+AC . . . . . . . . . . . . . . . . . B ADDR 00D6H NOT USED
+ACC. . . . . . . . . . . . . . . . . D ADDR 00E0H NOT USED
+ACSR . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+ADCF . . . . . . . . . . . . . . . . D ADDR 00F6H NOT USED
+ADCLK. . . . . . . . . . . . . . . . D ADDR 00F2H NOT USED
+ADCON. . . . . . . . . . . . . . . . D ADDR 00F3H NOT USED
+ADDH . . . . . . . . . . . . . . . . D ADDR 00F5H NOT USED
+ADDL . . . . . . . . . . . . . . . . D ADDR 00F4H NOT USED
+AUXR . . . . . . . . . . . . . . . . D ADDR 008EH NOT USED
+AUXR1. . . . . . . . . . . . . . . . D ADDR 00A2H NOT USED
+B. . . . . . . . . . . . . . . . . . D ADDR 00F0H NOT USED
+BDRCON . . . . . . . . . . . . . . . D ADDR 009BH NOT USED
+BDRCON_1 . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+BRL. . . . . . . . . . . . . . . . . D ADDR 009AH NOT USED
+CCAP0H . . . . . . . . . . . . . . . D ADDR 00FAH NOT USED
+CCAP0L . . . . . . . . . . . . . . . D ADDR 00EAH NOT USED
+CCAP1H . . . . . . . . . . . . . . . D ADDR 00FBH NOT USED
+CCAP1L . . . . . . . . . . . . . . . D ADDR 00EBH NOT USED
+CCAP2H . . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAP3H . . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAP4H . . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL2H. . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAPL2L. . . . . . . . . . . . . . . D ADDR 00ECH NOT USED
+CCAPL3H. . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAPL3L. . . . . . . . . . . . . . . D ADDR 00EDH NOT USED
+CCAPL4H. . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL4L. . . . . . . . . . . . . . . D ADDR 00EEH NOT USED
+CCAPM0 . . . . . . . . . . . . . . . D ADDR 00DAH NOT USED
+CCAPM1 . . . . . . . . . . . . . . . D ADDR 00DBH NOT USED
+CCAPM2 . . . . . . . . . . . . . . . D ADDR 00DCH NOT USED
+CCAPM3 . . . . . . . . . . . . . . . D ADDR 00DDH NOT USED
+CCAPM4 . . . . . . . . . . . . . . . D ADDR 00DEH NOT USED
+CCF0 . . . . . . . . . . . . . . . . B ADDR 00D8H NOT USED
+CCF1 . . . . . . . . . . . . . . . . B ADDR 00D9H NOT USED
+CCF2 . . . . . . . . . . . . . . . . B ADDR 00DAH NOT USED
+CCF3 . . . . . . . . . . . . . . . . B ADDR 00DBH NOT USED
+CCF4 . . . . . . . . . . . . . . . . B ADDR 00DCH NOT USED
+CCON . . . . . . . . . . . . . . . . D ADDR 00D8H NOT USED
+CFINT. . . . . . . . . . . . . . . . C ADDR 0033H NOT USED
+CH . . . . . . . . . . . . . . . . . D ADDR 00F9H NOT USED
+CKCON. . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKCON0 . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKRL . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+CKSEL. . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+CL . . . . . . . . . . . . . . . . . D ADDR 00E9H NOT USED
+CLKREG . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CMOD . . . . . . . . . . . . . . . . D ADDR 00D9H NOT USED
+CPRL2. . . . . . . . . . . . . . . . B ADDR 00C8H NOT USED
+CR . . . . . . . . . . . . . . . . . B ADDR 00DEH NOT USED
+CT2. . . . . . . . . . . . . . . . . B ADDR 00C9H NOT USED
+CY . . . . . . . . . . . . . . . . . B ADDR 00D7H NOT USED
+DP0H . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DP0L . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+DP1H . . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+DP1L . . . . . . . . . . . . . . . . D ADDR 0084H NOT USED
+DPH. . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DPL. . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+EA . . . . . . . . . . . . . . . . . B ADDR 00AFH NOT USED
+EC . . . . . . . . . . . . . . . . . B ADDR 00AEH NOT USED
+EECON. . . . . . . . . . . . . . . . D ADDR 0096H NOT USED
+ES . . . . . . . . . . . . . . . . . B ADDR 00ACH NOT USED
+ET0. . . . . . . . . . . . . . . . . B ADDR 00A9H NOT USED
+ET1. . . . . . . . . . . . . . . . . B ADDR 00ABH NOT USED
+ET2. . . . . . . . . . . . . . . . . B ADDR 00ADH NOT USED
+EX0. . . . . . . . . . . . . . . . . B ADDR 00A8H NOT USED
+EX1. . . . . . . . . . . . . . . . . B ADDR 00AAH NOT USED
+EXEN2. . . . . . . . . . . . . . . . B ADDR 00CBH NOT USED
+EXF2 . . . . . . . . . . . . . . . . B ADDR 00CEH NOT USED
+EXTI0. . . . . . . . . . . . . . . . C ADDR 0003H NOT USED
+EXTI1. . . . . . . . . . . . . . . . C ADDR 0013H NOT USED
+F0 . . . . . . . . . . . . . . . . . B ADDR 00D5H NOT USED
+FE . . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+IE . . . . . . . . . . . . . . . . . D ADDR 00A8H NOT USED
+IE0. . . . . . . . . . . . . . . . . B ADDR 0089H NOT USED
+IE1. . . . . . . . . . . . . . . . . B ADDR 008BH NOT USED
+INT0 . . . . . . . . . . . . . . . . B ADDR 00B2H NOT USED
+INT1 . . . . . . . . . . . . . . . . B ADDR 00B3H NOT USED
+IP . . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPH. . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH0 . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH1 . . . . . . . . . . . . . . . . D ADDR 00B3H NOT USED
+IPL0 . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPL1 . . . . . . . . . . . . . . . . D ADDR 00B2H NOT USED
+IT0. . . . . . . . . . . . . . . . . B ADDR 0088H NOT USED
+IT1. . . . . . . . . . . . . . . . . B ADDR 008AH NOT USED
+KBE. . . . . . . . . . . . . . . . . D ADDR 009DH NOT USED
+KBF. . . . . . . . . . . . . . . . . D ADDR 009EH NOT USED
+KBLS . . . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+OSCCON . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+OV . . . . . . . . . . . . . . . . . B ADDR 00D2H NOT USED
+P. . . . . . . . . . . . . . . . . . B ADDR 00D0H NOT USED
+P0 . . . . . . . . . . . . . . . . . D ADDR 0080H NOT USED
+P1 . . . . . . . . . . . . . . . . . D ADDR 0090H NOT USED
+P1M1 . . . . . . . . . . . . . . . . D ADDR 00D4H NOT USED
+P1M2 . . . . . . . . . . . . . . . . D ADDR 00E2H NOT USED
+P2 . . . . . . . . . . . . . . . . . D ADDR 00A0H NOT USED
+P3 . . . . . . . . . . . . . . . . . D ADDR 00B0H NOT USED
+P3M1 . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+P3M2 . . . . . . . . . . . . . . . . D ADDR 00E3H NOT USED
+P4 . . . . . . . . . . . . . . . . . D ADDR 00C0H NOT USED
+P4M1 . . . . . . . . . . . . . . . . D ADDR 00D6H NOT USED
+P4M2 . . . . . . . . . . . . . . . . D ADDR 00E4H NOT USED
+P5 . . . . . . . . . . . . . . . . . D ADDR 00E8H NOT USED
+PC . . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PCON . . . . . . . . . . . . . . . . D ADDR 0087H NOT USED
+PPCL . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PS . . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSL. . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSW. . . . . . . . . . . . . . . . . D ADDR 00D0H NOT USED
+PT0. . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT0L . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT1. . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT1L . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT2. . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PT2L . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PX0. . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX0L . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX1. . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+PX1L . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+RB8. . . . . . . . . . . . . . . . . B ADDR 009AH NOT USED
+RCAP2H . . . . . . . . . . . . . . . D ADDR 00CBH NOT USED
+RCAP2L . . . . . . . . . . . . . . . D ADDR 00CAH NOT USED
+RCLK . . . . . . . . . . . . . . . . B ADDR 00CDH NOT USED
+RD . . . . . . . . . . . . . . . . . B ADDR 00B7H NOT USED
+REN. . . . . . . . . . . . . . . . . B ADDR 009CH NOT USED
+RESET. . . . . . . . . . . . . . . . C ADDR 0000H NOT USED
+RI . . . . . . . . . . . . . . . . . B ADDR 0098H NOT USED
+RS0. . . . . . . . . . . . . . . . . B ADDR 00D3H NOT USED
+RS1. . . . . . . . . . . . . . . . . B ADDR 00D4H NOT USED
+RXD. . . . . . . . . . . . . . . . . B ADDR 00B0H NOT USED
+SADDR. . . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_0. . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_1. . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SADEN. . . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_0. . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_1. . . . . . . . . . . . . . . D ADDR 00BAH NOT USED
+SBUF . . . . . . . . . . . . . . . . D ADDR 0099H NOT USED
+SCON . . . . . . . . . . . . . . . . D ADDR 0098H NOT USED
+SINT . . . . . . . . . . . . . . . . C ADDR 0023H NOT USED
+SM0. . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+SM1. . . . . . . . . . . . . . . . . B ADDR 009EH NOT USED
+SM2. . . . . . . . . . . . . . . . . B ADDR 009DH NOT USED
+SP . . . . . . . . . . . . . . . . . D ADDR 0081H NOT USED
+SPCON. . . . . . . . . . . . . . . . D ADDR 00C3H NOT USED
+SPCR . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+SPDAT. . . . . . . . . . . . . . . . D ADDR 00C5H NOT USED
+SPDR . . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+SPSR . . . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SPSTA. . . . . . . . . . . . . . . . D ADDR 00C4H NOT USED
+T0 . . . . . . . . . . . . . . . . . B ADDR 00B4H NOT USED
+T1 . . . . . . . . . . . . . . . . . B ADDR 00B5H NOT USED
+T2CON. . . . . . . . . . . . . . . . D ADDR 00C8H NOT USED
+T2MOD. . . . . . . . . . . . . . . . D ADDR 00C9H NOT USED
+TB8. . . . . . . . . . . . . . . . . B ADDR 009BH NOT USED
+TCLK . . . . . . . . . . . . . . . . B ADDR 00CCH NOT USED
+TCON . . . . . . . . . . . . . . . . D ADDR 0088H NOT USED
+TF0. . . . . . . . . . . . . . . . . B ADDR 008DH NOT USED
+TF1. . . . . . . . . . . . . . . . . B ADDR 008FH NOT USED
+TF2. . . . . . . . . . . . . . . . . B ADDR 00CFH NOT USED
+TH0. . . . . . . . . . . . . . . . . D ADDR 008CH NOT USED
+TH1. . . . . . . . . . . . . . . . . D ADDR 008DH NOT USED
+TH2. . . . . . . . . . . . . . . . . D ADDR 00CDH NOT USED
+TI . . . . . . . . . . . . . . . . . B ADDR 0099H NOT USED
+TIMER0 . . . . . . . . . . . . . . . C ADDR 000BH NOT USED
+TIMER1 . . . . . . . . . . . . . . . C ADDR 001BH NOT USED
+TIMER2 . . . . . . . . . . . . . . . C ADDR 002BH NOT USED
+TL0. . . . . . . . . . . . . . . . . D ADDR 008AH NOT USED
+TL1. . . . . . . . . . . . . . . . . D ADDR 008BH NOT USED
+TL2. . . . . . . . . . . . . . . . . D ADDR 00CCH NOT USED
+TMOD . . . . . . . . . . . . . . . . D ADDR 0089H NOT USED
+TR0. . . . . . . . . . . . . . . . . B ADDR 008CH NOT USED
+TR1. . . . . . . . . . . . . . . . . B ADDR 008EH NOT USED
+TR2. . . . . . . . . . . . . . . . . B ADDR 00CAH NOT USED
+TXD. . . . . . . . . . . . . . . . . B ADDR 00B1H NOT USED
+WDTCON . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTPRG . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTRST . . . . . . . . . . . . . . . D ADDR 00A6H NOT USED
+WR . . . . . . . . . . . . . . . . . B ADDR 00B6H NOT USED \ No newline at end of file
diff --git a/demo/demo5.sim b/demo/demo5.sim
new file mode 100644
index 0000000..7f2a49c
--- /dev/null
+++ b/demo/demo5.sim
@@ -0,0 +1,2 @@
+7D9DA265AF8276820125E7E130CFFF37 12/21/07 demo4.asm
+32 0 128 254 \ No newline at end of file
diff --git a/demo/demo_c_0 b/demo/demo_c_0
new file mode 100644
index 0000000..671d577
--- /dev/null
+++ b/demo/demo_c_0
Binary files differ
diff --git a/demo/demo_c_0.adb b/demo/demo_c_0.adb
new file mode 100644
index 0000000..30be84d
--- /dev/null
+++ b/demo/demo_c_0.adb
@@ -0,0 +1,106 @@
+M:demo_c_0
+F:G$someFunction$0$0({2}DF,SV:S),C,0,0,0,0,0
+F:G$main$0$0({2}DF,SI:S),C,0,0,0,0,0
+F:G$main$0$0({2}DF,SI:S),C,0,0,0,0,0
+S:G$some_variable$0$0({4}SL:U),E,0,0
+S:G$i$0$0({2}SI:S),E,0,0
+S:LsomeFunction$somevalue$1$1({1}SC:U),R,0,0,[r2]
+S:G$P0$0$0({1}SC:U),I,0,0
+S:G$SP$0$0({1}SC:U),I,0,0
+S:G$DPL$0$0({1}SC:U),I,0,0
+S:G$DPH$0$0({1}SC:U),I,0,0
+S:G$PCON$0$0({1}SC:U),I,0,0
+S:G$TCON$0$0({1}SC:U),I,0,0
+S:G$TMOD$0$0({1}SC:U),I,0,0
+S:G$TL0$0$0({1}SC:U),I,0,0
+S:G$TL1$0$0({1}SC:U),I,0,0
+S:G$TH0$0$0({1}SC:U),I,0,0
+S:G$TH1$0$0({1}SC:U),I,0,0
+S:G$P1$0$0({1}SC:U),I,0,0
+S:G$SCON$0$0({1}SC:U),I,0,0
+S:G$SBUF$0$0({1}SC:U),I,0,0
+S:G$P2$0$0({1}SC:U),I,0,0
+S:G$IE$0$0({1}SC:U),I,0,0
+S:G$P3$0$0({1}SC:U),I,0,0
+S:G$IP$0$0({1}SC:U),I,0,0
+S:G$PSW$0$0({1}SC:U),I,0,0
+S:G$ACC$0$0({1}SC:U),I,0,0
+S:G$A$0$0({1}SC:U),I,0,0
+S:G$B$0$0({1}SC:U),I,0,0
+S:G$P0_0$0$0({1}SX:U),J,0,0
+S:G$P0_1$0$0({1}SX:U),J,0,0
+S:G$P0_2$0$0({1}SX:U),J,0,0
+S:G$P0_3$0$0({1}SX:U),J,0,0
+S:G$P0_4$0$0({1}SX:U),J,0,0
+S:G$P0_5$0$0({1}SX:U),J,0,0
+S:G$P0_6$0$0({1}SX:U),J,0,0
+S:G$P0_7$0$0({1}SX:U),J,0,0
+S:G$IT0$0$0({1}SX:U),J,0,0
+S:G$IE0$0$0({1}SX:U),J,0,0
+S:G$IT1$0$0({1}SX:U),J,0,0
+S:G$IE1$0$0({1}SX:U),J,0,0
+S:G$TR0$0$0({1}SX:U),J,0,0
+S:G$TF0$0$0({1}SX:U),J,0,0
+S:G$TR1$0$0({1}SX:U),J,0,0
+S:G$TF1$0$0({1}SX:U),J,0,0
+S:G$P1_0$0$0({1}SX:U),J,0,0
+S:G$P1_1$0$0({1}SX:U),J,0,0
+S:G$P1_2$0$0({1}SX:U),J,0,0
+S:G$P1_3$0$0({1}SX:U),J,0,0
+S:G$P1_4$0$0({1}SX:U),J,0,0
+S:G$P1_5$0$0({1}SX:U),J,0,0
+S:G$P1_6$0$0({1}SX:U),J,0,0
+S:G$P1_7$0$0({1}SX:U),J,0,0
+S:G$RI$0$0({1}SX:U),J,0,0
+S:G$TI$0$0({1}SX:U),J,0,0
+S:G$RB8$0$0({1}SX:U),J,0,0
+S:G$TB8$0$0({1}SX:U),J,0,0
+S:G$REN$0$0({1}SX:U),J,0,0
+S:G$SM2$0$0({1}SX:U),J,0,0
+S:G$SM1$0$0({1}SX:U),J,0,0
+S:G$SM0$0$0({1}SX:U),J,0,0
+S:G$P2_0$0$0({1}SX:U),J,0,0
+S:G$P2_1$0$0({1}SX:U),J,0,0
+S:G$P2_2$0$0({1}SX:U),J,0,0
+S:G$P2_3$0$0({1}SX:U),J,0,0
+S:G$P2_4$0$0({1}SX:U),J,0,0
+S:G$P2_5$0$0({1}SX:U),J,0,0
+S:G$P2_6$0$0({1}SX:U),J,0,0
+S:G$P2_7$0$0({1}SX:U),J,0,0
+S:G$EX0$0$0({1}SX:U),J,0,0
+S:G$ET0$0$0({1}SX:U),J,0,0
+S:G$EX1$0$0({1}SX:U),J,0,0
+S:G$ET1$0$0({1}SX:U),J,0,0
+S:G$ES$0$0({1}SX:U),J,0,0
+S:G$EA$0$0({1}SX:U),J,0,0
+S:G$P3_0$0$0({1}SX:U),J,0,0
+S:G$P3_1$0$0({1}SX:U),J,0,0
+S:G$P3_2$0$0({1}SX:U),J,0,0
+S:G$P3_3$0$0({1}SX:U),J,0,0
+S:G$P3_4$0$0({1}SX:U),J,0,0
+S:G$P3_5$0$0({1}SX:U),J,0,0
+S:G$P3_6$0$0({1}SX:U),J,0,0
+S:G$P3_7$0$0({1}SX:U),J,0,0
+S:G$RXD$0$0({1}SX:U),J,0,0
+S:G$TXD$0$0({1}SX:U),J,0,0
+S:G$INT0$0$0({1}SX:U),J,0,0
+S:G$INT1$0$0({1}SX:U),J,0,0
+S:G$T0$0$0({1}SX:U),J,0,0
+S:G$T1$0$0({1}SX:U),J,0,0
+S:G$WR$0$0({1}SX:U),J,0,0
+S:G$RD$0$0({1}SX:U),J,0,0
+S:G$PX0$0$0({1}SX:U),J,0,0
+S:G$PT0$0$0({1}SX:U),J,0,0
+S:G$PX1$0$0({1}SX:U),J,0,0
+S:G$PT1$0$0({1}SX:U),J,0,0
+S:G$PS$0$0({1}SX:U),J,0,0
+S:G$P$0$0({1}SX:U),J,0,0
+S:G$FL$0$0({1}SX:U),J,0,0
+S:G$OV$0$0({1}SX:U),J,0,0
+S:G$RS0$0$0({1}SX:U),J,0,0
+S:G$RS1$0$0({1}SX:U),J,0,0
+S:G$F0$0$0({1}SX:U),J,0,0
+S:G$AC$0$0({1}SX:U),J,0,0
+S:G$CY$0$0({1}SX:U),J,0,0
+S:G$someFunction$0$0({2}DF,SV:S),C,0,0
+S:G$main$0$0({2}DF,SI:S),C,0,0
diff --git a/demo/demo_c_0.asm b/demo/demo_c_0.asm
new file mode 100644
index 0000000..8338791
--- /dev/null
+++ b/demo/demo_c_0.asm
@@ -0,0 +1,529 @@
+;--------------------------------------------------------
+; File Created by SDCC : free open source ANSI-C Compiler
+; Version 2.9.0 #5416 (Oct 6 2009) (UNIX)
+; This file was generated Tue Oct 27 23:03:10 2009
+;--------------------------------------------------------
+ .module demo_c_0
+ .optsdcc -mmcs51 --model-small
+
+;--------------------------------------------------------
+; Public variables in this module
+;--------------------------------------------------------
+ .globl _main
+ .globl _someFunction
+ .globl _CY
+ .globl _AC
+ .globl _F0
+ .globl _RS1
+ .globl _RS0
+ .globl _OV
+ .globl _FL
+ .globl _P
+ .globl _PS
+ .globl _PT1
+ .globl _PX1
+ .globl _PT0
+ .globl _PX0
+ .globl _RD
+ .globl _WR
+ .globl _T1
+ .globl _T0
+ .globl _INT1
+ .globl _INT0
+ .globl _TXD
+ .globl _RXD
+ .globl _P3_7
+ .globl _P3_6
+ .globl _P3_5
+ .globl _P3_4
+ .globl _P3_3
+ .globl _P3_2
+ .globl _P3_1
+ .globl _P3_0
+ .globl _EA
+ .globl _ES
+ .globl _ET1
+ .globl _EX1
+ .globl _ET0
+ .globl _EX0
+ .globl _P2_7
+ .globl _P2_6
+ .globl _P2_5
+ .globl _P2_4
+ .globl _P2_3
+ .globl _P2_2
+ .globl _P2_1
+ .globl _P2_0
+ .globl _SM0
+ .globl _SM1
+ .globl _SM2
+ .globl _REN
+ .globl _TB8
+ .globl _RB8
+ .globl _TI
+ .globl _RI
+ .globl _P1_7
+ .globl _P1_6
+ .globl _P1_5
+ .globl _P1_4
+ .globl _P1_3
+ .globl _P1_2
+ .globl _P1_1
+ .globl _P1_0
+ .globl _TF1
+ .globl _TR1
+ .globl _TF0
+ .globl _TR0
+ .globl _IE1
+ .globl _IT1
+ .globl _IE0
+ .globl _IT0
+ .globl _P0_7
+ .globl _P0_6
+ .globl _P0_5
+ .globl _P0_4
+ .globl _P0_3
+ .globl _P0_2
+ .globl _P0_1
+ .globl _P0_0
+ .globl _B
+ .globl _A
+ .globl _ACC
+ .globl _PSW
+ .globl _IP
+ .globl _P3
+ .globl _IE
+ .globl _P2
+ .globl _SBUF
+ .globl _SCON
+ .globl _P1
+ .globl _TH1
+ .globl _TH0
+ .globl _TL1
+ .globl _TL0
+ .globl _TMOD
+ .globl _TCON
+ .globl _PCON
+ .globl _DPH
+ .globl _DPL
+ .globl _SP
+ .globl _P0
+ .globl _i
+ .globl _some_variable
+;--------------------------------------------------------
+; special function registers
+;--------------------------------------------------------
+ .area RSEG (DATA)
+G$P0$0$0 == 0x0080
+_P0 = 0x0080
+G$SP$0$0 == 0x0081
+_SP = 0x0081
+G$DPL$0$0 == 0x0082
+_DPL = 0x0082
+G$DPH$0$0 == 0x0083
+_DPH = 0x0083
+G$PCON$0$0 == 0x0087
+_PCON = 0x0087
+G$TCON$0$0 == 0x0088
+_TCON = 0x0088
+G$TMOD$0$0 == 0x0089
+_TMOD = 0x0089
+G$TL0$0$0 == 0x008a
+_TL0 = 0x008a
+G$TL1$0$0 == 0x008b
+_TL1 = 0x008b
+G$TH0$0$0 == 0x008c
+_TH0 = 0x008c
+G$TH1$0$0 == 0x008d
+_TH1 = 0x008d
+G$P1$0$0 == 0x0090
+_P1 = 0x0090
+G$SCON$0$0 == 0x0098
+_SCON = 0x0098
+G$SBUF$0$0 == 0x0099
+_SBUF = 0x0099
+G$P2$0$0 == 0x00a0
+_P2 = 0x00a0
+G$IE$0$0 == 0x00a8
+_IE = 0x00a8
+G$P3$0$0 == 0x00b0
+_P3 = 0x00b0
+G$IP$0$0 == 0x00b8
+_IP = 0x00b8
+G$PSW$0$0 == 0x00d0
+_PSW = 0x00d0
+G$ACC$0$0 == 0x00e0
+_ACC = 0x00e0
+G$A$0$0 == 0x00e0
+_A = 0x00e0
+G$B$0$0 == 0x00f0
+_B = 0x00f0
+;--------------------------------------------------------
+; special function bits
+;--------------------------------------------------------
+ .area RSEG (DATA)
+G$P0_0$0$0 == 0x0080
+_P0_0 = 0x0080
+G$P0_1$0$0 == 0x0081
+_P0_1 = 0x0081
+G$P0_2$0$0 == 0x0082
+_P0_2 = 0x0082
+G$P0_3$0$0 == 0x0083
+_P0_3 = 0x0083
+G$P0_4$0$0 == 0x0084
+_P0_4 = 0x0084
+G$P0_5$0$0 == 0x0085
+_P0_5 = 0x0085
+G$P0_6$0$0 == 0x0086
+_P0_6 = 0x0086
+G$P0_7$0$0 == 0x0087
+_P0_7 = 0x0087
+G$IT0$0$0 == 0x0088
+_IT0 = 0x0088
+G$IE0$0$0 == 0x0089
+_IE0 = 0x0089
+G$IT1$0$0 == 0x008a
+_IT1 = 0x008a
+G$IE1$0$0 == 0x008b
+_IE1 = 0x008b
+G$TR0$0$0 == 0x008c
+_TR0 = 0x008c
+G$TF0$0$0 == 0x008d
+_TF0 = 0x008d
+G$TR1$0$0 == 0x008e
+_TR1 = 0x008e
+G$TF1$0$0 == 0x008f
+_TF1 = 0x008f
+G$P1_0$0$0 == 0x0090
+_P1_0 = 0x0090
+G$P1_1$0$0 == 0x0091
+_P1_1 = 0x0091
+G$P1_2$0$0 == 0x0092
+_P1_2 = 0x0092
+G$P1_3$0$0 == 0x0093
+_P1_3 = 0x0093
+G$P1_4$0$0 == 0x0094
+_P1_4 = 0x0094
+G$P1_5$0$0 == 0x0095
+_P1_5 = 0x0095
+G$P1_6$0$0 == 0x0096
+_P1_6 = 0x0096
+G$P1_7$0$0 == 0x0097
+_P1_7 = 0x0097
+G$RI$0$0 == 0x0098
+_RI = 0x0098
+G$TI$0$0 == 0x0099
+_TI = 0x0099
+G$RB8$0$0 == 0x009a
+_RB8 = 0x009a
+G$TB8$0$0 == 0x009b
+_TB8 = 0x009b
+G$REN$0$0 == 0x009c
+_REN = 0x009c
+G$SM2$0$0 == 0x009d
+_SM2 = 0x009d
+G$SM1$0$0 == 0x009e
+_SM1 = 0x009e
+G$SM0$0$0 == 0x009f
+_SM0 = 0x009f
+G$P2_0$0$0 == 0x00a0
+_P2_0 = 0x00a0
+G$P2_1$0$0 == 0x00a1
+_P2_1 = 0x00a1
+G$P2_2$0$0 == 0x00a2
+_P2_2 = 0x00a2
+G$P2_3$0$0 == 0x00a3
+_P2_3 = 0x00a3
+G$P2_4$0$0 == 0x00a4
+_P2_4 = 0x00a4
+G$P2_5$0$0 == 0x00a5
+_P2_5 = 0x00a5
+G$P2_6$0$0 == 0x00a6
+_P2_6 = 0x00a6
+G$P2_7$0$0 == 0x00a7
+_P2_7 = 0x00a7
+G$EX0$0$0 == 0x00a8
+_EX0 = 0x00a8
+G$ET0$0$0 == 0x00a9
+_ET0 = 0x00a9
+G$EX1$0$0 == 0x00aa
+_EX1 = 0x00aa
+G$ET1$0$0 == 0x00ab
+_ET1 = 0x00ab
+G$ES$0$0 == 0x00ac
+_ES = 0x00ac
+G$EA$0$0 == 0x00af
+_EA = 0x00af
+G$P3_0$0$0 == 0x00b0
+_P3_0 = 0x00b0
+G$P3_1$0$0 == 0x00b1
+_P3_1 = 0x00b1
+G$P3_2$0$0 == 0x00b2
+_P3_2 = 0x00b2
+G$P3_3$0$0 == 0x00b3
+_P3_3 = 0x00b3
+G$P3_4$0$0 == 0x00b4
+_P3_4 = 0x00b4
+G$P3_5$0$0 == 0x00b5
+_P3_5 = 0x00b5
+G$P3_6$0$0 == 0x00b6
+_P3_6 = 0x00b6
+G$P3_7$0$0 == 0x00b7
+_P3_7 = 0x00b7
+G$RXD$0$0 == 0x00b0
+_RXD = 0x00b0
+G$TXD$0$0 == 0x00b1
+_TXD = 0x00b1
+G$INT0$0$0 == 0x00b2
+_INT0 = 0x00b2
+G$INT1$0$0 == 0x00b3
+_INT1 = 0x00b3
+G$T0$0$0 == 0x00b4
+_T0 = 0x00b4
+G$T1$0$0 == 0x00b5
+_T1 = 0x00b5
+G$WR$0$0 == 0x00b6
+_WR = 0x00b6
+G$RD$0$0 == 0x00b7
+_RD = 0x00b7
+G$PX0$0$0 == 0x00b8
+_PX0 = 0x00b8
+G$PT0$0$0 == 0x00b9
+_PT0 = 0x00b9
+G$PX1$0$0 == 0x00ba
+_PX1 = 0x00ba
+G$PT1$0$0 == 0x00bb
+_PT1 = 0x00bb
+G$PS$0$0 == 0x00bc
+_PS = 0x00bc
+G$P$0$0 == 0x00d0
+_P = 0x00d0
+G$FL$0$0 == 0x00d1
+_FL = 0x00d1
+G$OV$0$0 == 0x00d2
+_OV = 0x00d2
+G$RS0$0$0 == 0x00d3
+_RS0 = 0x00d3
+G$RS1$0$0 == 0x00d4
+_RS1 = 0x00d4
+G$F0$0$0 == 0x00d5
+_F0 = 0x00d5
+G$AC$0$0 == 0x00d6
+_AC = 0x00d6
+G$CY$0$0 == 0x00d7
+_CY = 0x00d7
+;--------------------------------------------------------
+; overlayable register banks
+;--------------------------------------------------------
+ .area REG_BANK_0 (REL,OVR,DATA)
+ .ds 8
+;--------------------------------------------------------
+; internal ram data
+;--------------------------------------------------------
+ .area DSEG (DATA)
+G$some_variable$0$0==.
+_some_variable::
+ .ds 4
+G$i$0$0==.
+_i::
+ .ds 2
+;--------------------------------------------------------
+; overlayable items in internal ram
+;--------------------------------------------------------
+ .area OSEG (OVR,DATA)
+;--------------------------------------------------------
+; Stack segment in internal ram
+;--------------------------------------------------------
+ .area SSEG (DATA)
+__start__stack:
+ .ds 1
+
+;--------------------------------------------------------
+; indirectly addressable internal ram data
+;--------------------------------------------------------
+ .area ISEG (DATA)
+;--------------------------------------------------------
+; absolute internal ram data
+;--------------------------------------------------------
+ .area IABS (ABS,DATA)
+ .area IABS (ABS,DATA)
+;--------------------------------------------------------
+; bit data
+;--------------------------------------------------------
+ .area BSEG (BIT)
+;--------------------------------------------------------
+; paged external ram data
+;--------------------------------------------------------
+ .area PSEG (PAG,XDATA)
+;--------------------------------------------------------
+; external ram data
+;--------------------------------------------------------
+ .area XSEG (XDATA)
+;--------------------------------------------------------
+; absolute external ram data
+;--------------------------------------------------------
+ .area XABS (ABS,XDATA)
+;--------------------------------------------------------
+; external initialized ram data
+;--------------------------------------------------------
+ .area XISEG (XDATA)
+ .area HOME (CODE)
+ .area GSINIT0 (CODE)
+ .area GSINIT1 (CODE)
+ .area GSINIT2 (CODE)
+ .area GSINIT3 (CODE)
+ .area GSINIT4 (CODE)
+ .area GSINIT5 (CODE)
+ .area GSINIT (CODE)
+ .area GSFINAL (CODE)
+ .area CSEG (CODE)
+;--------------------------------------------------------
+; interrupt vector
+;--------------------------------------------------------
+ .area HOME (CODE)
+__interrupt_vect:
+ ljmp __sdcc_gsinit_startup
+;--------------------------------------------------------
+; global & static initialisations
+;--------------------------------------------------------
+ .area HOME (CODE)
+ .area GSINIT (CODE)
+ .area GSFINAL (CODE)
+ .area GSINIT (CODE)
+ .globl __sdcc_gsinit_startup
+ .globl __sdcc_program_startup
+ .globl __start__stack
+ .globl __mcs51_genXINIT
+ .globl __mcs51_genXRAMCLEAR
+ .globl __mcs51_genRAMCLEAR
+ G$main$0$0 ==.
+ C$demo_c_0.c$10$1$1 ==.
+; demo_c_0.c:10: unsigned long some_variable=0; ///< Documentation for this variable comes here
+ clr a
+ mov _some_variable,a
+ mov (_some_variable + 1),a
+ mov (_some_variable + 2),a
+ mov (_some_variable + 3),a
+ .area GSFINAL (CODE)
+ ljmp __sdcc_program_startup
+;--------------------------------------------------------
+; Home
+;--------------------------------------------------------
+ .area HOME (CODE)
+ .area HOME (CODE)
+__sdcc_program_startup:
+ lcall _main
+; return from main will lock up
+ sjmp .
+;--------------------------------------------------------
+; code
+;--------------------------------------------------------
+ .area CSEG (CODE)
+;------------------------------------------------------------
+;Allocation info for local variables in function 'someFunction'
+;------------------------------------------------------------
+;somevalue Allocated to registers r2
+;------------------------------------------------------------
+ G$someFunction$0$0 ==.
+ C$demo_c_0.c$20$0$0 ==.
+; demo_c_0.c:20: void someFunction(unsigned char somevalue)
+; -----------------------------------------
+; function someFunction
+; -----------------------------------------
+_someFunction:
+ ar2 = 0x02
+ ar3 = 0x03
+ ar4 = 0x04
+ ar5 = 0x05
+ ar6 = 0x06
+ ar7 = 0x07
+ ar0 = 0x00
+ ar1 = 0x01
+ mov r2,dpl
+ C$demo_c_0.c$23$1$1 ==.
+; demo_c_0.c:23: P1=somevalue;
+ mov _P1,r2
+ C$demo_c_0.c$24$1$1 ==.
+; demo_c_0.c:24: P3=somevalue^0xFF;
+ mov a,#0xFF
+ xrl a,r2
+ mov _P3,a
+ C$demo_c_0.c$25$1$1 ==.
+ XG$someFunction$0$0 ==.
+ ret
+;------------------------------------------------------------
+;Allocation info for local variables in function 'main'
+;------------------------------------------------------------
+;------------------------------------------------------------
+ G$main$0$0 ==.
+ C$demo_c_0.c$28$1$1 ==.
+; demo_c_0.c:28: int main()
+; -----------------------------------------
+; function main
+; -----------------------------------------
+_main:
+ C$demo_c_0.c$31$1$1 ==.
+; demo_c_0.c:31: while(1) {
+00102$:
+ C$demo_c_0.c$32$2$2 ==.
+; demo_c_0.c:32: for(i=0; i<255; i++) {
+ clr a
+ mov _i,a
+ mov (_i + 1),a
+00104$:
+ clr c
+ mov a,_i
+ subb a,#0xFF
+ mov a,(_i + 1)
+ xrl a,#0x80
+ subb a,#0x80
+ jnc 00107$
+ C$demo_c_0.c$33$3$3 ==.
+; demo_c_0.c:33: someFunction(i+2);
+ mov r2,_i
+ mov a,#0x02
+ add a,r2
+ mov dpl,a
+ lcall _someFunction
+ C$demo_c_0.c$34$3$3 ==.
+; demo_c_0.c:34: some_variable++;
+ inc _some_variable
+ clr a
+ cjne a,_some_variable,00114$
+ inc (_some_variable + 1)
+ cjne a,(_some_variable + 1),00114$
+ inc (_some_variable + 2)
+ cjne a,(_some_variable + 2),00114$
+ inc (_some_variable + 3)
+00114$:
+ C$demo_c_0.c$32$2$2 ==.
+; demo_c_0.c:32: for(i=0; i<255; i++) {
+ inc _i
+ clr a
+ cjne a,_i,00104$
+ inc (_i + 1)
+ sjmp 00104$
+00107$:
+ C$demo_c_0.c$36$2$2 ==.
+; demo_c_0.c:36: some_variable-=22;
+ mov a,_some_variable
+ add a,#0xea
+ mov _some_variable,a
+ mov a,(_some_variable + 1)
+ addc a,#0xff
+ mov (_some_variable + 1),a
+ mov a,(_some_variable + 2)
+ addc a,#0xff
+ mov (_some_variable + 2),a
+ mov a,(_some_variable + 3)
+ addc a,#0xff
+ mov (_some_variable + 3),a
+ C$demo_c_0.c$40$1$1 ==.
+; demo_c_0.c:40: return 0;
+ C$demo_c_0.c$41$1$1 ==.
+ XG$main$0$0 ==.
+ sjmp 00102$
+ .area CSEG (CODE)
+ .area CONST (CODE)
+ .area XINIT (CODE)
+ .area CABS (ABS,CODE)
diff --git a/demo/demo_c_0.c b/demo/demo_c_0.c
new file mode 100644
index 0000000..9655334
--- /dev/null
+++ b/demo/demo_c_0.c
@@ -0,0 +1,41 @@
+/**
+ * Very very simple demonstration code written in C language
+ * @file demo_c_0.c
+ */
+
+// This file defines registers avaliable in AT89x51 MCUs
+// See /usr/share/sdcc/include/mcs51/ for alternatives
+#include <at89x51.h>
+
+unsigned long some_variable=0; ///< Documentation for this variable comes here
+int i; ///< General purpose interator
+
+/**
+ * These lines are a doxygen documentation for this function
+ * See doxygen manual for more details (http://www.stack.nl/~dimitri/doxygen/manual.html)
+ * Note: Try to click on the 1st line of the function declaration and then press Ctrl+E
+ * <b style="color: #FF0000">Some bold text</b>
+ * @param somevalue Some agrument
+ */
+void someFunction(unsigned char somevalue)
+{
+ // P1 and P3 are variables defined in "at89x51.h"
+ P1=somevalue;
+ P3=somevalue^0xFF;
+}
+
+/** Main loop */
+int main()
+{
+ // Infinite loop
+ while(1) {
+ for(i=0; i<255; i++) {
+ someFunction(i+2);
+ some_variable++;
+ }
+ some_variable-=22;
+ }
+
+ // Report success
+ return 0;
+}
diff --git a/demo/demo_c_0.cdb b/demo/demo_c_0.cdb
new file mode 100644
index 0000000..8886635
--- /dev/null
+++ b/demo/demo_c_0.cdb
@@ -0,0 +1,278 @@
+M:demo_c_0
+F:G$someFunction$0$0({2}DF,SV:S),C,0,0,0,0,0
+F:G$main$0$0({2}DF,SI:S),C,0,0,0,0,0
+F:G$main$0$0({2}DF,SI:S),C,0,0,0,0,0
+S:G$some_variable$0$0({4}SL:U),E,0,0
+S:G$i$0$0({2}SI:S),E,0,0
+S:LsomeFunction$somevalue$1$1({1}SC:U),R,0,0,[r2]
+S:G$P0$0$0({1}SC:U),I,0,0
+S:G$SP$0$0({1}SC:U),I,0,0
+S:G$DPL$0$0({1}SC:U),I,0,0
+S:G$DPH$0$0({1}SC:U),I,0,0
+S:G$PCON$0$0({1}SC:U),I,0,0
+S:G$TCON$0$0({1}SC:U),I,0,0
+S:G$TMOD$0$0({1}SC:U),I,0,0
+S:G$TL0$0$0({1}SC:U),I,0,0
+S:G$TL1$0$0({1}SC:U),I,0,0
+S:G$TH0$0$0({1}SC:U),I,0,0
+S:G$TH1$0$0({1}SC:U),I,0,0
+S:G$P1$0$0({1}SC:U),I,0,0
+S:G$SCON$0$0({1}SC:U),I,0,0
+S:G$SBUF$0$0({1}SC:U),I,0,0
+S:G$P2$0$0({1}SC:U),I,0,0
+S:G$IE$0$0({1}SC:U),I,0,0
+S:G$P3$0$0({1}SC:U),I,0,0
+S:G$IP$0$0({1}SC:U),I,0,0
+S:G$PSW$0$0({1}SC:U),I,0,0
+S:G$ACC$0$0({1}SC:U),I,0,0
+S:G$A$0$0({1}SC:U),I,0,0
+S:G$B$0$0({1}SC:U),I,0,0
+S:G$P0_0$0$0({1}SX:U),J,0,0
+S:G$P0_1$0$0({1}SX:U),J,0,0
+S:G$P0_2$0$0({1}SX:U),J,0,0
+S:G$P0_3$0$0({1}SX:U),J,0,0
+S:G$P0_4$0$0({1}SX:U),J,0,0
+S:G$P0_5$0$0({1}SX:U),J,0,0
+S:G$P0_6$0$0({1}SX:U),J,0,0
+S:G$P0_7$0$0({1}SX:U),J,0,0
+S:G$IT0$0$0({1}SX:U),J,0,0
+S:G$IE0$0$0({1}SX:U),J,0,0
+S:G$IT1$0$0({1}SX:U),J,0,0
+S:G$IE1$0$0({1}SX:U),J,0,0
+S:G$TR0$0$0({1}SX:U),J,0,0
+S:G$TF0$0$0({1}SX:U),J,0,0
+S:G$TR1$0$0({1}SX:U),J,0,0
+S:G$TF1$0$0({1}SX:U),J,0,0
+S:G$P1_0$0$0({1}SX:U),J,0,0
+S:G$P1_1$0$0({1}SX:U),J,0,0
+S:G$P1_2$0$0({1}SX:U),J,0,0
+S:G$P1_3$0$0({1}SX:U),J,0,0
+S:G$P1_4$0$0({1}SX:U),J,0,0
+S:G$P1_5$0$0({1}SX:U),J,0,0
+S:G$P1_6$0$0({1}SX:U),J,0,0
+S:G$P1_7$0$0({1}SX:U),J,0,0
+S:G$RI$0$0({1}SX:U),J,0,0
+S:G$TI$0$0({1}SX:U),J,0,0
+S:G$RB8$0$0({1}SX:U),J,0,0
+S:G$TB8$0$0({1}SX:U),J,0,0
+S:G$REN$0$0({1}SX:U),J,0,0
+S:G$SM2$0$0({1}SX:U),J,0,0
+S:G$SM1$0$0({1}SX:U),J,0,0
+S:G$SM0$0$0({1}SX:U),J,0,0
+S:G$P2_0$0$0({1}SX:U),J,0,0
+S:G$P2_1$0$0({1}SX:U),J,0,0
+S:G$P2_2$0$0({1}SX:U),J,0,0
+S:G$P2_3$0$0({1}SX:U),J,0,0
+S:G$P2_4$0$0({1}SX:U),J,0,0
+S:G$P2_5$0$0({1}SX:U),J,0,0
+S:G$P2_6$0$0({1}SX:U),J,0,0
+S:G$P2_7$0$0({1}SX:U),J,0,0
+S:G$EX0$0$0({1}SX:U),J,0,0
+S:G$ET0$0$0({1}SX:U),J,0,0
+S:G$EX1$0$0({1}SX:U),J,0,0
+S:G$ET1$0$0({1}SX:U),J,0,0
+S:G$ES$0$0({1}SX:U),J,0,0
+S:G$EA$0$0({1}SX:U),J,0,0
+S:G$P3_0$0$0({1}SX:U),J,0,0
+S:G$P3_1$0$0({1}SX:U),J,0,0
+S:G$P3_2$0$0({1}SX:U),J,0,0
+S:G$P3_3$0$0({1}SX:U),J,0,0
+S:G$P3_4$0$0({1}SX:U),J,0,0
+S:G$P3_5$0$0({1}SX:U),J,0,0
+S:G$P3_6$0$0({1}SX:U),J,0,0
+S:G$P3_7$0$0({1}SX:U),J,0,0
+S:G$RXD$0$0({1}SX:U),J,0,0
+S:G$TXD$0$0({1}SX:U),J,0,0
+S:G$INT0$0$0({1}SX:U),J,0,0
+S:G$INT1$0$0({1}SX:U),J,0,0
+S:G$T0$0$0({1}SX:U),J,0,0
+S:G$T1$0$0({1}SX:U),J,0,0
+S:G$WR$0$0({1}SX:U),J,0,0
+S:G$RD$0$0({1}SX:U),J,0,0
+S:G$PX0$0$0({1}SX:U),J,0,0
+S:G$PT0$0$0({1}SX:U),J,0,0
+S:G$PX1$0$0({1}SX:U),J,0,0
+S:G$PT1$0$0({1}SX:U),J,0,0
+S:G$PS$0$0({1}SX:U),J,0,0
+S:G$P$0$0({1}SX:U),J,0,0
+S:G$FL$0$0({1}SX:U),J,0,0
+S:G$OV$0$0({1}SX:U),J,0,0
+S:G$RS0$0$0({1}SX:U),J,0,0
+S:G$RS1$0$0({1}SX:U),J,0,0
+S:G$F0$0$0({1}SX:U),J,0,0
+S:G$AC$0$0({1}SX:U),J,0,0
+S:G$CY$0$0({1}SX:U),J,0,0
+S:G$someFunction$0$0({2}DF,SV:S),C,0,0
+S:G$main$0$0({2}DF,SI:S),C,0,0
+L:G$P0$0$0:80
+L:G$P0_0$0$0:80
+L:G$P0_1$0$0:81
+L:G$SP$0$0:81
+L:G$DPL$0$0:82
+L:G$P0_2$0$0:82
+L:G$DPH$0$0:83
+L:G$P0_3$0$0:83
+L:G$P0_4$0$0:84
+L:G$P0_5$0$0:85
+L:G$P0_6$0$0:86
+L:G$P0_7$0$0:87
+L:G$PCON$0$0:87
+L:G$IT0$0$0:88
+L:G$TCON$0$0:88
+L:G$IE0$0$0:89
+L:G$TMOD$0$0:89
+L:G$IT1$0$0:8A
+L:G$TL0$0$0:8A
+L:G$IE1$0$0:8B
+L:G$TL1$0$0:8B
+L:G$TH0$0$0:8C
+L:G$TR0$0$0:8C
+L:G$TF0$0$0:8D
+L:G$TH1$0$0:8D
+L:G$TR1$0$0:8E
+L:G$TF1$0$0:8F
+L:G$P1$0$0:90
+L:G$P1_0$0$0:90
+L:G$P1_1$0$0:91
+L:G$P1_2$0$0:92
+L:G$P1_3$0$0:93
+L:G$P1_4$0$0:94
+L:G$P1_5$0$0:95
+L:G$P1_6$0$0:96
+L:G$P1_7$0$0:97
+L:G$RI$0$0:98
+L:G$SCON$0$0:98
+L:G$SBUF$0$0:99
+L:G$TI$0$0:99
+L:G$RB8$0$0:9A
+L:G$TB8$0$0:9B
+L:G$REN$0$0:9C
+L:G$SM2$0$0:9D
+L:G$SM1$0$0:9E
+L:G$SM0$0$0:9F
+L:G$P2$0$0:A0
+L:G$P2_0$0$0:A0
+L:G$P2_1$0$0:A1
+L:G$P2_2$0$0:A2
+L:G$P2_3$0$0:A3
+L:G$P2_4$0$0:A4
+L:G$P2_5$0$0:A5
+L:G$P2_6$0$0:A6
+L:G$P2_7$0$0:A7
+L:G$EX0$0$0:A8
+L:G$IE$0$0:A8
+L:G$ET0$0$0:A9
+L:G$EX1$0$0:AA
+L:G$ET1$0$0:AB
+L:G$ES$0$0:AC
+L:G$EA$0$0:AF
+L:G$P3$0$0:B0
+L:G$P3_0$0$0:B0
+L:G$RXD$0$0:B0
+L:G$P3_1$0$0:B1
+L:G$TXD$0$0:B1
+L:G$INT0$0$0:B2
+L:G$P3_2$0$0:B2
+L:G$INT1$0$0:B3
+L:G$P3_3$0$0:B3
+L:G$P3_4$0$0:B4
+L:G$T0$0$0:B4
+L:G$P3_5$0$0:B5
+L:G$T1$0$0:B5
+L:G$P3_6$0$0:B6
+L:G$WR$0$0:B6
+L:G$P3_7$0$0:B7
+L:G$RD$0$0:B7
+L:G$IP$0$0:B8
+L:G$PX0$0$0:B8
+L:G$PT0$0$0:B9
+L:G$PX1$0$0:BA
+L:G$PT1$0$0:BB
+L:G$PS$0$0:BC
+L:G$P$0$0:D0
+L:G$PSW$0$0:D0
+L:G$FL$0$0:D1
+L:G$OV$0$0:D2
+L:G$RS0$0$0:D3
+L:G$RS1$0$0:D4
+L:G$F0$0$0:D5
+L:G$AC$0$0:D6
+L:G$CY$0$0:D7
+L:G$A$0$0:E0
+L:G$ACC$0$0:E0
+L:G$B$0$0:F0
+L:G$some_variable$0$0:8
+L:G$i$0$0:C
+L:A$demo_c_0$385:0
+L:A$demo_c_0$415:3
+L:A$demo_c_0$417:6
+L:A$demo_c_0$402:61
+L:C$demo_c_0.c$10$1$1:61
+L:A$demo_c_0$403:62
+L:A$demo_c_0$404:64
+L:A$demo_c_0$405:66
+L:A$demo_c_0$406:68
+L:A$demo_c_0$408:6A
+L:A$demo_c_0$442:6D
+L:C$demo_c_0.c$20$0$0:6D
+L:G$someFunction$0$0:6D
+L:A$demo_c_0$445:6F
+L:C$demo_c_0.c$23$1$1:6F
+L:A$demo_c_0$448:71
+L:C$demo_c_0.c$24$1$1:71
+L:A$demo_c_0$449:73
+L:A$demo_c_0$450:74
+L:A$demo_c_0$453:76
+L:C$demo_c_0.c$25$1$1:76
+L:XG$someFunction$0$0:76
+L:A$demo_c_0$470:77
+L:C$demo_c_0.c$28$1$1:77
+L:C$demo_c_0.c$31$1$1:77
+L:G$main$0$0:77
+L:A$demo_c_0$471:78
+L:A$demo_c_0$472:7A
+L:A$demo_c_0$474:7C
+L:A$demo_c_0$475:7D
+L:A$demo_c_0$476:7F
+L:A$demo_c_0$477:81
+L:A$demo_c_0$478:83
+L:A$demo_c_0$479:85
+L:A$demo_c_0$480:87
+L:A$demo_c_0$483:89
+L:C$demo_c_0.c$33$3$3:89
+L:A$demo_c_0$484:8B
+L:A$demo_c_0$485:8D
+L:A$demo_c_0$486:8E
+L:A$demo_c_0$487:90
+L:A$demo_c_0$490:93
+L:C$demo_c_0.c$34$3$3:93
+L:A$demo_c_0$491:95
+L:A$demo_c_0$492:96
+L:A$demo_c_0$493:99
+L:A$demo_c_0$494:9B
+L:A$demo_c_0$495:9E
+L:A$demo_c_0$496:A0
+L:A$demo_c_0$497:A3
+L:A$demo_c_0$501:A5
+L:C$demo_c_0.c$32$2$2:A5
+L:A$demo_c_0$502:A7
+L:A$demo_c_0$503:A8
+L:A$demo_c_0$504:AB
+L:A$demo_c_0$505:AD
+L:A$demo_c_0$509:AF
+L:C$demo_c_0.c$36$2$2:AF
+L:A$demo_c_0$510:B1
+L:A$demo_c_0$511:B3
+L:A$demo_c_0$512:B5
+L:A$demo_c_0$513:B7
+L:A$demo_c_0$514:B9
+L:A$demo_c_0$515:BB
+L:A$demo_c_0$516:BD
+L:A$demo_c_0$517:BF
+L:A$demo_c_0$518:C1
+L:A$demo_c_0$519:C3
+L:A$demo_c_0$520:C5
+L:A$demo_c_0$525:C7
+L:C$demo_c_0.c$40$1$1:C7
+L:C$demo_c_0.c$41$1$1:C7
+L:XG$main$0$0:C7
diff --git a/demo/demo_c_0.hashes b/demo/demo_c_0.hashes
new file mode 100644
index 0000000..aa19cb5
--- /dev/null
+++ b/demo/demo_c_0.hashes
@@ -0,0 +1 @@
+79C98C5ADE29831807D59F6BC438063A "demo_c_0.c"
diff --git a/demo/demo_c_0.hex b/demo/demo_c_0.hex
new file mode 100644
index 0000000..6160cd7
--- /dev/null
+++ b/demo/demo_c_0.hex
@@ -0,0 +1,34 @@
+:03000000020008F3
+:06006100E4F508F509F5C5
+:030067000AF50B8C
+:03006A000200038E
+:0500030012007780FEF1
+:0A006D00AA828A9074FF6AF5B0229F
+:05007700E4F50CF50D9D
+:0A007C00C3E50C94FFE50D648094C9
+:0B008600805026AA0C74022AF582129A
+:06009100006D0508E4B556
+:05009700080C0509B58D
+:05009C000907050AB58B
+:0400A1000A02050B3F
+:0700A500050CE4B50CD105C8
+:0300AC000D80CDF7
+:0700AF00E50824EAF508E56D
+:0600B6000934FFF509E525
+:0600BC000A34FFF50AE51D
+:0700C2000B34FFF50B80AECB
+:06003700E478FFF6D8FD9D
+:080015007900E94400601B7A48
+:05001D00009000CD7809
+:030022000075A0C6
+:0A00250000E493F2A308B8000205FE
+:08002F00A0D9F4DAF275A0FF7C
+:08003D007800E84400600A7934
+:030045000075A0A3
+:0600480000E4F309D8FCFE
+:08004E007800E84400600C7921
+:0B00560000900000E4F0A3D8FCD9FAF1
+:0300080075810DF2
+:0A000B001200C9E582600302000341
+:0400C900758200221A
+:00000001FF
diff --git a/demo/demo_c_0.ihx b/demo/demo_c_0.ihx
new file mode 100644
index 0000000..6160cd7
--- /dev/null
+++ b/demo/demo_c_0.ihx
@@ -0,0 +1,34 @@
+:03000000020008F3
+:06006100E4F508F509F5C5
+:030067000AF50B8C
+:03006A000200038E
+:0500030012007780FEF1
+:0A006D00AA828A9074FF6AF5B0229F
+:05007700E4F50CF50D9D
+:0A007C00C3E50C94FFE50D648094C9
+:0B008600805026AA0C74022AF582129A
+:06009100006D0508E4B556
+:05009700080C0509B58D
+:05009C000907050AB58B
+:0400A1000A02050B3F
+:0700A500050CE4B50CD105C8
+:0300AC000D80CDF7
+:0700AF00E50824EAF508E56D
+:0600B6000934FFF509E525
+:0600BC000A34FFF50AE51D
+:0700C2000B34FFF50B80AECB
+:06003700E478FFF6D8FD9D
+:080015007900E94400601B7A48
+:05001D00009000CD7809
+:030022000075A0C6
+:0A00250000E493F2A308B8000205FE
+:08002F00A0D9F4DAF275A0FF7C
+:08003D007800E84400600A7934
+:030045000075A0A3
+:0600480000E4F309D8FCFE
+:08004E007800E84400600C7921
+:0B00560000900000E4F0A3D8FCD9FAF1
+:0300080075810DF2
+:0A000B001200C9E582600302000341
+:0400C900758200221A
+:00000001FF
diff --git a/demo/demo_c_0.lnk b/demo/demo_c_0.lnk
new file mode 100644
index 0000000..4e51a94
--- /dev/null
+++ b/demo/demo_c_0.lnk
@@ -0,0 +1,19 @@
+-myuxi
+-Y
+-a 0x0100
+-v 0x0000
+-w 0x0800
+-z
+-b HOME = 0x0000
+-b ISEG = 0x0000
+-b BSEG = 0x0000
+-k /usr/libexec/sdcc/../share/sdcc/lib/small
+-k /usr/share/sdcc/lib/small
+-l mcs51
+-l libsdcc
+-l libint
+-l liblong
+-l libfloat
+demo_c_0.rel
+
+-e
diff --git a/demo/demo_c_0.lst b/demo/demo_c_0.lst
new file mode 100644
index 0000000..ec4c901
--- /dev/null
+++ b/demo/demo_c_0.lst
@@ -0,0 +1,529 @@
+ 1 ;--------------------------------------------------------
+ 2 ; File Created by SDCC : free open source ANSI-C Compiler
+ 3 ; Version 2.9.0 #5416 (Oct 6 2009) (UNIX)
+ 4 ; This file was generated Tue Oct 27 23:03:10 2009
+ 5 ;--------------------------------------------------------
+ 6 .module demo_c_0
+ 7 .optsdcc -mmcs51 --model-small
+ 8
+ 9 ;--------------------------------------------------------
+ 10 ; Public variables in this module
+ 11 ;--------------------------------------------------------
+ 12 .globl _main
+ 13 .globl _someFunction
+ 14 .globl _CY
+ 15 .globl _AC
+ 16 .globl _F0
+ 17 .globl _RS1
+ 18 .globl _RS0
+ 19 .globl _OV
+ 20 .globl _FL
+ 21 .globl _P
+ 22 .globl _PS
+ 23 .globl _PT1
+ 24 .globl _PX1
+ 25 .globl _PT0
+ 26 .globl _PX0
+ 27 .globl _RD
+ 28 .globl _WR
+ 29 .globl _T1
+ 30 .globl _T0
+ 31 .globl _INT1
+ 32 .globl _INT0
+ 33 .globl _TXD
+ 34 .globl _RXD
+ 35 .globl _P3_7
+ 36 .globl _P3_6
+ 37 .globl _P3_5
+ 38 .globl _P3_4
+ 39 .globl _P3_3
+ 40 .globl _P3_2
+ 41 .globl _P3_1
+ 42 .globl _P3_0
+ 43 .globl _EA
+ 44 .globl _ES
+ 45 .globl _ET1
+ 46 .globl _EX1
+ 47 .globl _ET0
+ 48 .globl _EX0
+ 49 .globl _P2_7
+ 50 .globl _P2_6
+ 51 .globl _P2_5
+ 52 .globl _P2_4
+ 53 .globl _P2_3
+ 54 .globl _P2_2
+ 55 .globl _P2_1
+ 56 .globl _P2_0
+ 57 .globl _SM0
+ 58 .globl _SM1
+ 59 .globl _SM2
+ 60 .globl _REN
+ 61 .globl _TB8
+ 62 .globl _RB8
+ 63 .globl _TI
+ 64 .globl _RI
+ 65 .globl _P1_7
+ 66 .globl _P1_6
+ 67 .globl _P1_5
+ 68 .globl _P1_4
+ 69 .globl _P1_3
+ 70 .globl _P1_2
+ 71 .globl _P1_1
+ 72 .globl _P1_0
+ 73 .globl _TF1
+ 74 .globl _TR1
+ 75 .globl _TF0
+ 76 .globl _TR0
+ 77 .globl _IE1
+ 78 .globl _IT1
+ 79 .globl _IE0
+ 80 .globl _IT0
+ 81 .globl _P0_7
+ 82 .globl _P0_6
+ 83 .globl _P0_5
+ 84 .globl _P0_4
+ 85 .globl _P0_3
+ 86 .globl _P0_2
+ 87 .globl _P0_1
+ 88 .globl _P0_0
+ 89 .globl _B
+ 90 .globl _A
+ 91 .globl _ACC
+ 92 .globl _PSW
+ 93 .globl _IP
+ 94 .globl _P3
+ 95 .globl _IE
+ 96 .globl _P2
+ 97 .globl _SBUF
+ 98 .globl _SCON
+ 99 .globl _P1
+ 100 .globl _TH1
+ 101 .globl _TH0
+ 102 .globl _TL1
+ 103 .globl _TL0
+ 104 .globl _TMOD
+ 105 .globl _TCON
+ 106 .globl _PCON
+ 107 .globl _DPH
+ 108 .globl _DPL
+ 109 .globl _SP
+ 110 .globl _P0
+ 111 .globl _i
+ 112 .globl _some_variable
+ 113 ;--------------------------------------------------------
+ 114 ; special function registers
+ 115 ;--------------------------------------------------------
+ 116 .area RSEG (DATA)
+ 0080 117 G$P0$0$0 == 0x0080
+ 0080 118 _P0 = 0x0080
+ 0081 119 G$SP$0$0 == 0x0081
+ 0081 120 _SP = 0x0081
+ 0082 121 G$DPL$0$0 == 0x0082
+ 0082 122 _DPL = 0x0082
+ 0083 123 G$DPH$0$0 == 0x0083
+ 0083 124 _DPH = 0x0083
+ 0087 125 G$PCON$0$0 == 0x0087
+ 0087 126 _PCON = 0x0087
+ 0088 127 G$TCON$0$0 == 0x0088
+ 0088 128 _TCON = 0x0088
+ 0089 129 G$TMOD$0$0 == 0x0089
+ 0089 130 _TMOD = 0x0089
+ 008A 131 G$TL0$0$0 == 0x008a
+ 008A 132 _TL0 = 0x008a
+ 008B 133 G$TL1$0$0 == 0x008b
+ 008B 134 _TL1 = 0x008b
+ 008C 135 G$TH0$0$0 == 0x008c
+ 008C 136 _TH0 = 0x008c
+ 008D 137 G$TH1$0$0 == 0x008d
+ 008D 138 _TH1 = 0x008d
+ 0090 139 G$P1$0$0 == 0x0090
+ 0090 140 _P1 = 0x0090
+ 0098 141 G$SCON$0$0 == 0x0098
+ 0098 142 _SCON = 0x0098
+ 0099 143 G$SBUF$0$0 == 0x0099
+ 0099 144 _SBUF = 0x0099
+ 00A0 145 G$P2$0$0 == 0x00a0
+ 00A0 146 _P2 = 0x00a0
+ 00A8 147 G$IE$0$0 == 0x00a8
+ 00A8 148 _IE = 0x00a8
+ 00B0 149 G$P3$0$0 == 0x00b0
+ 00B0 150 _P3 = 0x00b0
+ 00B8 151 G$IP$0$0 == 0x00b8
+ 00B8 152 _IP = 0x00b8
+ 00D0 153 G$PSW$0$0 == 0x00d0
+ 00D0 154 _PSW = 0x00d0
+ 00E0 155 G$ACC$0$0 == 0x00e0
+ 00E0 156 _ACC = 0x00e0
+ 00E0 157 G$A$0$0 == 0x00e0
+ 00E0 158 _A = 0x00e0
+ 00F0 159 G$B$0$0 == 0x00f0
+ 00F0 160 _B = 0x00f0
+ 161 ;--------------------------------------------------------
+ 162 ; special function bits
+ 163 ;--------------------------------------------------------
+ 164 .area RSEG (DATA)
+ 0080 165 G$P0_0$0$0 == 0x0080
+ 0080 166 _P0_0 = 0x0080
+ 0081 167 G$P0_1$0$0 == 0x0081
+ 0081 168 _P0_1 = 0x0081
+ 0082 169 G$P0_2$0$0 == 0x0082
+ 0082 170 _P0_2 = 0x0082
+ 0083 171 G$P0_3$0$0 == 0x0083
+ 0083 172 _P0_3 = 0x0083
+ 0084 173 G$P0_4$0$0 == 0x0084
+ 0084 174 _P0_4 = 0x0084
+ 0085 175 G$P0_5$0$0 == 0x0085
+ 0085 176 _P0_5 = 0x0085
+ 0086 177 G$P0_6$0$0 == 0x0086
+ 0086 178 _P0_6 = 0x0086
+ 0087 179 G$P0_7$0$0 == 0x0087
+ 0087 180 _P0_7 = 0x0087
+ 0088 181 G$IT0$0$0 == 0x0088
+ 0088 182 _IT0 = 0x0088
+ 0089 183 G$IE0$0$0 == 0x0089
+ 0089 184 _IE0 = 0x0089
+ 008A 185 G$IT1$0$0 == 0x008a
+ 008A 186 _IT1 = 0x008a
+ 008B 187 G$IE1$0$0 == 0x008b
+ 008B 188 _IE1 = 0x008b
+ 008C 189 G$TR0$0$0 == 0x008c
+ 008C 190 _TR0 = 0x008c
+ 008D 191 G$TF0$0$0 == 0x008d
+ 008D 192 _TF0 = 0x008d
+ 008E 193 G$TR1$0$0 == 0x008e
+ 008E 194 _TR1 = 0x008e
+ 008F 195 G$TF1$0$0 == 0x008f
+ 008F 196 _TF1 = 0x008f
+ 0090 197 G$P1_0$0$0 == 0x0090
+ 0090 198 _P1_0 = 0x0090
+ 0091 199 G$P1_1$0$0 == 0x0091
+ 0091 200 _P1_1 = 0x0091
+ 0092 201 G$P1_2$0$0 == 0x0092
+ 0092 202 _P1_2 = 0x0092
+ 0093 203 G$P1_3$0$0 == 0x0093
+ 0093 204 _P1_3 = 0x0093
+ 0094 205 G$P1_4$0$0 == 0x0094
+ 0094 206 _P1_4 = 0x0094
+ 0095 207 G$P1_5$0$0 == 0x0095
+ 0095 208 _P1_5 = 0x0095
+ 0096 209 G$P1_6$0$0 == 0x0096
+ 0096 210 _P1_6 = 0x0096
+ 0097 211 G$P1_7$0$0 == 0x0097
+ 0097 212 _P1_7 = 0x0097
+ 0098 213 G$RI$0$0 == 0x0098
+ 0098 214 _RI = 0x0098
+ 0099 215 G$TI$0$0 == 0x0099
+ 0099 216 _TI = 0x0099
+ 009A 217 G$RB8$0$0 == 0x009a
+ 009A 218 _RB8 = 0x009a
+ 009B 219 G$TB8$0$0 == 0x009b
+ 009B 220 _TB8 = 0x009b
+ 009C 221 G$REN$0$0 == 0x009c
+ 009C 222 _REN = 0x009c
+ 009D 223 G$SM2$0$0 == 0x009d
+ 009D 224 _SM2 = 0x009d
+ 009E 225 G$SM1$0$0 == 0x009e
+ 009E 226 _SM1 = 0x009e
+ 009F 227 G$SM0$0$0 == 0x009f
+ 009F 228 _SM0 = 0x009f
+ 00A0 229 G$P2_0$0$0 == 0x00a0
+ 00A0 230 _P2_0 = 0x00a0
+ 00A1 231 G$P2_1$0$0 == 0x00a1
+ 00A1 232 _P2_1 = 0x00a1
+ 00A2 233 G$P2_2$0$0 == 0x00a2
+ 00A2 234 _P2_2 = 0x00a2
+ 00A3 235 G$P2_3$0$0 == 0x00a3
+ 00A3 236 _P2_3 = 0x00a3
+ 00A4 237 G$P2_4$0$0 == 0x00a4
+ 00A4 238 _P2_4 = 0x00a4
+ 00A5 239 G$P2_5$0$0 == 0x00a5
+ 00A5 240 _P2_5 = 0x00a5
+ 00A6 241 G$P2_6$0$0 == 0x00a6
+ 00A6 242 _P2_6 = 0x00a6
+ 00A7 243 G$P2_7$0$0 == 0x00a7
+ 00A7 244 _P2_7 = 0x00a7
+ 00A8 245 G$EX0$0$0 == 0x00a8
+ 00A8 246 _EX0 = 0x00a8
+ 00A9 247 G$ET0$0$0 == 0x00a9
+ 00A9 248 _ET0 = 0x00a9
+ 00AA 249 G$EX1$0$0 == 0x00aa
+ 00AA 250 _EX1 = 0x00aa
+ 00AB 251 G$ET1$0$0 == 0x00ab
+ 00AB 252 _ET1 = 0x00ab
+ 00AC 253 G$ES$0$0 == 0x00ac
+ 00AC 254 _ES = 0x00ac
+ 00AF 255 G$EA$0$0 == 0x00af
+ 00AF 256 _EA = 0x00af
+ 00B0 257 G$P3_0$0$0 == 0x00b0
+ 00B0 258 _P3_0 = 0x00b0
+ 00B1 259 G$P3_1$0$0 == 0x00b1
+ 00B1 260 _P3_1 = 0x00b1
+ 00B2 261 G$P3_2$0$0 == 0x00b2
+ 00B2 262 _P3_2 = 0x00b2
+ 00B3 263 G$P3_3$0$0 == 0x00b3
+ 00B3 264 _P3_3 = 0x00b3
+ 00B4 265 G$P3_4$0$0 == 0x00b4
+ 00B4 266 _P3_4 = 0x00b4
+ 00B5 267 G$P3_5$0$0 == 0x00b5
+ 00B5 268 _P3_5 = 0x00b5
+ 00B6 269 G$P3_6$0$0 == 0x00b6
+ 00B6 270 _P3_6 = 0x00b6
+ 00B7 271 G$P3_7$0$0 == 0x00b7
+ 00B7 272 _P3_7 = 0x00b7
+ 00B0 273 G$RXD$0$0 == 0x00b0
+ 00B0 274 _RXD = 0x00b0
+ 00B1 275 G$TXD$0$0 == 0x00b1
+ 00B1 276 _TXD = 0x00b1
+ 00B2 277 G$INT0$0$0 == 0x00b2
+ 00B2 278 _INT0 = 0x00b2
+ 00B3 279 G$INT1$0$0 == 0x00b3
+ 00B3 280 _INT1 = 0x00b3
+ 00B4 281 G$T0$0$0 == 0x00b4
+ 00B4 282 _T0 = 0x00b4
+ 00B5 283 G$T1$0$0 == 0x00b5
+ 00B5 284 _T1 = 0x00b5
+ 00B6 285 G$WR$0$0 == 0x00b6
+ 00B6 286 _WR = 0x00b6
+ 00B7 287 G$RD$0$0 == 0x00b7
+ 00B7 288 _RD = 0x00b7
+ 00B8 289 G$PX0$0$0 == 0x00b8
+ 00B8 290 _PX0 = 0x00b8
+ 00B9 291 G$PT0$0$0 == 0x00b9
+ 00B9 292 _PT0 = 0x00b9
+ 00BA 293 G$PX1$0$0 == 0x00ba
+ 00BA 294 _PX1 = 0x00ba
+ 00BB 295 G$PT1$0$0 == 0x00bb
+ 00BB 296 _PT1 = 0x00bb
+ 00BC 297 G$PS$0$0 == 0x00bc
+ 00BC 298 _PS = 0x00bc
+ 00D0 299 G$P$0$0 == 0x00d0
+ 00D0 300 _P = 0x00d0
+ 00D1 301 G$FL$0$0 == 0x00d1
+ 00D1 302 _FL = 0x00d1
+ 00D2 303 G$OV$0$0 == 0x00d2
+ 00D2 304 _OV = 0x00d2
+ 00D3 305 G$RS0$0$0 == 0x00d3
+ 00D3 306 _RS0 = 0x00d3
+ 00D4 307 G$RS1$0$0 == 0x00d4
+ 00D4 308 _RS1 = 0x00d4
+ 00D5 309 G$F0$0$0 == 0x00d5
+ 00D5 310 _F0 = 0x00d5
+ 00D6 311 G$AC$0$0 == 0x00d6
+ 00D6 312 _AC = 0x00d6
+ 00D7 313 G$CY$0$0 == 0x00d7
+ 00D7 314 _CY = 0x00d7
+ 315 ;--------------------------------------------------------
+ 316 ; overlayable register banks
+ 317 ;--------------------------------------------------------
+ 318 .area REG_BANK_0 (REL,OVR,DATA)
+ 0000 319 .ds 8
+ 320 ;--------------------------------------------------------
+ 321 ; internal ram data
+ 322 ;--------------------------------------------------------
+ 323 .area DSEG (DATA)
+ 0000 324 G$some_variable$0$0==.
+ 0000 325 _some_variable::
+ 0000 326 .ds 4
+ 0004 327 G$i$0$0==.
+ 0004 328 _i::
+ 0004 329 .ds 2
+ 330 ;--------------------------------------------------------
+ 331 ; overlayable items in internal ram
+ 332 ;--------------------------------------------------------
+ 333 .area OSEG (OVR,DATA)
+ 334 ;--------------------------------------------------------
+ 335 ; Stack segment in internal ram
+ 336 ;--------------------------------------------------------
+ 337 .area SSEG (DATA)
+ 0000 338 __start__stack:
+ 0000 339 .ds 1
+ 340
+ 341 ;--------------------------------------------------------
+ 342 ; indirectly addressable internal ram data
+ 343 ;--------------------------------------------------------
+ 344 .area ISEG (DATA)
+ 345 ;--------------------------------------------------------
+ 346 ; absolute internal ram data
+ 347 ;--------------------------------------------------------
+ 348 .area IABS (ABS,DATA)
+ 349 .area IABS (ABS,DATA)
+ 350 ;--------------------------------------------------------
+ 351 ; bit data
+ 352 ;--------------------------------------------------------
+ 353 .area BSEG (BIT)
+ 354 ;--------------------------------------------------------
+ 355 ; paged external ram data
+ 356 ;--------------------------------------------------------
+ 357 .area PSEG (PAG,XDATA)
+ 358 ;--------------------------------------------------------
+ 359 ; external ram data
+ 360 ;--------------------------------------------------------
+ 361 .area XSEG (XDATA)
+ 362 ;--------------------------------------------------------
+ 363 ; absolute external ram data
+ 364 ;--------------------------------------------------------
+ 365 .area XABS (ABS,XDATA)
+ 366 ;--------------------------------------------------------
+ 367 ; external initialized ram data
+ 368 ;--------------------------------------------------------
+ 369 .area XISEG (XDATA)
+ 370 .area HOME (CODE)
+ 371 .area GSINIT0 (CODE)
+ 372 .area GSINIT1 (CODE)
+ 373 .area GSINIT2 (CODE)
+ 374 .area GSINIT3 (CODE)
+ 375 .area GSINIT4 (CODE)
+ 376 .area GSINIT5 (CODE)
+ 377 .area GSINIT (CODE)
+ 378 .area GSFINAL (CODE)
+ 379 .area CSEG (CODE)
+ 380 ;--------------------------------------------------------
+ 381 ; interrupt vector
+ 382 ;--------------------------------------------------------
+ 383 .area HOME (CODE)
+ 0000 384 __interrupt_vect:
+ 0000 02s00r00 385 ljmp __sdcc_gsinit_startup
+ 386 ;--------------------------------------------------------
+ 387 ; global & static initialisations
+ 388 ;--------------------------------------------------------
+ 389 .area HOME (CODE)
+ 390 .area GSINIT (CODE)
+ 391 .area GSFINAL (CODE)
+ 392 .area GSINIT (CODE)
+ 393 .globl __sdcc_gsinit_startup
+ 394 .globl __sdcc_program_startup
+ 395 .globl __start__stack
+ 396 .globl __mcs51_genXINIT
+ 397 .globl __mcs51_genXRAMCLEAR
+ 398 .globl __mcs51_genRAMCLEAR
+ 0000 399 G$main$0$0 ==.
+ 0000 400 C$demo_c_0.c$10$1$1 ==.
+ 401 ; demo_c_0.c:10: unsigned long some_variable=0; ///< Documentation for this variable comes here
+ 0000 E4 402 clr a
+ 0001 F5*00 403 mov _some_variable,a
+ 0003 F5*01 404 mov (_some_variable + 1),a
+ 0005 F5*02 405 mov (_some_variable + 2),a
+ 0007 F5*03 406 mov (_some_variable + 3),a
+ 407 .area GSFINAL (CODE)
+ 0000 02s00r03 408 ljmp __sdcc_program_startup
+ 409 ;--------------------------------------------------------
+ 410 ; Home
+ 411 ;--------------------------------------------------------
+ 412 .area HOME (CODE)
+ 413 .area HOME (CODE)
+ 0003 414 __sdcc_program_startup:
+ 0003 12s00r0A 415 lcall _main
+ 416 ; return from main will lock up
+ 0006 80 FE 417 sjmp .
+ 418 ;--------------------------------------------------------
+ 419 ; code
+ 420 ;--------------------------------------------------------
+ 421 .area CSEG (CODE)
+ 422 ;------------------------------------------------------------
+ 423 ;Allocation info for local variables in function 'someFunction'
+ 424 ;------------------------------------------------------------
+ 425 ;somevalue Allocated to registers r2
+ 426 ;------------------------------------------------------------
+ 0000 427 G$someFunction$0$0 ==.
+ 0000 428 C$demo_c_0.c$20$0$0 ==.
+ 429 ; demo_c_0.c:20: void someFunction(unsigned char somevalue)
+ 430 ; -----------------------------------------
+ 431 ; function someFunction
+ 432 ; -----------------------------------------
+ 0000 433 _someFunction:
+ 0002 434 ar2 = 0x02
+ 0003 435 ar3 = 0x03
+ 0004 436 ar4 = 0x04
+ 0005 437 ar5 = 0x05
+ 0006 438 ar6 = 0x06
+ 0007 439 ar7 = 0x07
+ 0000 440 ar0 = 0x00
+ 0001 441 ar1 = 0x01
+ 0000 AA 82 442 mov r2,dpl
+ 0002 443 C$demo_c_0.c$23$1$1 ==.
+ 444 ; demo_c_0.c:23: P1=somevalue;
+ 0002 8A 90 445 mov _P1,r2
+ 0004 446 C$demo_c_0.c$24$1$1 ==.
+ 447 ; demo_c_0.c:24: P3=somevalue^0xFF;
+ 0004 74 FF 448 mov a,#0xFF
+ 0006 6A 449 xrl a,r2
+ 0007 F5 B0 450 mov _P3,a
+ 0009 451 C$demo_c_0.c$25$1$1 ==.
+ 0009 452 XG$someFunction$0$0 ==.
+ 0009 22 453 ret
+ 454 ;------------------------------------------------------------
+ 455 ;Allocation info for local variables in function 'main'
+ 456 ;------------------------------------------------------------
+ 457 ;------------------------------------------------------------
+ 000A 458 G$main$0$0 ==.
+ 000A 459 C$demo_c_0.c$28$1$1 ==.
+ 460 ; demo_c_0.c:28: int main()
+ 461 ; -----------------------------------------
+ 462 ; function main
+ 463 ; -----------------------------------------
+ 000A 464 _main:
+ 000A 465 C$demo_c_0.c$31$1$1 ==.
+ 466 ; demo_c_0.c:31: while(1) {
+ 000A 467 00102$:
+ 000A 468 C$demo_c_0.c$32$2$2 ==.
+ 469 ; demo_c_0.c:32: for(i=0; i<255; i++) {
+ 000A E4 470 clr a
+ 000B F5*04 471 mov _i,a
+ 000D F5*05 472 mov (_i + 1),a
+ 000F 473 00104$:
+ 000F C3 474 clr c
+ 0010 E5*04 475 mov a,_i
+ 0012 94 FF 476 subb a,#0xFF
+ 0014 E5*05 477 mov a,(_i + 1)
+ 0016 64 80 478 xrl a,#0x80
+ 0018 94 80 479 subb a,#0x80
+ 001A 50 26 480 jnc 00107$
+ 001C 481 C$demo_c_0.c$33$3$3 ==.
+ 482 ; demo_c_0.c:33: someFunction(i+2);
+ 001C AA*04 483 mov r2,_i
+ 001E 74 02 484 mov a,#0x02
+ 0020 2A 485 add a,r2
+ 0021 F5 82 486 mov dpl,a
+ 0023 12s00r00 487 lcall _someFunction
+ 0026 488 C$demo_c_0.c$34$3$3 ==.
+ 489 ; demo_c_0.c:34: some_variable++;
+ 0026 05*00 490 inc _some_variable
+ 0028 E4 491 clr a
+ 0029 B5*00 0C 492 cjne a,_some_variable,00114$
+ 002C 05*01 493 inc (_some_variable + 1)
+ 002E B5*01 07 494 cjne a,(_some_variable + 1),00114$
+ 0031 05*02 495 inc (_some_variable + 2)
+ 0033 B5*02 02 496 cjne a,(_some_variable + 2),00114$
+ 0036 05*03 497 inc (_some_variable + 3)
+ 0038 498 00114$:
+ 0038 499 C$demo_c_0.c$32$2$2 ==.
+ 500 ; demo_c_0.c:32: for(i=0; i<255; i++) {
+ 0038 05*04 501 inc _i
+ 003A E4 502 clr a
+ 003B B5*04 D1 503 cjne a,_i,00104$
+ 003E 05*05 504 inc (_i + 1)
+ 0040 80 CD 505 sjmp 00104$
+ 0042 506 00107$:
+ 0042 507 C$demo_c_0.c$36$2$2 ==.
+ 508 ; demo_c_0.c:36: some_variable-=22;
+ 0042 E5*00 509 mov a,_some_variable
+ 0044 24 EA 510 add a,#0xea
+ 0046 F5*00 511 mov _some_variable,a
+ 0048 E5*01 512 mov a,(_some_variable + 1)
+ 004A 34 FF 513 addc a,#0xff
+ 004C F5*01 514 mov (_some_variable + 1),a
+ 004E E5*02 515 mov a,(_some_variable + 2)
+ 0050 34 FF 516 addc a,#0xff
+ 0052 F5*02 517 mov (_some_variable + 2),a
+ 0054 E5*03 518 mov a,(_some_variable + 3)
+ 0056 34 FF 519 addc a,#0xff
+ 0058 F5*03 520 mov (_some_variable + 3),a
+ 005A 521 C$demo_c_0.c$40$1$1 ==.
+ 522 ; demo_c_0.c:40: return 0;
+ 005A 523 C$demo_c_0.c$41$1$1 ==.
+ 005A 524 XG$main$0$0 ==.
+ 005A 80 AE 525 sjmp 00102$
+ 526 .area CSEG (CODE)
+ 527 .area CONST (CODE)
+ 528 .area XINIT (CODE)
+ 529 .area CABS (ABS,CODE)
diff --git a/demo/demo_c_0.map b/demo/demo_c_0.map
new file mode 100644
index 0000000..d1247dd
--- /dev/null
+++ b/demo/demo_c_0.map
@@ -0,0 +1,488 @@
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+CABS 0000 0000 = 0. bytes (ABS,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:FFFFFF00 s_BSEG
+ 0C:0000 l_BIT_BANK
+ 0C:0000 l_BSEG
+ 0C:0000 l_BSEG_BYTES
+ 0C:0000 l_CABS
+ 0C:0000 l_CONST
+ 0C:0000 l_GSINIT1
+ 0C:0000 l_GSINIT5
+ 0C:0000 l_IABS
+ 0C:0000 l_ISEG
+ 0C:0000 l_OSEG
+ 0C:0000 l_PSEG
+ 0C:0000 l_REG_BANK_1
+ 0C:0000 l_REG_BANK_2
+ 0C:0000 l_REG_BANK_3
+ 0C:0000 l_RSEG
+ 0C:0000 l_XABS
+ 0C:0000 l_XINIT
+ 0C:0000 l_XISEG
+ 0C:0000 l_XSEG
+ 0C:0000 l__CODE
+ 0C:0000 s_BSEG_BYTES
+ 0C:0000 s_CABS
+ 0C:0000 s_DSEG
+ 0C:0000 s_HOME
+ 0C:0000 s_IABS
+ 0C:0000 s_ISEG
+ 0C:0000 s_PSEG
+ 0C:0000 s_REG_BANK_0
+ 0C:0000 s_XABS
+ 0C:0000 s_XISEG
+ 0C:0000 s_XSEG
+ 0C:0003 l_GSFINAL
+ 0C:0003 l_GSINIT0
+ 0C:0008 l_HOME
+ 0C:0008 l_REG_BANK_0
+ 0C:0008 s_GSINIT0
+ 0C:0008 s_REG_BANK_1
+ 0C:0009 l_GSINIT
+ 0C:000A l_GSINIT2
+ 0C:000B s_GSINIT1
+ 0C:000B s_GSINIT2
+ 0C:000E s_RSEG
+ 0C:000E s_SSEG
+ 0C:0010 s_REG_BANK_2
+ 0C:0015 s_GSINIT3
+ 0C:0018 s_BIT_BANK
+ 0C:0018 s_OSEG
+ 0C:0018 s_REG_BANK_3
+ 0C:0020 s__CODE
+ 0C:0022 l_GSINIT3
+ 0C:002A l_GSINIT4
+ 0C:0037 s_GSINIT4
+ 0C:0060 l_CSEG
+ 0C:0061 s_GSINIT
+ 0C:0061 s_GSINIT5
+ 0C:006A s_GSFINAL
+ 0C:006D s_CSEG
+ 0C:0080 l_DSEG
+ 0C:00CD s_CONST
+ 0C:00CD s_XINIT
+ 0C:00F2 l_SSEG
+ 0C:0100 l_IRAM
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+. .ABS. 0000 0000 = 0. bytes (ABS,CON)
+
+ Value Global
+ -------- --------------------------------
+ 0080 G$P0$0$0
+ 0080 G$P0_0$0$0
+ 0080 _P0
+ 0080 _P0_0
+ 0081 G$P0_1$0$0
+ 0081 G$SP$0$0
+ 0081 _P0_1
+ 0081 _SP
+ 0082 G$DPL$0$0
+ 0082 G$P0_2$0$0
+ 0082 _DPL
+ 0082 _P0_2
+ 0083 G$DPH$0$0
+ 0083 G$P0_3$0$0
+ 0083 _DPH
+ 0083 _P0_3
+ 0084 G$P0_4$0$0
+ 0084 _P0_4
+ 0085 G$P0_5$0$0
+ 0085 _P0_5
+ 0086 G$P0_6$0$0
+ 0086 _P0_6
+ 0087 G$P0_7$0$0
+ 0087 G$PCON$0$0
+ 0087 _P0_7
+ 0087 _PCON
+ 0088 G$IT0$0$0
+ 0088 G$TCON$0$0
+ 0088 _IT0
+ 0088 _TCON
+ 0089 G$IE0$0$0
+ 0089 G$TMOD$0$0
+ 0089 _IE0
+ 0089 _TMOD
+ 008A G$IT1$0$0
+ 008A G$TL0$0$0
+ 008A _IT1
+ 008A _TL0
+ 008B G$IE1$0$0
+ 008B G$TL1$0$0
+ 008B _IE1
+ 008B _TL1
+ 008C G$TH0$0$0
+ 008C G$TR0$0$0
+ 008C _TH0
+ 008C _TR0
+ 008D G$TF0$0$0
+ 008D G$TH1$0$0
+ 008D _TF0
+ 008D _TH1
+ 008E G$TR1$0$0
+ 008E _TR1
+ 008F G$TF1$0$0
+ 008F _TF1
+ 0090 G$P1$0$0
+ 0090 G$P1_0$0$0
+ 0090 _P1
+ 0090 _P1_0
+ 0091 G$P1_1$0$0
+ 0091 _P1_1
+ 0092 G$P1_2$0$0
+ 0092 _P1_2
+ 0093 G$P1_3$0$0
+ 0093 _P1_3
+ 0094 G$P1_4$0$0
+ 0094 _P1_4
+ 0095 G$P1_5$0$0
+ 0095 _P1_5
+ 0096 G$P1_6$0$0
+ 0096 _P1_6
+ 0097 G$P1_7$0$0
+ 0097 _P1_7
+ 0098 G$RI$0$0
+ 0098 G$SCON$0$0
+ 0098 _RI
+ 0098 _SCON
+ 0099 G$SBUF$0$0
+ 0099 G$TI$0$0
+ 0099 _SBUF
+ 0099 _TI
+ 009A G$RB8$0$0
+ 009A _RB8
+ 009B G$TB8$0$0
+ 009B _TB8
+ 009C G$REN$0$0
+ 009C _REN
+ 009D G$SM2$0$0
+ 009D _SM2
+ 009E G$SM1$0$0
+ 009E _SM1
+ 009F G$SM0$0$0
+ 009F _SM0
+ 00A0 G$P2$0$0
+ 00A0 G$P2_0$0$0
+ 00A0 _P2
+ 00A0 _P2_0
+ 00A0 __XPAGE
+ 00A1 G$P2_1$0$0
+ 00A1 _P2_1
+ 00A2 G$P2_2$0$0
+ 00A2 _P2_2
+ 00A3 G$P2_3$0$0
+ 00A3 _P2_3
+ 00A4 G$P2_4$0$0
+ 00A4 _P2_4
+ 00A5 G$P2_5$0$0
+ 00A5 _P2_5
+ 00A6 G$P2_6$0$0
+ 00A6 _P2_6
+ 00A7 G$P2_7$0$0
+ 00A7 _P2_7
+ 00A8 G$EX0$0$0
+ 00A8 G$IE$0$0
+ 00A8 _EX0
+ 00A8 _IE
+ 00A9 G$ET0$0$0
+ 00A9 _ET0
+ 00AA G$EX1$0$0
+ 00AA _EX1
+ 00AB G$ET1$0$0
+ 00AB _ET1
+ 00AC G$ES$0$0
+ 00AC _ES
+ 00AF G$EA$0$0
+ 00AF _EA
+ 00B0 G$P3$0$0
+ 00B0 G$P3_0$0$0
+ 00B0 G$RXD$0$0
+ 00B0 _P3
+ 00B0 _P3_0
+ 00B0 _RXD
+ 00B1 G$P3_1$0$0
+ 00B1 G$TXD$0$0
+ 00B1 _P3_1
+ 00B1 _TXD
+ 00B2 G$INT0$0$0
+ 00B2 G$P3_2$0$0
+ 00B2 _INT0
+ 00B2 _P3_2
+ 00B3 G$INT1$0$0
+ 00B3 G$P3_3$0$0
+ 00B3 _INT1
+ 00B3 _P3_3
+ 00B4 G$P3_4$0$0
+ 00B4 G$T0$0$0
+ 00B4 _P3_4
+ 00B4 _T0
+ 00B5 G$P3_5$0$0
+ 00B5 G$T1$0$0
+ 00B5 _P3_5
+ 00B5 _T1
+ 00B6 G$P3_6$0$0
+ 00B6 G$WR$0$0
+ 00B6 _P3_6
+ 00B6 _WR
+ 00B7 G$P3_7$0$0
+ 00B7 G$RD$0$0
+ 00B7 _P3_7
+ 00B7 _RD
+ 00B8 G$IP$0$0
+ 00B8 G$PX0$0$0
+ 00B8 _IP
+ 00B8 _PX0
+ 00B9 G$PT0$0$0
+ 00B9 _PT0
+ 00BA G$PX1$0$0
+ 00BA _PX1
+ 00BB G$PT1$0$0
+ 00BB _PT1
+ 00BC G$PS$0$0
+ 00BC _PS
+ 00D0 G$P$0$0
+ 00D0 G$PSW$0$0
+ 00D0 _P
+ 00D0 _PSW
+ 00D1 G$FL$0$0
+ 00D1 _FL
+ 00D2 G$OV$0$0
+ 00D2 _OV
+ 00D3 G$RS0$0$0
+ 00D3 _RS0
+ 00D4 G$RS1$0$0
+ 00D4 _RS1
+ 00D5 G$F0$0$0
+ 00D5 _F0
+ 00D6 G$AC$0$0
+ 00D6 _AC
+ 00D7 G$CY$0$0
+ 00D7 _CY
+ 00E0 G$A$0$0
+ 00E0 G$ACC$0$0
+ 00E0 _A
+ 00E0 _ACC
+ 00F0 G$B$0$0
+ 00F0 _B
+
+
+
+
+
+
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+DSEG 0000 0080 = 128. bytes (REL,CON)
+
+ Value Global
+ -------- --------------------------------
+ 0008 G$some_variable$0$0
+ 0008 _some_variable
+ 000C G$i$0$0
+ 000C _i
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+SSEG 000E 00F2 = 242. bytes (REL,OVR)
+
+ Value Global
+ -------- --------------------------------
+ 000E __start__stack
+
+
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+HOME 0000 0008 = 8. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0000 A$demo_c_0$385
+ 0C:0003 A$demo_c_0$415
+ 0C:0003 __sdcc_program_startup
+ 0C:0006 A$demo_c_0$417
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT0 0008 0003 = 3. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0008 __sdcc_gsinit_startup
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT3 0015 0022 = 34. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0015 __mcs51_genXINIT
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT4 0037 002A = 42. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0037 __mcs51_genRAMCLEAR
+ 0C:003D __mcs51_genXRAMCLEAR
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT 0061 0009 = 9. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0061 A$demo_c_0$402
+ 0C:0061 C$demo_c_0.c$10$1$1
+ 0C:0062 A$demo_c_0$403
+ 0C:0064 A$demo_c_0$404
+ 0C:0066 A$demo_c_0$405
+ 0C:0068 A$demo_c_0$406
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSFINAL 006A 0003 = 3. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:006A A$demo_c_0$408
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+CSEG 006D 0060 = 96. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:006D A$demo_c_0$442
+ 0C:006D C$demo_c_0.c$20$0$0
+ 0C:006D G$someFunction$0$0
+ 0C:006D _someFunction
+ 0C:006F A$demo_c_0$445
+ 0C:006F C$demo_c_0.c$23$1$1
+ 0C:0071 A$demo_c_0$448
+ 0C:0071 C$demo_c_0.c$24$1$1
+ 0C:0073 A$demo_c_0$449
+ 0C:0074 A$demo_c_0$450
+ 0C:0076 A$demo_c_0$453
+ 0C:0076 C$demo_c_0.c$25$1$1
+ 0C:0076 XG$someFunction$0$0
+ 0C:0077 A$demo_c_0$470
+ 0C:0077 C$demo_c_0.c$28$1$1
+ 0C:0077 C$demo_c_0.c$31$1$1
+ 0C:0077 G$main$0$0
+ 0C:0077 _main
+ 0C:0078 A$demo_c_0$471
+ 0C:007A A$demo_c_0$472
+ 0C:007C A$demo_c_0$474
+ 0C:007D A$demo_c_0$475
+ 0C:007F A$demo_c_0$476
+ 0C:0081 A$demo_c_0$477
+ 0C:0083 A$demo_c_0$478
+ 0C:0085 A$demo_c_0$479
+ 0C:0087 A$demo_c_0$480
+ 0C:0089 A$demo_c_0$483
+ 0C:0089 C$demo_c_0.c$33$3$3
+ 0C:008B A$demo_c_0$484
+ 0C:008D A$demo_c_0$485
+ 0C:008E A$demo_c_0$486
+ 0C:0090 A$demo_c_0$487
+ 0C:0093 A$demo_c_0$490
+ 0C:0093 C$demo_c_0.c$34$3$3
+ 0C:0095 A$demo_c_0$491
+ 0C:0096 A$demo_c_0$492
+ 0C:0099 A$demo_c_0$493
+ 0C:009B A$demo_c_0$494
+ 0C:009E A$demo_c_0$495
+ 0C:00A0 A$demo_c_0$496
+ 0C:00A3 A$demo_c_0$497
+ 0C:00A5 A$demo_c_0$501
+ 0C:00A5 C$demo_c_0.c$32$2$2
+ 0C:00A7 A$demo_c_0$502
+ 0C:00A8 A$demo_c_0$503
+ 0C:00AB A$demo_c_0$504
+ 0C:00AD A$demo_c_0$505
+ 0C:00AF A$demo_c_0$509
+ 0C:00AF C$demo_c_0.c$36$2$2
+ 0C:00B1 A$demo_c_0$510
+ 0C:00B3 A$demo_c_0$511
+ 0C:00B5 A$demo_c_0$512
+ 0C:00B7 A$demo_c_0$513
+ 0C:00B9 A$demo_c_0$514
+ 0C:00BB A$demo_c_0$515
+ 0C:00BD A$demo_c_0$516
+ 0C:00BF A$demo_c_0$517
+ 0C:00C1 A$demo_c_0$518
+ 0C:00C3 A$demo_c_0$519
+ 0C:00C5 A$demo_c_0$520
+ 0C:00C7 A$demo_c_0$525
+ 0C:00C7 C$demo_c_0.c$40$1$1
+ 0C:00C7 C$demo_c_0.c$41$1$1
+ 0C:00C7 XG$main$0$0
+ 0C:00C9 __sdcc_external_startup
+
+
+ ASxxxx Linker V01.75 + NoICE + SDCC Feb 1999, page 1.
+
+Files Linked [ module(s) ]
+
+demo_c_0.rel
+
+Libraries Linked [ object file ]
+
+/usr/share/sdcc/lib/small/mcs51.lib [ crtclear.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtxinit.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtxclear.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtpagesfr.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtstart.rel ]
+/usr/share/sdcc/lib/small/libsdcc.lib [ _startup.rel ]
+
+ ASxxxx Linker V01.75 + NoICE + SDCC Feb 1999, page 2.
+
+User Base Address Definitions
+
+HOME = 0x0000
+ISEG = 0x0000
+BSEG = 0x0000
+
+ \ No newline at end of file
diff --git a/demo/demo_c_0.mem b/demo/demo_c_0.mem
new file mode 100644
index 0000000..01837e4
--- /dev/null
+++ b/demo/demo_c_0.mem
@@ -0,0 +1,28 @@
+Internal RAM layout:
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+0x00:|0|0|0|0|0|0|0|0|a|a|a|a|a|a|S|S|
+0x10:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x20:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x30:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x40:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x50:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x60:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x70:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x80:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x90:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xa0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xb0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xc0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xd0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xe0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xf0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute
+
+Stack starts at: 0x0e (sp set to 0x0d) with 242 bytes available.
+
+Other memory:
+ Name Start End Size Max
+ ---------------- -------- -------- -------- --------
+ PAGED EXT. RAM 0 0
+ EXTERNAL RAM 0 0
+ ROM/EPROM/FLASH 0x0000 0x00cc 205 2048
diff --git a/demo/demo_c_0.rel b/demo/demo_c_0.rel
new file mode 100644
index 0000000..172db17
--- /dev/null
+++ b/demo/demo_c_0.rel
@@ -0,0 +1,378 @@
+;!FILE demo_c_0.asm
+XH
+H 1A areas 117 global symbols
+M demo_c_0
+O -mmcs51 --model-small
+S G$EX0$0$0 Def00A8
+S G$IT0$0$0 Def0088
+S G$TH1$0$0 Def008D
+S _P1 Def0090
+S _A Def00E0
+S G$RXD$0$0 Def00B0
+S G$EX1$0$0 Def00AA
+S G$TB8$0$0 Def009B
+S G$IT1$0$0 Def008A
+S G$IE$0$0 Def00A8
+S _P2 Def00A0
+S _B Def00F0
+S _SP Def0081
+S _P3 Def00B0
+S _PS Def00BC
+S G$TXD$0$0 Def00B1
+S G$SM0$0$0 Def009F
+S G$TL0$0$0 Def008A
+S _T0 Def00B4
+S G$SM1$0$0 Def009E
+S G$TL1$0$0 Def008B
+S _T1 Def00B5
+S _OV Def00D2
+S G$FL$0$0 Def00D1
+S G$SM2$0$0 Def009D
+S _ACC Def00E0
+S __mcs51_genRAMCLEAR Ref0000
+S G$PT0$0$0 Def00B9
+S G$RS0$0$0 Def00D3
+S G$PT1$0$0 Def00BB
+S _WR Def00B6
+S G$F0$0$0 Def00D5
+S G$RS1$0$0 Def00D4
+S G$RD$0$0 Def00B7
+S G$TR0$0$0 Def008C
+S G$TR1$0$0 Def008E
+S G$PX0$0$0 Def00B8
+S G$ES$0$0 Def00AC
+S G$PX1$0$0 Def00BA
+S G$IP$0$0 Def00B8
+S G$PSW$0$0 Def00D0
+S G$RI$0$0 Def0098
+S _P0_0 Def0080
+S G$CY$0$0 Def00D7
+S _PCON Def0087
+S _SBUF Def0099
+S _P0_1 Def0081
+S _P1_0 Def0090
+S _P Def00D0
+S G$TI$0$0 Def0099
+S _P0_2 Def0082
+S _P1_1 Def0091
+S _P2_0 Def00A0
+S _P0_3 Def0083
+S _P1_2 Def0092
+S _P2_1 Def00A1
+S _P3_0 Def00B0
+S _SCON Def0098
+S _P0_4 Def0084
+S _P1_3 Def0093
+S _P2_2 Def00A2
+S _P3_1 Def00B1
+S G$P0$0$0 Def0080
+S _TCON Def0088
+S _TMOD Def0089
+S _P0_5 Def0085
+S _P1_4 Def0094
+S _P2_3 Def00A3
+S _P3_2 Def00B2
+S G$A$0$0 Def00E0
+S G$P1$0$0 Def0090
+S _P0_6 Def0086
+S _P1_5 Def0095
+S _P2_4 Def00A4
+S _P3_3 Def00B3
+S G$B$0$0 Def00F0
+S G$P2$0$0 Def00A0
+S _P0_7 Def0087
+S _P1_6 Def0096
+S _P2_5 Def00A5
+S _P3_4 Def00B4
+S G$PS$0$0 Def00BC
+S G$P3$0$0 Def00B0
+S G$SP$0$0 Def0081
+S _P1_7 Def0097
+S _P2_6 Def00A6
+S _P3_5 Def00B5
+S G$T0$0$0 Def00B4
+S _P2_7 Def00A7
+S _P3_6 Def00B6
+S G$OV$0$0 Def00D2
+S G$T1$0$0 Def00B5
+S _P3_7 Def00B7
+S G$ACC$0$0 Def00E0
+S _INT0 Def00B2
+S _DPH Def0083
+S _INT1 Def00B3
+S G$WR$0$0 Def00B6
+S _IE0 Def0089
+S _IE1 Def008B
+S _DPL Def0082
+S G$P0_0$0$0 Def0080
+S G$P$0$0 Def00D0
+S G$P1_0$0$0 Def0090
+S G$P0_1$0$0 Def0081
+S G$SBUF$0$0 Def0099
+S G$PCON$0$0 Def0087
+S _AC Def00D6
+S G$P2_0$0$0 Def00A0
+S G$P1_1$0$0 Def0091
+S G$P0_2$0$0 Def0082
+S _REN Def009C
+S G$P3_0$0$0 Def00B0
+S G$P2_1$0$0 Def00A1
+S G$P1_2$0$0 Def0092
+S G$P0_3$0$0 Def0083
+S _EA Def00AF
+S G$P3_1$0$0 Def00B1
+S G$P2_2$0$0 Def00A2
+S G$P1_3$0$0 Def0093
+S G$P0_4$0$0 Def0084
+S G$SCON$0$0 Def0098
+S G$P3_2$0$0 Def00B2
+S G$P2_3$0$0 Def00A3
+S G$P1_4$0$0 Def0094
+S G$P0_5$0$0 Def0085
+S G$TMOD$0$0 Def0089
+S G$TCON$0$0 Def0088
+S G$P3_3$0$0 Def00B3
+S G$P2_4$0$0 Def00A4
+S G$P1_5$0$0 Def0095
+S G$P0_6$0$0 Def0086
+S _ET0 Def00A9
+S G$P3_4$0$0 Def00B4
+S G$P2_5$0$0 Def00A5
+S G$P1_6$0$0 Def0096
+S G$P0_7$0$0 Def0087
+S _TF0 Def008D
+S _ET1 Def00AB
+S G$P3_5$0$0 Def00B5
+S G$P2_6$0$0 Def00A6
+S G$P1_7$0$0 Def0097
+S _TF1 Def008F
+S G$P3_6$0$0 Def00B6
+S G$P2_7$0$0 Def00A7
+S _TH0 Def008C
+S _RB8 Def009A
+S __mcs51_genXINIT Ref0000
+S G$P3_7$0$0 Def00B7
+S _TH1 Def008D
+S _IT0 Def0088
+S _EX0 Def00A8
+S _IE Def00A8
+S _IT1 Def008A
+S _TB8 Def009B
+S _EX1 Def00AA
+S _RXD Def00B0
+S G$INT0$0$0 Def00B2
+S G$INT1$0$0 Def00B3
+S G$DPH$0$0 Def0083
+S _TL0 Def008A
+S _SM0 Def009F
+S _TXD Def00B1
+S _TL1 Def008B
+S _SM1 Def009E
+S G$IE0$0$0 Def0089
+S _SM2 Def009D
+S _FL Def00D1
+S G$IE1$0$0 Def008B
+S G$DPL$0$0 Def0082
+S _PT0 Def00B9
+S _PT1 Def00BB
+S _RS0 Def00D3
+S _TR0 Def008C
+S _RD Def00B7
+S _RS1 Def00D4
+S _F0 Def00D5
+S _TR1 Def008E
+S G$AC$0$0 Def00D6
+S _ES Def00AC
+S _PX0 Def00B8
+S G$REN$0$0 Def009C
+S _IP Def00B8
+S _PX1 Def00BA
+S G$EA$0$0 Def00AF
+S _PSW Def00D0
+S __sdcc_gsinit_startup Ref0000
+S _RI Def0098
+S _CY Def00D7
+S G$ET0$0$0 Def00A9
+S _TI Def0099
+S G$ET1$0$0 Def00AB
+S G$TF0$0$0 Def008D
+S G$TF1$0$0 Def008F
+S __mcs51_genXRAMCLEAR Ref0000
+S G$RB8$0$0 Def009A
+S G$TH0$0$0 Def008C
+S _P0 Def0080
+A _CODE size 0 flags 0 addr 0
+A RSEG size 0 flags 0 addr 0
+A REG_BANK_0 size 8 flags 4 addr 0
+A DSEG size 6 flags 0 addr 0
+S _i Def0004
+S G$some_variable$0$0 Def0000
+S G$i$0$0 Def0004
+S _some_variable Def0000
+A OSEG size 0 flags 4 addr 0
+A SSEG size 1 flags 0 addr 0
+S __start__stack Def0000
+A ISEG size 0 flags 0 addr 0
+A IABS size 0 flags 8 addr 0
+A BSEG size 0 flags 80 addr 0
+A PSEG size 0 flags 50 addr 0
+A XSEG size 0 flags 40 addr 0
+A XABS size 0 flags 48 addr 0
+A XISEG size 0 flags 40 addr 0
+A HOME size 8 flags 20 addr 0
+S __sdcc_program_startup Def0003
+S A$demo_c_0$415 Def0003
+S A$demo_c_0$417 Def0006
+S A$demo_c_0$385 Def0000
+A GSINIT0 size 0 flags 20 addr 0
+A GSINIT1 size 0 flags 20 addr 0
+A GSINIT2 size 0 flags 20 addr 0
+A GSINIT3 size 0 flags 20 addr 0
+A GSINIT4 size 0 flags 20 addr 0
+A GSINIT5 size 0 flags 20 addr 0
+A GSINIT size 9 flags 20 addr 0
+S A$demo_c_0$402 Def0000
+S A$demo_c_0$403 Def0001
+S A$demo_c_0$404 Def0003
+S A$demo_c_0$405 Def0005
+S A$demo_c_0$406 Def0007
+S C$demo_c_0.c$10$1$1 Def0000
+A GSFINAL size 3 flags 20 addr 0
+S A$demo_c_0$408 Def0000
+A CSEG size 5C flags 20 addr 0
+S A$demo_c_0$494 Def002E
+S A$demo_c_0$485 Def0020
+S A$demo_c_0$476 Def0012
+S A$demo_c_0$449 Def0006
+S C$demo_c_0.c$40$1$1 Def005A
+S C$demo_c_0.c$31$1$1 Def000A
+S A$demo_c_0$495 Def0031
+S A$demo_c_0$486 Def0021
+S A$demo_c_0$477 Def0014
+S C$demo_c_0.c$41$1$1 Def005A
+S C$demo_c_0.c$23$1$1 Def0002
+S A$demo_c_0$496 Def0033
+S A$demo_c_0$487 Def0023
+S A$demo_c_0$478 Def0016
+S C$demo_c_0.c$24$1$1 Def0004
+S A$demo_c_0$497 Def0036
+S A$demo_c_0$479 Def0018
+S C$demo_c_0.c$32$2$2 Def0038
+S C$demo_c_0.c$25$1$1 Def0009
+S _main Def000A
+S XG$someFunction$0$0 Def0009
+S C$demo_c_0.c$33$3$3 Def001C
+S C$demo_c_0.c$28$1$1 Def000A
+S C$demo_c_0.c$36$2$2 Def0042
+S C$demo_c_0.c$34$3$3 Def0026
+S G$someFunction$0$0 Def0000
+S XG$main$0$0 Def005A
+S G$main$0$0 Def000A
+S A$demo_c_0$510 Def0044
+S A$demo_c_0$501 Def0038
+S A$demo_c_0$520 Def0058
+S A$demo_c_0$511 Def0046
+S A$demo_c_0$502 Def003A
+S A$demo_c_0$512 Def0048
+S A$demo_c_0$503 Def003B
+S A$demo_c_0$513 Def004A
+S A$demo_c_0$504 Def003E
+S A$demo_c_0$450 Def0007
+S A$demo_c_0$514 Def004C
+S A$demo_c_0$505 Def0040
+S A$demo_c_0$442 Def0000
+S _someFunction Def0000
+S A$demo_c_0$515 Def004E
+S A$demo_c_0$470 Def000A
+S A$demo_c_0$525 Def005A
+S A$demo_c_0$516 Def0050
+S A$demo_c_0$480 Def001A
+S A$demo_c_0$471 Def000B
+S A$demo_c_0$453 Def0009
+S A$demo_c_0$517 Def0052
+S A$demo_c_0$490 Def0026
+S A$demo_c_0$472 Def000D
+S A$demo_c_0$445 Def0002
+S C$demo_c_0.c$20$0$0 Def0000
+S A$demo_c_0$518 Def0054
+S A$demo_c_0$509 Def0042
+S A$demo_c_0$491 Def0028
+S A$demo_c_0$519 Def0056
+S A$demo_c_0$492 Def0029
+S A$demo_c_0$483 Def001C
+S A$demo_c_0$474 Def000F
+S A$demo_c_0$493 Def002C
+S A$demo_c_0$484 Def001E
+S A$demo_c_0$475 Def0010
+S A$demo_c_0$448 Def0004
+A CONST size 0 flags 20 addr 0
+A XINIT size 0 flags 20 addr 0
+A CABS size 0 flags 28 addr 0
+T 00 00
+R 00 00 00 02
+T 00 00
+R 00 00 00 03
+T 00 00
+R 00 00 00 03
+T 00 04
+R 00 00 00 03
+T 00 04
+R 00 00 00 03
+T 00 00
+R 00 00 00 05
+T 00 00
+R 00 00 00 05
+T 00 00
+R 00 00 00 0D
+T 00 00 02 00 00
+R 00 00 00 0D 02 03 00 BA
+T 00 00 E4 F5 00 00 00 F5 00 00 01 F5
+R 00 00 00 14 F1 21 04 00 03 F1 21 08 00 03
+T 00 06 00 00 02 F5 00 00 03
+R 00 00 00 14 F1 21 02 00 03 F1 21 06 00 03
+T 00 00 02 00 03
+R 00 00 00 15 00 03 00 0D
+T 00 03
+R 00 00 00 0D
+T 00 03 12 00 0A 80 FE
+R 00 00 00 0D 00 03 00 16
+T 00 00
+R 00 00 00 16
+T 00 00 AA 82 8A 90 74 FF 6A F5 B0 22
+R 00 00 00 16
+T 00 0A
+R 00 00 00 16
+T 00 0A
+R 00 00 00 16
+T 00 0A E4 F5 00 00 04 F5 00 00 05
+R 00 00 00 16 F1 21 04 00 03 F1 21 08 00 03
+T 00 0F
+R 00 00 00 16
+T 00 0F C3 E5 00 00 04 94 FF E5 00 00 05 64 80 94
+R 00 00 00 16 F1 21 04 00 03 F1 21 0A 00 03
+T 00 19 80 50 26 AA 00 00 04 74 02 2A F5 82 12
+R 00 00 00 16 F1 21 06 00 03
+T 00 24 00 00 05 00 00 00 E4 B5
+R 00 00 00 16 00 02 00 16 F1 21 05 00 03
+T 00 2A 00 00 00 0C 05 00 00 01 B5
+R 00 00 00 16 F1 21 02 00 03 F1 21 07 00 03
+T 00 2F 00 00 01 07 05 00 00 02 B5
+R 00 00 00 16 F1 21 02 00 03 F1 21 07 00 03
+T 00 34 00 00 02 02 05 00 00 03
+R 00 00 00 16 F1 21 02 00 03 F1 21 07 00 03
+T 00 38
+R 00 00 00 16
+T 00 38 05 00 00 04 E4 B5 00 00 04 D1 05
+R 00 00 00 16 F1 21 03 00 03 F1 21 08 00 03
+T 00 3F 00 00 05 80 CD
+R 00 00 00 16 F1 21 02 00 03
+T 00 42
+R 00 00 00 16
+T 00 42 E5 00 00 00 24 EA F5 00 00 00 E5
+R 00 00 00 16 F1 21 03 00 03 F1 21 09 00 03
+T 00 49 00 00 01 34 FF F5 00 00 01 E5
+R 00 00 00 16 F1 21 02 00 03 F1 21 08 00 03
+T 00 4F 00 00 02 34 FF F5 00 00 02 E5
+R 00 00 00 16 F1 21 02 00 03 F1 21 08 00 03
+T 00 55 00 00 03 34 FF F5 00 00 03 80 AE
+R 00 00 00 16 F1 21 02 00 03 F1 21 08 00 03
diff --git a/demo/demo_c_0.rst b/demo/demo_c_0.rst
new file mode 100644
index 0000000..cc9b36a
--- /dev/null
+++ b/demo/demo_c_0.rst
@@ -0,0 +1,529 @@
+ 1 ;--------------------------------------------------------
+ 2 ; File Created by SDCC : free open source ANSI-C Compiler
+ 3 ; Version 2.9.0 #5416 (Oct 6 2009) (UNIX)
+ 4 ; This file was generated Tue Oct 27 23:03:10 2009
+ 5 ;--------------------------------------------------------
+ 6 .module demo_c_0
+ 7 .optsdcc -mmcs51 --model-small
+ 8
+ 9 ;--------------------------------------------------------
+ 10 ; Public variables in this module
+ 11 ;--------------------------------------------------------
+ 12 .globl _main
+ 13 .globl _someFunction
+ 14 .globl _CY
+ 15 .globl _AC
+ 16 .globl _F0
+ 17 .globl _RS1
+ 18 .globl _RS0
+ 19 .globl _OV
+ 20 .globl _FL
+ 21 .globl _P
+ 22 .globl _PS
+ 23 .globl _PT1
+ 24 .globl _PX1
+ 25 .globl _PT0
+ 26 .globl _PX0
+ 27 .globl _RD
+ 28 .globl _WR
+ 29 .globl _T1
+ 30 .globl _T0
+ 31 .globl _INT1
+ 32 .globl _INT0
+ 33 .globl _TXD
+ 34 .globl _RXD
+ 35 .globl _P3_7
+ 36 .globl _P3_6
+ 37 .globl _P3_5
+ 38 .globl _P3_4
+ 39 .globl _P3_3
+ 40 .globl _P3_2
+ 41 .globl _P3_1
+ 42 .globl _P3_0
+ 43 .globl _EA
+ 44 .globl _ES
+ 45 .globl _ET1
+ 46 .globl _EX1
+ 47 .globl _ET0
+ 48 .globl _EX0
+ 49 .globl _P2_7
+ 50 .globl _P2_6
+ 51 .globl _P2_5
+ 52 .globl _P2_4
+ 53 .globl _P2_3
+ 54 .globl _P2_2
+ 55 .globl _P2_1
+ 56 .globl _P2_0
+ 57 .globl _SM0
+ 58 .globl _SM1
+ 59 .globl _SM2
+ 60 .globl _REN
+ 61 .globl _TB8
+ 62 .globl _RB8
+ 63 .globl _TI
+ 64 .globl _RI
+ 65 .globl _P1_7
+ 66 .globl _P1_6
+ 67 .globl _P1_5
+ 68 .globl _P1_4
+ 69 .globl _P1_3
+ 70 .globl _P1_2
+ 71 .globl _P1_1
+ 72 .globl _P1_0
+ 73 .globl _TF1
+ 74 .globl _TR1
+ 75 .globl _TF0
+ 76 .globl _TR0
+ 77 .globl _IE1
+ 78 .globl _IT1
+ 79 .globl _IE0
+ 80 .globl _IT0
+ 81 .globl _P0_7
+ 82 .globl _P0_6
+ 83 .globl _P0_5
+ 84 .globl _P0_4
+ 85 .globl _P0_3
+ 86 .globl _P0_2
+ 87 .globl _P0_1
+ 88 .globl _P0_0
+ 89 .globl _B
+ 90 .globl _A
+ 91 .globl _ACC
+ 92 .globl _PSW
+ 93 .globl _IP
+ 94 .globl _P3
+ 95 .globl _IE
+ 96 .globl _P2
+ 97 .globl _SBUF
+ 98 .globl _SCON
+ 99 .globl _P1
+ 100 .globl _TH1
+ 101 .globl _TH0
+ 102 .globl _TL1
+ 103 .globl _TL0
+ 104 .globl _TMOD
+ 105 .globl _TCON
+ 106 .globl _PCON
+ 107 .globl _DPH
+ 108 .globl _DPL
+ 109 .globl _SP
+ 110 .globl _P0
+ 111 .globl _i
+ 112 .globl _some_variable
+ 113 ;--------------------------------------------------------
+ 114 ; special function registers
+ 115 ;--------------------------------------------------------
+ 116 .area RSEG (DATA)
+ 0080 117 G$P0$0$0 == 0x0080
+ 0080 118 _P0 = 0x0080
+ 0081 119 G$SP$0$0 == 0x0081
+ 0081 120 _SP = 0x0081
+ 0082 121 G$DPL$0$0 == 0x0082
+ 0082 122 _DPL = 0x0082
+ 0083 123 G$DPH$0$0 == 0x0083
+ 0083 124 _DPH = 0x0083
+ 0087 125 G$PCON$0$0 == 0x0087
+ 0087 126 _PCON = 0x0087
+ 0088 127 G$TCON$0$0 == 0x0088
+ 0088 128 _TCON = 0x0088
+ 0089 129 G$TMOD$0$0 == 0x0089
+ 0089 130 _TMOD = 0x0089
+ 008A 131 G$TL0$0$0 == 0x008a
+ 008A 132 _TL0 = 0x008a
+ 008B 133 G$TL1$0$0 == 0x008b
+ 008B 134 _TL1 = 0x008b
+ 008C 135 G$TH0$0$0 == 0x008c
+ 008C 136 _TH0 = 0x008c
+ 008D 137 G$TH1$0$0 == 0x008d
+ 008D 138 _TH1 = 0x008d
+ 0090 139 G$P1$0$0 == 0x0090
+ 0090 140 _P1 = 0x0090
+ 0098 141 G$SCON$0$0 == 0x0098
+ 0098 142 _SCON = 0x0098
+ 0099 143 G$SBUF$0$0 == 0x0099
+ 0099 144 _SBUF = 0x0099
+ 00A0 145 G$P2$0$0 == 0x00a0
+ 00A0 146 _P2 = 0x00a0
+ 00A8 147 G$IE$0$0 == 0x00a8
+ 00A8 148 _IE = 0x00a8
+ 00B0 149 G$P3$0$0 == 0x00b0
+ 00B0 150 _P3 = 0x00b0
+ 00B8 151 G$IP$0$0 == 0x00b8
+ 00B8 152 _IP = 0x00b8
+ 00D0 153 G$PSW$0$0 == 0x00d0
+ 00D0 154 _PSW = 0x00d0
+ 00E0 155 G$ACC$0$0 == 0x00e0
+ 00E0 156 _ACC = 0x00e0
+ 00E0 157 G$A$0$0 == 0x00e0
+ 00E0 158 _A = 0x00e0
+ 00F0 159 G$B$0$0 == 0x00f0
+ 00F0 160 _B = 0x00f0
+ 161 ;--------------------------------------------------------
+ 162 ; special function bits
+ 163 ;--------------------------------------------------------
+ 164 .area RSEG (DATA)
+ 0080 165 G$P0_0$0$0 == 0x0080
+ 0080 166 _P0_0 = 0x0080
+ 0081 167 G$P0_1$0$0 == 0x0081
+ 0081 168 _P0_1 = 0x0081
+ 0082 169 G$P0_2$0$0 == 0x0082
+ 0082 170 _P0_2 = 0x0082
+ 0083 171 G$P0_3$0$0 == 0x0083
+ 0083 172 _P0_3 = 0x0083
+ 0084 173 G$P0_4$0$0 == 0x0084
+ 0084 174 _P0_4 = 0x0084
+ 0085 175 G$P0_5$0$0 == 0x0085
+ 0085 176 _P0_5 = 0x0085
+ 0086 177 G$P0_6$0$0 == 0x0086
+ 0086 178 _P0_6 = 0x0086
+ 0087 179 G$P0_7$0$0 == 0x0087
+ 0087 180 _P0_7 = 0x0087
+ 0088 181 G$IT0$0$0 == 0x0088
+ 0088 182 _IT0 = 0x0088
+ 0089 183 G$IE0$0$0 == 0x0089
+ 0089 184 _IE0 = 0x0089
+ 008A 185 G$IT1$0$0 == 0x008a
+ 008A 186 _IT1 = 0x008a
+ 008B 187 G$IE1$0$0 == 0x008b
+ 008B 188 _IE1 = 0x008b
+ 008C 189 G$TR0$0$0 == 0x008c
+ 008C 190 _TR0 = 0x008c
+ 008D 191 G$TF0$0$0 == 0x008d
+ 008D 192 _TF0 = 0x008d
+ 008E 193 G$TR1$0$0 == 0x008e
+ 008E 194 _TR1 = 0x008e
+ 008F 195 G$TF1$0$0 == 0x008f
+ 008F 196 _TF1 = 0x008f
+ 0090 197 G$P1_0$0$0 == 0x0090
+ 0090 198 _P1_0 = 0x0090
+ 0091 199 G$P1_1$0$0 == 0x0091
+ 0091 200 _P1_1 = 0x0091
+ 0092 201 G$P1_2$0$0 == 0x0092
+ 0092 202 _P1_2 = 0x0092
+ 0093 203 G$P1_3$0$0 == 0x0093
+ 0093 204 _P1_3 = 0x0093
+ 0094 205 G$P1_4$0$0 == 0x0094
+ 0094 206 _P1_4 = 0x0094
+ 0095 207 G$P1_5$0$0 == 0x0095
+ 0095 208 _P1_5 = 0x0095
+ 0096 209 G$P1_6$0$0 == 0x0096
+ 0096 210 _P1_6 = 0x0096
+ 0097 211 G$P1_7$0$0 == 0x0097
+ 0097 212 _P1_7 = 0x0097
+ 0098 213 G$RI$0$0 == 0x0098
+ 0098 214 _RI = 0x0098
+ 0099 215 G$TI$0$0 == 0x0099
+ 0099 216 _TI = 0x0099
+ 009A 217 G$RB8$0$0 == 0x009a
+ 009A 218 _RB8 = 0x009a
+ 009B 219 G$TB8$0$0 == 0x009b
+ 009B 220 _TB8 = 0x009b
+ 009C 221 G$REN$0$0 == 0x009c
+ 009C 222 _REN = 0x009c
+ 009D 223 G$SM2$0$0 == 0x009d
+ 009D 224 _SM2 = 0x009d
+ 009E 225 G$SM1$0$0 == 0x009e
+ 009E 226 _SM1 = 0x009e
+ 009F 227 G$SM0$0$0 == 0x009f
+ 009F 228 _SM0 = 0x009f
+ 00A0 229 G$P2_0$0$0 == 0x00a0
+ 00A0 230 _P2_0 = 0x00a0
+ 00A1 231 G$P2_1$0$0 == 0x00a1
+ 00A1 232 _P2_1 = 0x00a1
+ 00A2 233 G$P2_2$0$0 == 0x00a2
+ 00A2 234 _P2_2 = 0x00a2
+ 00A3 235 G$P2_3$0$0 == 0x00a3
+ 00A3 236 _P2_3 = 0x00a3
+ 00A4 237 G$P2_4$0$0 == 0x00a4
+ 00A4 238 _P2_4 = 0x00a4
+ 00A5 239 G$P2_5$0$0 == 0x00a5
+ 00A5 240 _P2_5 = 0x00a5
+ 00A6 241 G$P2_6$0$0 == 0x00a6
+ 00A6 242 _P2_6 = 0x00a6
+ 00A7 243 G$P2_7$0$0 == 0x00a7
+ 00A7 244 _P2_7 = 0x00a7
+ 00A8 245 G$EX0$0$0 == 0x00a8
+ 00A8 246 _EX0 = 0x00a8
+ 00A9 247 G$ET0$0$0 == 0x00a9
+ 00A9 248 _ET0 = 0x00a9
+ 00AA 249 G$EX1$0$0 == 0x00aa
+ 00AA 250 _EX1 = 0x00aa
+ 00AB 251 G$ET1$0$0 == 0x00ab
+ 00AB 252 _ET1 = 0x00ab
+ 00AC 253 G$ES$0$0 == 0x00ac
+ 00AC 254 _ES = 0x00ac
+ 00AF 255 G$EA$0$0 == 0x00af
+ 00AF 256 _EA = 0x00af
+ 00B0 257 G$P3_0$0$0 == 0x00b0
+ 00B0 258 _P3_0 = 0x00b0
+ 00B1 259 G$P3_1$0$0 == 0x00b1
+ 00B1 260 _P3_1 = 0x00b1
+ 00B2 261 G$P3_2$0$0 == 0x00b2
+ 00B2 262 _P3_2 = 0x00b2
+ 00B3 263 G$P3_3$0$0 == 0x00b3
+ 00B3 264 _P3_3 = 0x00b3
+ 00B4 265 G$P3_4$0$0 == 0x00b4
+ 00B4 266 _P3_4 = 0x00b4
+ 00B5 267 G$P3_5$0$0 == 0x00b5
+ 00B5 268 _P3_5 = 0x00b5
+ 00B6 269 G$P3_6$0$0 == 0x00b6
+ 00B6 270 _P3_6 = 0x00b6
+ 00B7 271 G$P3_7$0$0 == 0x00b7
+ 00B7 272 _P3_7 = 0x00b7
+ 00B0 273 G$RXD$0$0 == 0x00b0
+ 00B0 274 _RXD = 0x00b0
+ 00B1 275 G$TXD$0$0 == 0x00b1
+ 00B1 276 _TXD = 0x00b1
+ 00B2 277 G$INT0$0$0 == 0x00b2
+ 00B2 278 _INT0 = 0x00b2
+ 00B3 279 G$INT1$0$0 == 0x00b3
+ 00B3 280 _INT1 = 0x00b3
+ 00B4 281 G$T0$0$0 == 0x00b4
+ 00B4 282 _T0 = 0x00b4
+ 00B5 283 G$T1$0$0 == 0x00b5
+ 00B5 284 _T1 = 0x00b5
+ 00B6 285 G$WR$0$0 == 0x00b6
+ 00B6 286 _WR = 0x00b6
+ 00B7 287 G$RD$0$0 == 0x00b7
+ 00B7 288 _RD = 0x00b7
+ 00B8 289 G$PX0$0$0 == 0x00b8
+ 00B8 290 _PX0 = 0x00b8
+ 00B9 291 G$PT0$0$0 == 0x00b9
+ 00B9 292 _PT0 = 0x00b9
+ 00BA 293 G$PX1$0$0 == 0x00ba
+ 00BA 294 _PX1 = 0x00ba
+ 00BB 295 G$PT1$0$0 == 0x00bb
+ 00BB 296 _PT1 = 0x00bb
+ 00BC 297 G$PS$0$0 == 0x00bc
+ 00BC 298 _PS = 0x00bc
+ 00D0 299 G$P$0$0 == 0x00d0
+ 00D0 300 _P = 0x00d0
+ 00D1 301 G$FL$0$0 == 0x00d1
+ 00D1 302 _FL = 0x00d1
+ 00D2 303 G$OV$0$0 == 0x00d2
+ 00D2 304 _OV = 0x00d2
+ 00D3 305 G$RS0$0$0 == 0x00d3
+ 00D3 306 _RS0 = 0x00d3
+ 00D4 307 G$RS1$0$0 == 0x00d4
+ 00D4 308 _RS1 = 0x00d4
+ 00D5 309 G$F0$0$0 == 0x00d5
+ 00D5 310 _F0 = 0x00d5
+ 00D6 311 G$AC$0$0 == 0x00d6
+ 00D6 312 _AC = 0x00d6
+ 00D7 313 G$CY$0$0 == 0x00d7
+ 00D7 314 _CY = 0x00d7
+ 315 ;--------------------------------------------------------
+ 316 ; overlayable register banks
+ 317 ;--------------------------------------------------------
+ 318 .area REG_BANK_0 (REL,OVR,DATA)
+ 0000 319 .ds 8
+ 320 ;--------------------------------------------------------
+ 321 ; internal ram data
+ 322 ;--------------------------------------------------------
+ 323 .area DSEG (DATA)
+ 0000 324 G$some_variable$0$0==.
+ 0008 325 _some_variable::
+ 0008 326 .ds 4
+ 0004 327 G$i$0$0==.
+ 000C 328 _i::
+ 000C 329 .ds 2
+ 330 ;--------------------------------------------------------
+ 331 ; overlayable items in internal ram
+ 332 ;--------------------------------------------------------
+ 333 .area OSEG (OVR,DATA)
+ 334 ;--------------------------------------------------------
+ 335 ; Stack segment in internal ram
+ 336 ;--------------------------------------------------------
+ 337 .area SSEG (DATA)
+ 000E 338 __start__stack:
+ 000E 339 .ds 1
+ 340
+ 341 ;--------------------------------------------------------
+ 342 ; indirectly addressable internal ram data
+ 343 ;--------------------------------------------------------
+ 344 .area ISEG (DATA)
+ 345 ;--------------------------------------------------------
+ 346 ; absolute internal ram data
+ 347 ;--------------------------------------------------------
+ 348 .area IABS (ABS,DATA)
+ 349 .area IABS (ABS,DATA)
+ 350 ;--------------------------------------------------------
+ 351 ; bit data
+ 352 ;--------------------------------------------------------
+ 353 .area BSEG (BIT)
+ 354 ;--------------------------------------------------------
+ 355 ; paged external ram data
+ 356 ;--------------------------------------------------------
+ 357 .area PSEG (PAG,XDATA)
+ 358 ;--------------------------------------------------------
+ 359 ; external ram data
+ 360 ;--------------------------------------------------------
+ 361 .area XSEG (XDATA)
+ 362 ;--------------------------------------------------------
+ 363 ; absolute external ram data
+ 364 ;--------------------------------------------------------
+ 365 .area XABS (ABS,XDATA)
+ 366 ;--------------------------------------------------------
+ 367 ; external initialized ram data
+ 368 ;--------------------------------------------------------
+ 369 .area XISEG (XDATA)
+ 370 .area HOME (CODE)
+ 371 .area GSINIT0 (CODE)
+ 372 .area GSINIT1 (CODE)
+ 373 .area GSINIT2 (CODE)
+ 374 .area GSINIT3 (CODE)
+ 375 .area GSINIT4 (CODE)
+ 376 .area GSINIT5 (CODE)
+ 377 .area GSINIT (CODE)
+ 378 .area GSFINAL (CODE)
+ 379 .area CSEG (CODE)
+ 380 ;--------------------------------------------------------
+ 381 ; interrupt vector
+ 382 ;--------------------------------------------------------
+ 383 .area HOME (CODE)
+ 0000 384 __interrupt_vect:
+ 0000 02 00 08 385 ljmp __sdcc_gsinit_startup
+ 386 ;--------------------------------------------------------
+ 387 ; global & static initialisations
+ 388 ;--------------------------------------------------------
+ 389 .area HOME (CODE)
+ 390 .area GSINIT (CODE)
+ 391 .area GSFINAL (CODE)
+ 392 .area GSINIT (CODE)
+ 393 .globl __sdcc_gsinit_startup
+ 394 .globl __sdcc_program_startup
+ 395 .globl __start__stack
+ 396 .globl __mcs51_genXINIT
+ 397 .globl __mcs51_genXRAMCLEAR
+ 398 .globl __mcs51_genRAMCLEAR
+ 0000 399 G$main$0$0 ==.
+ 0000 400 C$demo_c_0.c$10$1$1 ==.
+ 401 ; demo_c_0.c:10: unsigned long some_variable=0; ///< Documentation for this variable comes here
+ 0061 E4 402 clr a
+ 0062 F5 08 403 mov _some_variable,a
+ 0064 F5 09 404 mov (_some_variable + 1),a
+ 0066 F5 0A 405 mov (_some_variable + 2),a
+ 0068 F5 0B 406 mov (_some_variable + 3),a
+ 407 .area GSFINAL (CODE)
+ 006A 02 00 03 408 ljmp __sdcc_program_startup
+ 409 ;--------------------------------------------------------
+ 410 ; Home
+ 411 ;--------------------------------------------------------
+ 412 .area HOME (CODE)
+ 413 .area HOME (CODE)
+ 0003 414 __sdcc_program_startup:
+ 0003 12 00 77 415 lcall _main
+ 416 ; return from main will lock up
+ 0006 80 FE 417 sjmp .
+ 418 ;--------------------------------------------------------
+ 419 ; code
+ 420 ;--------------------------------------------------------
+ 421 .area CSEG (CODE)
+ 422 ;------------------------------------------------------------
+ 423 ;Allocation info for local variables in function 'someFunction'
+ 424 ;------------------------------------------------------------
+ 425 ;somevalue Allocated to registers r2
+ 426 ;------------------------------------------------------------
+ 0000 427 G$someFunction$0$0 ==.
+ 0000 428 C$demo_c_0.c$20$0$0 ==.
+ 429 ; demo_c_0.c:20: void someFunction(unsigned char somevalue)
+ 430 ; -----------------------------------------
+ 431 ; function someFunction
+ 432 ; -----------------------------------------
+ 006D 433 _someFunction:
+ 0002 434 ar2 = 0x02
+ 0003 435 ar3 = 0x03
+ 0004 436 ar4 = 0x04
+ 0005 437 ar5 = 0x05
+ 0006 438 ar6 = 0x06
+ 0007 439 ar7 = 0x07
+ 0000 440 ar0 = 0x00
+ 0001 441 ar1 = 0x01
+ 006D AA 82 442 mov r2,dpl
+ 0002 443 C$demo_c_0.c$23$1$1 ==.
+ 444 ; demo_c_0.c:23: P1=somevalue;
+ 006F 8A 90 445 mov _P1,r2
+ 0004 446 C$demo_c_0.c$24$1$1 ==.
+ 447 ; demo_c_0.c:24: P3=somevalue^0xFF;
+ 0071 74 FF 448 mov a,#0xFF
+ 0073 6A 449 xrl a,r2
+ 0074 F5 B0 450 mov _P3,a
+ 0009 451 C$demo_c_0.c$25$1$1 ==.
+ 0009 452 XG$someFunction$0$0 ==.
+ 0076 22 453 ret
+ 454 ;------------------------------------------------------------
+ 455 ;Allocation info for local variables in function 'main'
+ 456 ;------------------------------------------------------------
+ 457 ;------------------------------------------------------------
+ 000A 458 G$main$0$0 ==.
+ 000A 459 C$demo_c_0.c$28$1$1 ==.
+ 460 ; demo_c_0.c:28: int main()
+ 461 ; -----------------------------------------
+ 462 ; function main
+ 463 ; -----------------------------------------
+ 0077 464 _main:
+ 000A 465 C$demo_c_0.c$31$1$1 ==.
+ 466 ; demo_c_0.c:31: while(1) {
+ 0077 467 00102$:
+ 000A 468 C$demo_c_0.c$32$2$2 ==.
+ 469 ; demo_c_0.c:32: for(i=0; i<255; i++) {
+ 0077 E4 470 clr a
+ 0078 F5 0C 471 mov _i,a
+ 007A F5 0D 472 mov (_i + 1),a
+ 007C 473 00104$:
+ 007C C3 474 clr c
+ 007D E5 0C 475 mov a,_i
+ 007F 94 FF 476 subb a,#0xFF
+ 0081 E5 0D 477 mov a,(_i + 1)
+ 0083 64 80 478 xrl a,#0x80
+ 0085 94 80 479 subb a,#0x80
+ 0087 50 26 480 jnc 00107$
+ 001C 481 C$demo_c_0.c$33$3$3 ==.
+ 482 ; demo_c_0.c:33: someFunction(i+2);
+ 0089 AA 0C 483 mov r2,_i
+ 008B 74 02 484 mov a,#0x02
+ 008D 2A 485 add a,r2
+ 008E F5 82 486 mov dpl,a
+ 0090 12 00 6D 487 lcall _someFunction
+ 0026 488 C$demo_c_0.c$34$3$3 ==.
+ 489 ; demo_c_0.c:34: some_variable++;
+ 0093 05 08 490 inc _some_variable
+ 0095 E4 491 clr a
+ 0096 B5 08 0C 492 cjne a,_some_variable,00114$
+ 0099 05 09 493 inc (_some_variable + 1)
+ 009B B5 09 07 494 cjne a,(_some_variable + 1),00114$
+ 009E 05 0A 495 inc (_some_variable + 2)
+ 00A0 B5 0A 02 496 cjne a,(_some_variable + 2),00114$
+ 00A3 05 0B 497 inc (_some_variable + 3)
+ 00A5 498 00114$:
+ 0038 499 C$demo_c_0.c$32$2$2 ==.
+ 500 ; demo_c_0.c:32: for(i=0; i<255; i++) {
+ 00A5 05 0C 501 inc _i
+ 00A7 E4 502 clr a
+ 00A8 B5 0C D1 503 cjne a,_i,00104$
+ 00AB 05 0D 504 inc (_i + 1)
+ 00AD 80 CD 505 sjmp 00104$
+ 00AF 506 00107$:
+ 0042 507 C$demo_c_0.c$36$2$2 ==.
+ 508 ; demo_c_0.c:36: some_variable-=22;
+ 00AF E5 08 509 mov a,_some_variable
+ 00B1 24 EA 510 add a,#0xea
+ 00B3 F5 08 511 mov _some_variable,a
+ 00B5 E5 09 512 mov a,(_some_variable + 1)
+ 00B7 34 FF 513 addc a,#0xff
+ 00B9 F5 09 514 mov (_some_variable + 1),a
+ 00BB E5 0A 515 mov a,(_some_variable + 2)
+ 00BD 34 FF 516 addc a,#0xff
+ 00BF F5 0A 517 mov (_some_variable + 2),a
+ 00C1 E5 0B 518 mov a,(_some_variable + 3)
+ 00C3 34 FF 519 addc a,#0xff
+ 00C5 F5 0B 520 mov (_some_variable + 3),a
+ 005A 521 C$demo_c_0.c$40$1$1 ==.
+ 522 ; demo_c_0.c:40: return 0;
+ 005A 523 C$demo_c_0.c$41$1$1 ==.
+ 005A 524 XG$main$0$0 ==.
+ 00C7 80 AE 525 sjmp 00102$
+ 526 .area CSEG (CODE)
+ 527 .area CONST (CODE)
+ 528 .area XINIT (CODE)
+ 529 .area CABS (ABS,CODE)
diff --git a/demo/demo_c_0.sym b/demo/demo_c_0.sym
new file mode 100644
index 0000000..9d943ba
--- /dev/null
+++ b/demo/demo_c_0.sym
@@ -0,0 +1,659 @@
+ ASxxxx Assembler V01.70 + NoICE + SDCC mods + Flat24 Feb-1999 (Intel 8051), page 1.
+
+Symbol Table
+
+ A 00D6
+ D A$demo_c_0$385 0000 GR
+ 14 A$demo_c_0$402 0000 GR
+ 14 A$demo_c_0$403 0001 GR
+ 14 A$demo_c_0$404 0003 GR
+ 14 A$demo_c_0$405 0005 GR
+ 14 A$demo_c_0$406 0007 GR
+ 15 A$demo_c_0$408 0000 GR
+ D A$demo_c_0$415 0003 GR
+ D A$demo_c_0$417 0006 GR
+ 16 A$demo_c_0$442 0000 GR
+ 16 A$demo_c_0$445 0002 GR
+ 16 A$demo_c_0$448 0004 GR
+ 16 A$demo_c_0$449 0006 GR
+ 16 A$demo_c_0$450 0007 GR
+ 16 A$demo_c_0$453 0009 GR
+ 16 A$demo_c_0$470 000A GR
+ 16 A$demo_c_0$471 000B GR
+ 16 A$demo_c_0$472 000D GR
+ 16 A$demo_c_0$474 000F GR
+ 16 A$demo_c_0$475 0010 GR
+ 16 A$demo_c_0$476 0012 GR
+ 16 A$demo_c_0$477 0014 GR
+ 16 A$demo_c_0$478 0016 GR
+ 16 A$demo_c_0$479 0018 GR
+ 16 A$demo_c_0$480 001A GR
+ 16 A$demo_c_0$483 001C GR
+ 16 A$demo_c_0$484 001E GR
+ 16 A$demo_c_0$485 0020 GR
+ 16 A$demo_c_0$486 0021 GR
+ 16 A$demo_c_0$487 0023 GR
+ 16 A$demo_c_0$490 0026 GR
+ 16 A$demo_c_0$491 0028 GR
+ 16 A$demo_c_0$492 0029 GR
+ 16 A$demo_c_0$493 002C GR
+ 16 A$demo_c_0$494 002E GR
+ 16 A$demo_c_0$495 0031 GR
+ 16 A$demo_c_0$496 0033 GR
+ 16 A$demo_c_0$497 0036 GR
+ 16 A$demo_c_0$501 0038 GR
+ 16 A$demo_c_0$502 003A GR
+ 16 A$demo_c_0$503 003B GR
+ 16 A$demo_c_0$504 003E GR
+ 16 A$demo_c_0$505 0040 GR
+ 16 A$demo_c_0$509 0042 GR
+ 16 A$demo_c_0$510 0044 GR
+ 16 A$demo_c_0$511 0046 GR
+ 16 A$demo_c_0$512 0048 GR
+ 16 A$demo_c_0$513 004A GR
+ 16 A$demo_c_0$514 004C GR
+ 16 A$demo_c_0$515 004E GR
+ 16 A$demo_c_0$516 0050 GR
+ 16 A$demo_c_0$517 0052 GR
+ 16 A$demo_c_0$518 0054 GR
+ 16 A$demo_c_0$519 0056 GR
+ 16 A$demo_c_0$520 0058 GR
+ 16 A$demo_c_0$525 005A GR
+ AC 00D6
+ ACC 00E0
+ ACC.0 00E0
+ ACC.1 00E1
+ ACC.2 00E2
+ ACC.3 00E3
+ ACC.4 00E4
+ ACC.5 00E5
+ ACC.6 00E6
+ ACC.7 00E7
+ B 00F0
+ B.0 00F0
+ B.1 00F1
+ B.2 00F2
+ B.3 00F3
+ B.4 00F4
+ B.5 00F5
+ B.6 00F6
+ B.7 00F7
+ 14 C$demo_c_0.c$10$1$1 = 0000 GR
+ 16 C$demo_c_0.c$20$0$0 = 0000 GR
+ 16 C$demo_c_0.c$23$1$1 = 0002 GR
+ 16 C$demo_c_0.c$24$1$1 = 0004 GR
+ 16 C$demo_c_0.c$25$1$1 = 0009 GR
+ 16 C$demo_c_0.c$28$1$1 = 000A GR
+ 16 C$demo_c_0.c$31$1$1 = 000A GR
+ 16 C$demo_c_0.c$32$2$2 = 0038 GR
+ 16 C$demo_c_0.c$33$3$3 = 001C GR
+ 16 C$demo_c_0.c$34$3$3 = 0026 GR
+ 16 C$demo_c_0.c$36$2$2 = 0042 GR
+ 16 C$demo_c_0.c$40$1$1 = 005A GR
+ 16 C$demo_c_0.c$41$1$1 = 005A GR
+ CPRL2 00C8
+ CT2 00C9
+ CY 00D7
+ DPH 0083
+ DPL 0082
+ EA 00AF
+ ES 00AC
+ ET0 00A9
+ ET1 00AB
+ ET2 00AD
+ EX0 00A8
+ EX1 00AA
+ EXEN2 00CB
+ EXF2 00CE
+ F0 00D5
+ G$A$0$0 = 00E0 G
+ G$AC$0$0 = 00D6 G
+ G$ACC$0$0 = 00E0 G
+ G$B$0$0 = 00F0 G
+ G$CY$0$0 = 00D7 G
+ G$DPH$0$0 = 0083 G
+ G$DPL$0$0 = 0082 G
+ G$EA$0$0 = 00AF G
+ G$ES$0$0 = 00AC G
+ G$ET0$0$0 = 00A9 G
+ G$ET1$0$0 = 00AB G
+ G$EX0$0$0 = 00A8 G
+ G$EX1$0$0 = 00AA G
+ G$F0$0$0 = 00D5 G
+ G$FL$0$0 = 00D1 G
+ G$IE$0$0 = 00A8 G
+ G$IE0$0$0 = 0089 G
+ G$IE1$0$0 = 008B G
+ G$INT0$0$0 = 00B2 G
+ G$INT1$0$0 = 00B3 G
+ G$IP$0$0 = 00B8 G
+ G$IT0$0$0 = 0088 G
+ G$IT1$0$0 = 008A G
+ G$OV$0$0 = 00D2 G
+ G$P$0$0 = 00D0 G
+ G$P0$0$0 = 0080 G
+ G$P0_0$0$0 = 0080 G
+ G$P0_1$0$0 = 0081 G
+ G$P0_2$0$0 = 0082 G
+ G$P0_3$0$0 = 0083 G
+ G$P0_4$0$0 = 0084 G
+ G$P0_5$0$0 = 0085 G
+ G$P0_6$0$0 = 0086 G
+ G$P0_7$0$0 = 0087 G
+ G$P1$0$0 = 0090 G
+ G$P1_0$0$0 = 0090 G
+ G$P1_1$0$0 = 0091 G
+ G$P1_2$0$0 = 0092 G
+ G$P1_3$0$0 = 0093 G
+ G$P1_4$0$0 = 0094 G
+ G$P1_5$0$0 = 0095 G
+ G$P1_6$0$0 = 0096 G
+ G$P1_7$0$0 = 0097 G
+ G$P2$0$0 = 00A0 G
+ G$P2_0$0$0 = 00A0 G
+ G$P2_1$0$0 = 00A1 G
+ G$P2_2$0$0 = 00A2 G
+ G$P2_3$0$0 = 00A3 G
+ G$P2_4$0$0 = 00A4 G
+ G$P2_5$0$0 = 00A5 G
+ G$P2_6$0$0 = 00A6 G
+ G$P2_7$0$0 = 00A7 G
+ G$P3$0$0 = 00B0 G
+ G$P3_0$0$0 = 00B0 G
+ G$P3_1$0$0 = 00B1 G
+ G$P3_2$0$0 = 00B2 G
+ G$P3_3$0$0 = 00B3 G
+ G$P3_4$0$0 = 00B4 G
+ G$P3_5$0$0 = 00B5 G
+ G$P3_6$0$0 = 00B6 G
+ G$P3_7$0$0 = 00B7 G
+ G$PCON$0$0 = 0087 G
+ G$PS$0$0 = 00BC G
+ G$PSW$0$0 = 00D0 G
+ G$PT0$0$0 = 00B9 G
+ G$PT1$0$0 = 00BB G
+ G$PX0$0$0 = 00B8 G
+ G$PX1$0$0 = 00BA G
+ G$RB8$0$0 = 009A G
+ G$RD$0$0 = 00B7 G
+ G$REN$0$0 = 009C G
+ G$RI$0$0 = 0098 G
+ G$RS0$0$0 = 00D3 G
+ G$RS1$0$0 = 00D4 G
+ G$RXD$0$0 = 00B0 G
+ G$SBUF$0$0 = 0099 G
+ G$SCON$0$0 = 0098 G
+ G$SM0$0$0 = 009F G
+ G$SM1$0$0 = 009E G
+ G$SM2$0$0 = 009D G
+ G$SP$0$0 = 0081 G
+ G$T0$0$0 = 00B4 G
+ G$T1$0$0 = 00B5 G
+ G$TB8$0$0 = 009B G
+ G$TCON$0$0 = 0088 G
+ G$TF0$0$0 = 008D G
+ G$TF1$0$0 = 008F G
+ G$TH0$0$0 = 008C G
+ G$TH1$0$0 = 008D G
+ G$TI$0$0 = 0099 G
+ G$TL0$0$0 = 008A G
+ G$TL1$0$0 = 008B G
+ G$TMOD$0$0 = 0089 G
+ G$TR0$0$0 = 008C G
+ G$TR1$0$0 = 008E G
+ G$TXD$0$0 = 00B1 G
+ G$WR$0$0 = 00B6 G
+ 3 G$i$0$0 = 0004 GR
+ 16 G$main$0$0 = 000A GR
+ 16 G$someFunction$0$0 = 0000 GR
+ 3 G$some_variable$0$0 = 0000 GR
+ IE 00A8
+ IE.0 00A8
+ IE.1 00A9
+ IE.2 00AA
+ IE.3 00AB
+ IE.4 00AC
+ IE.5 00AD
+ IE.7 00AF
+ IE0 0089
+ IE1 008B
+ INT0 00B2
+ INT1 00B3
+ IP 00B8
+ IP.0 00B8
+ IP.1 00B9
+ IP.2 00BA
+ IP.3 00BB
+ IP.4 00BC
+ IP.5 00BD
+ IT0 0088
+ IT1 008A
+ OV 00D2
+ P 00D0
+ P0 0080
+ P0.0 0080
+ P0.1 0081
+ P0.2 0082
+ P0.3 0083
+ P0.4 0084
+ P0.5 0085
+ P0.6 0086
+ P0.7 0087
+ P1 0090
+ P1.0 0090
+ P1.1 0091
+ P1.2 0092
+ P1.3 0093
+ P1.4 0094
+ P1.5 0095
+ P1.6 0096
+ P1.7 0097
+ P2 00A0
+ P2.0 00A0
+ P2.1 00A1
+ P2.2 00A2
+ P2.3 00A3
+ P2.4 00A4
+ P2.5 00A5
+ P2.6 00A6
+ P2.7 00A7
+ P3 00B0
+ P3.0 00B0
+ P3.1 00B1
+ P3.2 00B2
+ P3.3 00B3
+ P3.4 00B4
+ P3.5 00B5
+ P3.6 00B6
+ P3.7 00B7
+ PCON 0087
+ PS 00BC
+ PSW 00D0
+ PSW.0 00D0
+ PSW.1 00D1
+ PSW.2 00D2
+ PSW.3 00D3
+ PSW.4 00D4
+ PSW.5 00D5
+ PSW.6 00D6
+ PSW.7 00D7
+ PT0 00B9
+ PT1 00BB
+ PT2 00BD
+ PX0 00B8
+ PX1 00BA
+ RB8 009A
+ RCAP2H 00CB
+ RCAP2L 00CA
+ RCLK 00CD
+ REN 009C
+ RI 0098
+ RS0 00D3
+ RS1 00D4
+ RXD 00B0
+ SBUF 0099
+ SCON 0098
+ SCON.0 0098
+ SCON.1 0099
+ SCON.2 009A
+ SCON.3 009B
+ SCON.4 009C
+ SCON.5 009D
+ SCON.6 009E
+ SCON.7 009F
+ SM0 009F
+ SM1 009E
+ SM2 009D
+ SP 0081
+ T2CON 00C8
+ T2CON.0 00C8
+ T2CON.1 00C9
+ T2CON.2 00CA
+ T2CON.3 00CB
+ T2CON.4 00CC
+ T2CON.5 00CD
+ T2CON.6 00CE
+ T2CON.7 00CF
+ TB8 009B
+ TCLK 00CC
+ TCON 0088
+ TCON.0 0088
+ TCON.1 0089
+ TCON.2 008A
+ TCON.3 008B
+ TCON.4 008C
+ TCON.5 008D
+ TCON.6 008E
+ TCON.7 008F
+ TF0 008D
+ TF1 008F
+ TF2 00CF
+ TH0 008C
+ TH1 008D
+ TH2 00CD
+ TI 0099
+ TL0 008A
+ TL1 008B
+ TL2 00CC
+ TMOD 0089
+ TR0 008C
+ TR1 008E
+ TR2 00CA
+ TXD 00B1
+ 16 XG$main$0$0 = 005A GR
+ 16 XG$someFunction$0$0 = 0009 GR
+ _A = 00E0 G
+ _AC = 00D6 G
+ _ACC = 00E0 G
+ _B = 00F0 G
+ _CY = 00D7 G
+ _DPH = 0083 G
+ _DPL = 0082 G
+ _EA = 00AF G
+ _ES = 00AC G
+ _ET0 = 00A9 G
+ _ET1 = 00AB G
+ _EX0 = 00A8 G
+ _EX1 = 00AA G
+ _F0 = 00D5 G
+ _FL = 00D1 G
+ _IE = 00A8 G
+ _IE0 = 0089 G
+ _IE1 = 008B G
+ _INT0 = 00B2 G
+ _INT1 = 00B3 G
+ _IP = 00B8 G
+ _IT0 = 0088 G
+ _IT1 = 008A G
+ _OV = 00D2 G
+ _P = 00D0 G
+ _P0 = 0080 G
+ _P0_0 = 0080 G
+ _P0_1 = 0081 G
+ _P0_2 = 0082 G
+ _P0_3 = 0083 G
+ _P0_4 = 0084 G
+ _P0_5 = 0085 G
+ _P0_6 = 0086 G
+ _P0_7 = 0087 G
+ _P1 = 0090 G
+ _P1_0 = 0090 G
+ _P1_1 = 0091 G
+ _P1_2 = 0092 G
+ _P1_3 = 0093 G
+ _P1_4 = 0094 G
+ _P1_5 = 0095 G
+ _P1_6 = 0096 G
+ _P1_7 = 0097 G
+ _P2 = 00A0 G
+ _P2_0 = 00A0 G
+ _P2_1 = 00A1 G
+ _P2_2 = 00A2 G
+ _P2_3 = 00A3 G
+ _P2_4 = 00A4 G
+ _P2_5 = 00A5 G
+ _P2_6 = 00A6 G
+ _P2_7 = 00A7 G
+ _P3 = 00B0 G
+ _P3_0 = 00B0 G
+ _P3_1 = 00B1 G
+ _P3_2 = 00B2 G
+ _P3_3 = 00B3 G
+ _P3_4 = 00B4 G
+ _P3_5 = 00B5 G
+ _P3_6 = 00B6 G
+ _P3_7 = 00B7 G
+ _PCON = 0087 G
+ _PS = 00BC G
+ _PSW = 00D0 G
+ _PT0 = 00B9 G
+ _PT1 = 00BB G
+ _PX0 = 00B8 G
+ _PX1 = 00BA G
+ _RB8 = 009A G
+ _RD = 00B7 G
+ _REN = 009C G
+ _RI = 0098 G
+ _RS0 = 00D3 G
+ _RS1 = 00D4 G
+ _RXD = 00B0 G
+ _SBUF = 0099 G
+ _SCON = 0098 G
+ _SM0 = 009F G
+ _SM1 = 009E G
+ _SM2 = 009D G
+ _SP = 0081 G
+ _T0 = 00B4 G
+ _T1 = 00B5 G
+ _TB8 = 009B G
+ _TCON = 0088 G
+ _TF0 = 008D G
+ _TF1 = 008F G
+ _TH0 = 008C G
+ _TH1 = 008D G
+ _TI = 0099 G
+ _TL0 = 008A G
+ _TL1 = 008B G
+ _TMOD = 0089 G
+ _TR0 = 008C G
+ _TR1 = 008E G
+ _TXD = 00B1 G
+ _WR = 00B6 G
+ D __interrupt_vect 0000 R
+ __mcs51_genRAMCLEAR **** GX
+ __mcs51_genXINIT **** GX
+ __mcs51_genXRAMCLEAR **** GX
+ __sdcc_gsinit_startup **** GX
+ D __sdcc_program_startup 0003 GR
+ 5 __start__stack 0000 GR
+ 3 _i 0004 GR
+ 16 _main 000A GR
+ 16 _someFunction 0000 GR
+ 3 _some_variable 0000 GR
+ a 00D6
+ ac 00D6
+ acc 00E0
+ acc.0 00E0
+ acc.1 00E1
+ acc.2 00E2
+ acc.3 00E3
+ acc.4 00E4
+ acc.5 00E5
+ acc.6 00E6
+ acc.7 00E7
+ ar0 = 0000
+ ar1 = 0001
+ ar2 = 0002
+ ar3 = 0003
+ ar4 = 0004
+ ar5 = 0005
+ ar6 = 0006
+ ar7 = 0007
+ b 00F0
+ b.0 00F0
+ b.1 00F1
+ b.2 00F2
+ b.3 00F3
+ b.4 00F4
+ b.5 00F5
+ b.6 00F6
+ b.7 00F7
+ cprl2 00C8
+ ct2 00C9
+ cy 00D7
+ dph 0083
+ dpl 0082
+ ea 00AF
+ es 00AC
+ et0 00A9
+ et1 00AB
+ et2 00AD
+ ex0 00A8
+ ex1 00AA
+ exen2 00CB
+ exf2 00CE
+ f0 00D5
+ ie 00A8
+ ie.0 00A8
+ ie.1 00A9
+ ie.2 00AA
+ ie.3 00AB
+ ie.4 00AC
+ ie.5 00AD
+ ie.7 00AF
+ ie0 0089
+ ie1 008B
+ int0 00B2
+ int1 00B3
+ ip 00B8
+ ip.0 00B8
+ ip.1 00B9
+ ip.2 00BA
+ ip.3 00BB
+ ip.4 00BC
+ ip.5 00BD
+ it0 0088
+ it1 008A
+ ov 00D2
+ p 00D0
+ p0 0080
+ p0.0 0080
+ p0.1 0081
+ p0.2 0082
+ p0.3 0083
+ p0.4 0084
+ p0.5 0085
+ p0.6 0086
+ p0.7 0087
+ p1 0090
+ p1.0 0090
+ p1.1 0091
+ p1.2 0092
+ p1.3 0093
+ p1.4 0094
+ p1.5 0095
+ p1.6 0096
+ p1.7 0097
+ p2 00A0
+ p2.0 00A0
+ p2.1 00A1
+ p2.2 00A2
+ p2.3 00A3
+ p2.4 00A4
+ p2.5 00A5
+ p2.6 00A6
+ p2.7 00A7
+ p3 00B0
+ p3.0 00B0
+ p3.1 00B1
+ p3.2 00B2
+ p3.3 00B3
+ p3.4 00B4
+ p3.5 00B5
+ p3.6 00B6
+ p3.7 00B7
+ pcon 0087
+ ps 00BC
+ psw 00D0
+ psw.0 00D0
+ psw.1 00D1
+ psw.2 00D2
+ psw.3 00D3
+ psw.4 00D4
+ psw.5 00D5
+ psw.6 00D6
+ psw.7 00D7
+ pt0 00B9
+ pt1 00BB
+ pt2 00BD
+ px0 00B8
+ px1 00BA
+ rb8 009A
+ rcap2h 00CB
+ rcap2l 00CA
+ rclk 00CD
+ ren 009C
+ ri 0098
+ rs0 00D3
+ rs1 00D4
+ rxd 00B0
+ sbuf 0099
+ scon 0098
+ scon.0 0098
+ scon.1 0099
+ scon.2 009A
+ scon.3 009B
+ scon.4 009C
+ scon.5 009D
+ scon.6 009E
+ scon.7 009F
+ sm0 009F
+ sm1 009E
+ sm2 009D
+ sp 0081
+ t2con 00C8
+ t2con.0 00C8
+ t2con.1 00C9
+ t2con.2 00CA
+ t2con.3 00CB
+ t2con.4 00CC
+ t2con.5 00CD
+ t2con.6 00CE
+ t2con.7 00CF
+ tb8 009B
+ tclk 00CC
+ tcon 0088
+ tcon.0 0088
+ tcon.1 0089
+ tcon.2 008A
+ tcon.3 008B
+ tcon.4 008C
+ tcon.5 008D
+ tcon.6 008E
+ tcon.7 008F
+ tf0 008D
+ tf1 008F
+ tf2 00CF
+ th0 008C
+ th1 008D
+ th2 00CD
+ ti 0099
+ tl0 008A
+ tl1 008B
+ tl2 00CC
+ tmod 0089
+ tr0 008C
+ tr1 008E
+ tr2 00CA
+ txd 00B1
+
+ ASxxxx Assembler V01.70 + NoICE + SDCC mods + Flat24 Feb-1999 (Intel 8051), page 2.
+
+Area Table
+
+ 0 _CODE size 0 flags 0
+ 1 RSEG size 0 flags 0
+ 2 REG_BANK_0 size 8 flags 4
+ 3 DSEG size 6 flags 0
+ 4 OSEG size 0 flags 4
+ 5 SSEG size 1 flags 0
+ 6 ISEG size 0 flags 0
+ 7 IABS size 0 flags 8
+ 8 BSEG size 0 flags 80
+ 9 PSEG size 0 flags 50
+ A XSEG size 0 flags 40
+ B XABS size 0 flags 48
+ C XISEG size 0 flags 40
+ D HOME size 8 flags 20
+ E GSINIT0 size 0 flags 20
+ F GSINIT1 size 0 flags 20
+ 10 GSINIT2 size 0 flags 20
+ 11 GSINIT3 size 0 flags 20
+ 12 GSINIT4 size 0 flags 20
+ 13 GSINIT5 size 0 flags 20
+ 14 GSINIT size 9 flags 20
+ 15 GSFINAL size 3 flags 20
+ 16 CSEG size 5C flags 20
+ 17 CONST size 0 flags 20
+ 18 XINIT size 0 flags 20
+ 19 CABS size 0 flags 28
diff --git a/demo/file.hex b/demo/file.hex
new file mode 100644
index 0000000..b6d53b5
--- /dev/null
+++ b/demo/file.hex
@@ -0,0 +1,2 @@
+:0600000080FE33343334AE
+:00000001FF \ No newline at end of file
diff --git a/demo/file.lst b/demo/file.lst
new file mode 100644
index 0000000..5ca698c
--- /dev/null
+++ b/demo/file.lst
@@ -0,0 +1,292 @@
+demo3 demo - 3 32/13/1907 PAGE 6
+ 1 ; MCU 8051 IDE - Demostration code
+ 2 ; Compiler directives
+ 3
+ 4
+ 5 $DATE(32/13/1907)   ; Places date
+ 6 ; $EJECT ; Places a fo
+ 7 ; $INCLUDE(file.asm) ; Inserts fil
+ 8 ; $LIST ; Allows list
+ 9 ; $NOLIST ; Stops outpu
+ 10 ; $NOMOD ; No predefin
+ demo3 demo - 3 32/13/1907 PAGE 7
+ 11 $OBJECT(file.hex) ; Places obje
+ 12 ; $NOOBJECT ; No object f
+ 13 $PAGING ; Break outpu
+ 14 ; $NOPAGING ; Print listi
+ 15 $PAGELENGTH(10) ; No. of line
+ 16 $PAGEWIDTH(20)    ; No. of colu
+ 17 $PRINT(file.lst) ; Places list
+ 18 ; $NOPRINT ; Listing wil
+ 19 ; $SYMBOLS ; Append symb
+ 20 ; $NOSYMBOLS ; Symbol tabl
+ demo3 demo - 3 32/13/1907 PAGE 8
+ 21 $TITLE('demo - 3') ; Places stri
+ 22
+ 23
+ 24 ;; Summary of Cross Assembler Directi
+ 25 ;; ----------------------------------
+ 26
+ 0036 27 a EQU 54d ; Define symb
+ 001B 28 b0 DATA a / 2 ; Define inte
+ 0031 29 c IDATA (b0*2-5) ; Def
+ 0038 30 d BIT 070Q ; Define inte
+ demo3 demo - 3 32/13/1907 PAGE 9
+ FFA5 31 e CODE 0FFA5h ; Define prog
+****WARNING: Exceeding code memory capacity: e = 65445
+ FFF2 33 var SET (A * 44) MOD 9 - 14 ;
+ 34
+ 35 CSEG at 20h ; Select prog
+ 36 x: DB '34' ; Store byte
+ 37 y: DW 3334h ; Store word
+ 38
+ 39 DSEG at 5d ; Select inte
+ 40 m: DS 1 ; Reserve byt
+ demo3 demo - 3 32/13/1907 PAGE 10
+ 41
+ 42 xseg ; Select exte
+ 43 n: DS 1 ; Reserve byt
+ 44
+ 45 ISEG ; Select indi
+ 46 o: DS 1 ; Reserve byt
+ 47
+ 48 NOLIST ; Disable code listin
+ 51 LIST ; Enable code listing
+ 52
+ demo3 demo - 3 32/13/1907 PAGE 11
+ 53
+ 54 +1 mc macro label ; Define macr
+ 55 +1 sjmp main
+ 56 IF 2 <> 2 OR 1 = 4
+ 57 EXITM ; Exit macro
+ 58 ENDIF
+ 59 sjmp label
+ 60 endm ; End of defi
+ 61
+ 62 main: ORG 0 ; Set segment
+ demo3 demo - 3 32/13/1907 PAGE 12
+ 63 IF 0 ; Begin conditional a
+ 64 USING 2 ; Sel
+ 65 ELSE ; Alternative conditi
+ 66 USING 2 ; Sel
+ 67 ENDIF ; End conditional ass
+ 68
+ 69 mc main ; Macro instu
+ 70
+ 71 END ; End of assembly lan
+ASSEMBLY COMPLETE, NO ERRORS FOUND, 1 WARNING
+
+
+
+ demo3 demo - 3 32/13/1907 PAGE 2
+
+ERROR SUMMARY:
+Line 31, WARNING: Exceeding code memory capacity: e = 65445
+ demo3 demo - 3 32/13/1907 PAGE 3
+
+
+
+
+ demo3 demo - 3 32/13/1907 PAGE 4
+SYMBOL TABLE:
+A. . . . . . . . . . . . . . . . . . N NUMB 0036H NOT USED
+AC . . . . . . . . . . . . . . . . . B ADDR 00D6H NOT USED
+ACC. . . . . . . . . . . . . . . . . D ADDR 00E0H NOT USED
+ACSR . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+ADCF . . . . . . . . . . . . . . . . D ADDR 00F6H NOT USED
+ADCLK. . . . . . . . . . . . . . . . D ADDR 00F2H NOT USED
+ADCON. . . . . . . . . . . . . . . . D ADDR 00F3H NOT USED
+ADDH . . . . . . . . . . . . . . . . D ADDR 00F5H NOT USED
+ADDL . . . . . . . . . . . . . . . . D ADDR 00F4H NOT USED
+AR0. . . . . . . . . . . . . . . . . NUMB 0010H NOT USED REDEFINABLE
+AR1. . . . . . . . . . . . . . . . . NUMB 0011H NOT USED REDEFINABLE
+AR2. . . . . . . . . . . . . . . . . NUMB 0012H NOT USED REDEFINABLE
+AR3. . . . . . . . . . . . . . . . . NUMB 0013H NOT USED REDEFINABLE
+AR4. . . . . . . . . . . . . . . . . NUMB 0014H NOT USED REDEFINABLE
+AR5. . . . . . . . . . . . . . . . . NUMB 0015H NOT USED REDEFINABLE
+AR6. . . . . . . . . . . . . . . . . NUMB 0016H NOT USED REDEFINABLE
+AR7. . . . . . . . . . . . . . . . . NUMB 0017H NOT USED REDEFINABLE
+AUXR . . . . . . . . . . . . . . . . D ADDR 008EH NOT USED
+AUXR1. . . . . . . . . . . . . . . . D ADDR 00A2H NOT USED
+B. . . . . . . . . . . . . . . . . . D ADDR 00F0H NOT USED
+B0 . . . . . . . . . . . . . . . . . D ADDR 001BH NOT USED
+BDRCON . . . . . . . . . . . . . . . D ADDR 009BH NOT USED
+BDRCON_1 . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+BRL. . . . . . . . . . . . . . . . . D ADDR 009AH NOT USED
+C. . . . . . . . . . . . . . . . . . I ADDR 0031H NOT USED
+CCAP0H . . . . . . . . . . . . . . . D ADDR 00FAH NOT USED
+CCAP0L . . . . . . . . . . . . . . . D ADDR 00EAH NOT USED
+CCAP1H . . . . . . . . . . . . . . . D ADDR 00FBH NOT USED
+CCAP1L . . . . . . . . . . . . . . . D ADDR 00EBH NOT USED
+CCAP2H . . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAP3H . . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAP4H . . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL2H. . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAPL2L. . . . . . . . . . . . . . . D ADDR 00ECH NOT USED
+CCAPL3H. . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAPL3L. . . . . . . . . . . . . . . D ADDR 00EDH NOT USED
+CCAPL4H. . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL4L. . . . . . . . . . . . . . . D ADDR 00EEH NOT USED
+CCAPM0 . . . . . . . . . . . . . . . D ADDR 00DAH NOT USED
+CCAPM1 . . . . . . . . . . . . . . . D ADDR 00DBH NOT USED
+CCAPM2 . . . . . . . . . . . . . . . D ADDR 00DCH NOT USED
+CCAPM3 . . . . . . . . . . . . . . . D ADDR 00DDH NOT USED
+CCAPM4 . . . . . . . . . . . . . . . D ADDR 00DEH NOT USED
+CCF0 . . . . . . . . . . . . . . . . B ADDR 00D8H NOT USED
+CCF1 . . . . . . . . . . . . . . . . B ADDR 00D9H NOT USED
+CCF2 . . . . . . . . . . . . . . . . B ADDR 00DAH NOT USED
+CCF3 . . . . . . . . . . . . . . . . B ADDR 00DBH NOT USED
+CCF4 . . . . . . . . . . . . . . . . B ADDR 00DCH NOT USED
+CCON . . . . . . . . . . . . . . . . D ADDR 00D8H NOT USED
+CFINT. . . . . . . . . . . . . . . . C ADDR 0033H NOT USED
+CH . . . . . . . . . . . . . . . . . D ADDR 00F9H NOT USED
+CKCON. . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKCON0 . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKRL . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+CKSEL. . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+CL . . . . . . . . . . . . . . . . . D ADDR 00E9H NOT USED
+CLKREG . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CMOD . . . . . . . . . . . . . . . . D ADDR 00D9H NOT USED
+CPRL2. . . . . . . . . . . . . . . . B ADDR 00C8H NOT USED
+CR . . . . . . . . . . . . . . . . . B ADDR 00DEH NOT USED
+CT2. . . . . . . . . . . . . . . . . B ADDR 00C9H NOT USED
+CY . . . . . . . . . . . . . . . . . B ADDR 00D7H NOT USED
+D. . . . . . . . . . . . . . . . . . B ADDR 0038H NOT USED
+DP0H . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DP0L . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+DP1H . . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+DP1L . . . . . . . . . . . . . . . . D ADDR 0084H NOT USED
+DPH. . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+ demo3 demo - 3 32/13/1907 PAGE 5
+DPL. . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+E. . . . . . . . . . . . . . . . . . C ADDR FFA5H NOT USED
+EA . . . . . . . . . . . . . . . . . B ADDR 00AFH NOT USED
+EC . . . . . . . . . . . . . . . . . B ADDR 00AEH NOT USED
+EECON. . . . . . . . . . . . . . . . D ADDR 0096H NOT USED
+ES . . . . . . . . . . . . . . . . . B ADDR 00ACH NOT USED
+ET0. . . . . . . . . . . . . . . . . B ADDR 00A9H NOT USED
+ET1. . . . . . . . . . . . . . . . . B ADDR 00ABH NOT USED
+ET2. . . . . . . . . . . . . . . . . B ADDR 00ADH NOT USED
+EX0. . . . . . . . . . . . . . . . . B ADDR 00A8H NOT USED
+EX1. . . . . . . . . . . . . . . . . B ADDR 00AAH NOT USED
+EXEN2. . . . . . . . . . . . . . . . B ADDR 00CBH NOT USED
+EXF2 . . . . . . . . . . . . . . . . B ADDR 00CEH NOT USED
+EXTI0. . . . . . . . . . . . . . . . C ADDR 0003H NOT USED
+EXTI1. . . . . . . . . . . . . . . . C ADDR 0013H NOT USED
+F0 . . . . . . . . . . . . . . . . . B ADDR 00D5H NOT USED
+FE . . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+IE . . . . . . . . . . . . . . . . . D ADDR 00A8H NOT USED
+IE0. . . . . . . . . . . . . . . . . B ADDR 0089H NOT USED
+IE1. . . . . . . . . . . . . . . . . B ADDR 008BH NOT USED
+INT0 . . . . . . . . . . . . . . . . B ADDR 00B2H NOT USED
+INT1 . . . . . . . . . . . . . . . . B ADDR 00B3H NOT USED
+IP . . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPH. . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH0 . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH1 . . . . . . . . . . . . . . . . D ADDR 00B3H NOT USED
+IPL0 . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPL1 . . . . . . . . . . . . . . . . D ADDR 00B2H NOT USED
+IT0. . . . . . . . . . . . . . . . . B ADDR 0088H NOT USED
+IT1. . . . . . . . . . . . . . . . . B ADDR 008AH NOT USED
+KBE. . . . . . . . . . . . . . . . . D ADDR 009DH NOT USED
+KBF. . . . . . . . . . . . . . . . . D ADDR 009EH NOT USED
+KBLS . . . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+M. . . . . . . . . . . . . . . . . . D ADDR 0005H NOT USED
+MAIN . . . . . . . . . . . . . . . . C ADDR 0000H
+N. . . . . . . . . . . . . . . . . . X ADDR 0000H NOT USED
+O. . . . . . . . . . . . . . . . . . I ADDR 0000H NOT USED
+OSCCON . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+OV . . . . . . . . . . . . . . . . . B ADDR 00D2H NOT USED
+P. . . . . . . . . . . . . . . . . . B ADDR 00D0H NOT USED
+P0 . . . . . . . . . . . . . . . . . D ADDR 0080H NOT USED
+P1 . . . . . . . . . . . . . . . . . D ADDR 0090H NOT USED
+P1M1 . . . . . . . . . . . . . . . . D ADDR 00D4H NOT USED
+P1M2 . . . . . . . . . . . . . . . . D ADDR 00E2H NOT USED
+P2 . . . . . . . . . . . . . . . . . D ADDR 00A0H NOT USED
+P3 . . . . . . . . . . . . . . . . . D ADDR 00B0H NOT USED
+P3M1 . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+P3M2 . . . . . . . . . . . . . . . . D ADDR 00E3H NOT USED
+P4 . . . . . . . . . . . . . . . . . D ADDR 00C0H NOT USED
+P4M1 . . . . . . . . . . . . . . . . D ADDR 00D6H NOT USED
+P4M2 . . . . . . . . . . . . . . . . D ADDR 00E4H NOT USED
+P5 . . . . . . . . . . . . . . . . . D ADDR 00E8H NOT USED
+PC . . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PCON . . . . . . . . . . . . . . . . D ADDR 0087H NOT USED
+PPCL . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PS . . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSL. . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSW. . . . . . . . . . . . . . . . . D ADDR 00D0H NOT USED
+PT0. . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT0L . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT1. . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT1L . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT2. . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PT2L . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PX0. . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX0L . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX1. . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+PX1L . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+ demo3 demo - 3 32/13/1907 PAGE 6
+R. . . . . . . . . . . . . . . . . . B ADDR 0000H NOT USED
+RB8. . . . . . . . . . . . . . . . . B ADDR 009AH NOT USED
+RCAP2H . . . . . . . . . . . . . . . D ADDR 00CBH NOT USED
+RCAP2L . . . . . . . . . . . . . . . D ADDR 00CAH NOT USED
+RCLK . . . . . . . . . . . . . . . . B ADDR 00CDH NOT USED
+RD . . . . . . . . . . . . . . . . . B ADDR 00B7H NOT USED
+REN. . . . . . . . . . . . . . . . . B ADDR 009CH NOT USED
+RESET. . . . . . . . . . . . . . . . C ADDR 0000H NOT USED
+RI . . . . . . . . . . . . . . . . . B ADDR 0098H NOT USED
+RS0. . . . . . . . . . . . . . . . . B ADDR 00D3H NOT USED
+RS1. . . . . . . . . . . . . . . . . B ADDR 00D4H NOT USED
+RXD. . . . . . . . . . . . . . . . . B ADDR 00B0H NOT USED
+SADDR. . . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_0. . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_1. . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SADEN. . . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_0. . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_1. . . . . . . . . . . . . . . D ADDR 00BAH NOT USED
+SBUF . . . . . . . . . . . . . . . . D ADDR 0099H NOT USED
+SCON . . . . . . . . . . . . . . . . D ADDR 0098H NOT USED
+SINT . . . . . . . . . . . . . . . . C ADDR 0023H NOT USED
+SM0. . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+SM1. . . . . . . . . . . . . . . . . B ADDR 009EH NOT USED
+SM2. . . . . . . . . . . . . . . . . B ADDR 009DH NOT USED
+SP . . . . . . . . . . . . . . . . . D ADDR 0081H NOT USED
+SPCON. . . . . . . . . . . . . . . . D ADDR 00C3H NOT USED
+SPCR . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+SPDAT. . . . . . . . . . . . . . . . D ADDR 00C5H NOT USED
+SPDR . . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+SPSR . . . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SPSTA. . . . . . . . . . . . . . . . D ADDR 00C4H NOT USED
+T0 . . . . . . . . . . . . . . . . . B ADDR 00B4H NOT USED
+T1 . . . . . . . . . . . . . . . . . B ADDR 00B5H NOT USED
+T2CON. . . . . . . . . . . . . . . . D ADDR 00C8H NOT USED
+T2MOD. . . . . . . . . . . . . . . . D ADDR 00C9H NOT USED
+TB8. . . . . . . . . . . . . . . . . B ADDR 009BH NOT USED
+TCLK . . . . . . . . . . . . . . . . B ADDR 00CCH NOT USED
+TCON . . . . . . . . . . . . . . . . D ADDR 0088H NOT USED
+TF0. . . . . . . . . . . . . . . . . B ADDR 008DH NOT USED
+TF1. . . . . . . . . . . . . . . . . B ADDR 008FH NOT USED
+TF2. . . . . . . . . . . . . . . . . B ADDR 00CFH NOT USED
+TH0. . . . . . . . . . . . . . . . . D ADDR 008CH NOT USED
+TH1. . . . . . . . . . . . . . . . . D ADDR 008DH NOT USED
+TH2. . . . . . . . . . . . . . . . . D ADDR 00CDH NOT USED
+TI . . . . . . . . . . . . . . . . . B ADDR 0099H NOT USED
+TIMER0 . . . . . . . . . . . . . . . C ADDR 000BH NOT USED
+TIMER1 . . . . . . . . . . . . . . . C ADDR 001BH NOT USED
+TIMER2 . . . . . . . . . . . . . . . C ADDR 002BH NOT USED
+TL0. . . . . . . . . . . . . . . . . D ADDR 008AH NOT USED
+TL1. . . . . . . . . . . . . . . . . D ADDR 008BH NOT USED
+TL2. . . . . . . . . . . . . . . . . D ADDR 00CCH NOT USED
+TMOD . . . . . . . . . . . . . . . . D ADDR 0089H NOT USED
+TR0. . . . . . . . . . . . . . . . . B ADDR 008CH NOT USED
+TR1. . . . . . . . . . . . . . . . . B ADDR 008EH NOT USED
+TR2. . . . . . . . . . . . . . . . . B ADDR 00CAH NOT USED
+TXD. . . . . . . . . . . . . . . . . B ADDR 00B1H NOT USED
+VAR. . . . . . . . . . . . . . . . . NUMB FFF2H NOT USED REDEFINABLE
+WDTCON . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTPRG . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTRST . . . . . . . . . . . . . . . D ADDR 00A6H NOT USED
+WR . . . . . . . . . . . . . . . . . B ADDR 00B6H NOT USED
+X. . . . . . . . . . . . . . . . . . C ADDR 0002H NOT USED
+Y. . . . . . . . . . . . . . . . . . C ADDR 0004H NOT USED \ No newline at end of file
diff --git a/demo/keypad_display b/demo/keypad_display
new file mode 100644
index 0000000..4bea3f5
--- /dev/null
+++ b/demo/keypad_display
Binary files differ
diff --git a/demo/keypad_display.adb b/demo/keypad_display.adb
new file mode 100644
index 0000000..ff7f769
--- /dev/null
+++ b/demo/keypad_display.adb
@@ -0,0 +1,106 @@
+M:keypad_display
+F:G$main$0$0({2}DF,SI:S),C,0,0,0,0,0
+S:G$state$0$0({1}SC:S),E,0,0
+S:G$row$0$0({2}SI:S),E,0,0
+S:G$P0$0$0({1}SC:U),I,0,0
+S:G$SP$0$0({1}SC:U),I,0,0
+S:G$DPL$0$0({1}SC:U),I,0,0
+S:G$DPH$0$0({1}SC:U),I,0,0
+S:G$PCON$0$0({1}SC:U),I,0,0
+S:G$TCON$0$0({1}SC:U),I,0,0
+S:G$TMOD$0$0({1}SC:U),I,0,0
+S:G$TL0$0$0({1}SC:U),I,0,0
+S:G$TL1$0$0({1}SC:U),I,0,0
+S:G$TH0$0$0({1}SC:U),I,0,0
+S:G$TH1$0$0({1}SC:U),I,0,0
+S:G$P1$0$0({1}SC:U),I,0,0
+S:G$SCON$0$0({1}SC:U),I,0,0
+S:G$SBUF$0$0({1}SC:U),I,0,0
+S:G$P2$0$0({1}SC:U),I,0,0
+S:G$IE$0$0({1}SC:U),I,0,0
+S:G$P3$0$0({1}SC:U),I,0,0
+S:G$IP$0$0({1}SC:U),I,0,0
+S:G$PSW$0$0({1}SC:U),I,0,0
+S:G$ACC$0$0({1}SC:U),I,0,0
+S:G$B$0$0({1}SC:U),I,0,0
+S:G$P0_0$0$0({1}SX:U),J,0,0
+S:G$P0_1$0$0({1}SX:U),J,0,0
+S:G$P0_2$0$0({1}SX:U),J,0,0
+S:G$P0_3$0$0({1}SX:U),J,0,0
+S:G$P0_4$0$0({1}SX:U),J,0,0
+S:G$P0_5$0$0({1}SX:U),J,0,0
+S:G$P0_6$0$0({1}SX:U),J,0,0
+S:G$P0_7$0$0({1}SX:U),J,0,0
+S:G$IT0$0$0({1}SX:U),J,0,0
+S:G$IE0$0$0({1}SX:U),J,0,0
+S:G$IT1$0$0({1}SX:U),J,0,0
+S:G$IE1$0$0({1}SX:U),J,0,0
+S:G$TR0$0$0({1}SX:U),J,0,0
+S:G$TF0$0$0({1}SX:U),J,0,0
+S:G$TR1$0$0({1}SX:U),J,0,0
+S:G$TF1$0$0({1}SX:U),J,0,0
+S:G$P1_0$0$0({1}SX:U),J,0,0
+S:G$P1_1$0$0({1}SX:U),J,0,0
+S:G$P1_2$0$0({1}SX:U),J,0,0
+S:G$P1_3$0$0({1}SX:U),J,0,0
+S:G$P1_4$0$0({1}SX:U),J,0,0
+S:G$P1_5$0$0({1}SX:U),J,0,0
+S:G$P1_6$0$0({1}SX:U),J,0,0
+S:G$P1_7$0$0({1}SX:U),J,0,0
+S:G$RI$0$0({1}SX:U),J,0,0
+S:G$TI$0$0({1}SX:U),J,0,0
+S:G$RB8$0$0({1}SX:U),J,0,0
+S:G$TB8$0$0({1}SX:U),J,0,0
+S:G$REN$0$0({1}SX:U),J,0,0
+S:G$SM2$0$0({1}SX:U),J,0,0
+S:G$SM1$0$0({1}SX:U),J,0,0
+S:G$SM0$0$0({1}SX:U),J,0,0
+S:G$P2_0$0$0({1}SX:U),J,0,0
+S:G$P2_1$0$0({1}SX:U),J,0,0
+S:G$P2_2$0$0({1}SX:U),J,0,0
+S:G$P2_3$0$0({1}SX:U),J,0,0
+S:G$P2_4$0$0({1}SX:U),J,0,0
+S:G$P2_5$0$0({1}SX:U),J,0,0
+S:G$P2_6$0$0({1}SX:U),J,0,0
+S:G$P2_7$0$0({1}SX:U),J,0,0
+S:G$EX0$0$0({1}SX:U),J,0,0
+S:G$ET0$0$0({1}SX:U),J,0,0
+S:G$EX1$0$0({1}SX:U),J,0,0
+S:G$ET1$0$0({1}SX:U),J,0,0
+S:G$ES$0$0({1}SX:U),J,0,0
+S:G$EA$0$0({1}SX:U),J,0,0
+S:G$P3_0$0$0({1}SX:U),J,0,0
+S:G$P3_1$0$0({1}SX:U),J,0,0
+S:G$P3_2$0$0({1}SX:U),J,0,0
+S:G$P3_3$0$0({1}SX:U),J,0,0
+S:G$P3_4$0$0({1}SX:U),J,0,0
+S:G$P3_5$0$0({1}SX:U),J,0,0
+S:G$P3_6$0$0({1}SX:U),J,0,0
+S:G$P3_7$0$0({1}SX:U),J,0,0
+S:G$RXD$0$0({1}SX:U),J,0,0
+S:G$TXD$0$0({1}SX:U),J,0,0
+S:G$INT0$0$0({1}SX:U),J,0,0
+S:G$INT1$0$0({1}SX:U),J,0,0
+S:G$T0$0$0({1}SX:U),J,0,0
+S:G$T1$0$0({1}SX:U),J,0,0
+S:G$WR$0$0({1}SX:U),J,0,0
+S:G$RD$0$0({1}SX:U),J,0,0
+S:G$PX0$0$0({1}SX:U),J,0,0
+S:G$PT0$0$0({1}SX:U),J,0,0
+S:G$PX1$0$0({1}SX:U),J,0,0
+S:G$PT1$0$0({1}SX:U),J,0,0
+S:G$PS$0$0({1}SX:U),J,0,0
+S:G$P$0$0({1}SX:U),J,0,0
+S:G$F1$0$0({1}SX:U),J,0,0
+S:G$OV$0$0({1}SX:U),J,0,0
+S:G$RS0$0$0({1}SX:U),J,0,0
+S:G$RS1$0$0({1}SX:U),J,0,0
+S:G$F0$0$0({1}SX:U),J,0,0
+S:G$AC$0$0({1}SX:U),J,0,0
+S:G$CY$0$0({1}SX:U),J,0,0
+S:G$main$0$0({2}DF,SI:S),C,0,0
+S:Fkeypad_display$keypad$0$0({4}DA4,SC:S),D,0,0
+S:Fkeypad_display$display_0$0$0({4}DA4,SC:S),D,0,0
+S:Fkeypad_display$display_1$0$0({4}DA4,SC:S),D,0,0
+S:Fkeypad_display$display_2$0$0({4}DA4,SC:S),D,0,0
+S:Fkeypad_display$display_3$0$0({4}DA4,SC:S),D,0,0
diff --git a/demo/keypad_display.asm b/demo/keypad_display.asm
new file mode 100644
index 0000000..a216cbe
--- /dev/null
+++ b/demo/keypad_display.asm
@@ -0,0 +1,624 @@
+;--------------------------------------------------------
+; File Created by SDCC : free open source ANSI-C Compiler
+; Version 2.9.0 #5416 (Oct 6 2009) (UNIX)
+; This file was generated Tue Oct 27 23:03:55 2009
+;--------------------------------------------------------
+ .module keypad_display
+ .optsdcc -mmcs51 --model-small
+
+;--------------------------------------------------------
+; Public variables in this module
+;--------------------------------------------------------
+ .globl _main
+ .globl _CY
+ .globl _AC
+ .globl _F0
+ .globl _RS1
+ .globl _RS0
+ .globl _OV
+ .globl _F1
+ .globl _P
+ .globl _PS
+ .globl _PT1
+ .globl _PX1
+ .globl _PT0
+ .globl _PX0
+ .globl _RD
+ .globl _WR
+ .globl _T1
+ .globl _T0
+ .globl _INT1
+ .globl _INT0
+ .globl _TXD
+ .globl _RXD
+ .globl _P3_7
+ .globl _P3_6
+ .globl _P3_5
+ .globl _P3_4
+ .globl _P3_3
+ .globl _P3_2
+ .globl _P3_1
+ .globl _P3_0
+ .globl _EA
+ .globl _ES
+ .globl _ET1
+ .globl _EX1
+ .globl _ET0
+ .globl _EX0
+ .globl _P2_7
+ .globl _P2_6
+ .globl _P2_5
+ .globl _P2_4
+ .globl _P2_3
+ .globl _P2_2
+ .globl _P2_1
+ .globl _P2_0
+ .globl _SM0
+ .globl _SM1
+ .globl _SM2
+ .globl _REN
+ .globl _TB8
+ .globl _RB8
+ .globl _TI
+ .globl _RI
+ .globl _P1_7
+ .globl _P1_6
+ .globl _P1_5
+ .globl _P1_4
+ .globl _P1_3
+ .globl _P1_2
+ .globl _P1_1
+ .globl _P1_0
+ .globl _TF1
+ .globl _TR1
+ .globl _TF0
+ .globl _TR0
+ .globl _IE1
+ .globl _IT1
+ .globl _IE0
+ .globl _IT0
+ .globl _P0_7
+ .globl _P0_6
+ .globl _P0_5
+ .globl _P0_4
+ .globl _P0_3
+ .globl _P0_2
+ .globl _P0_1
+ .globl _P0_0
+ .globl _B
+ .globl _ACC
+ .globl _PSW
+ .globl _IP
+ .globl _P3
+ .globl _IE
+ .globl _P2
+ .globl _SBUF
+ .globl _SCON
+ .globl _P1
+ .globl _TH1
+ .globl _TH0
+ .globl _TL1
+ .globl _TL0
+ .globl _TMOD
+ .globl _TCON
+ .globl _PCON
+ .globl _DPH
+ .globl _DPL
+ .globl _SP
+ .globl _P0
+ .globl _row
+ .globl _state
+;--------------------------------------------------------
+; special function registers
+;--------------------------------------------------------
+ .area RSEG (DATA)
+G$P0$0$0 == 0x0080
+_P0 = 0x0080
+G$SP$0$0 == 0x0081
+_SP = 0x0081
+G$DPL$0$0 == 0x0082
+_DPL = 0x0082
+G$DPH$0$0 == 0x0083
+_DPH = 0x0083
+G$PCON$0$0 == 0x0087
+_PCON = 0x0087
+G$TCON$0$0 == 0x0088
+_TCON = 0x0088
+G$TMOD$0$0 == 0x0089
+_TMOD = 0x0089
+G$TL0$0$0 == 0x008a
+_TL0 = 0x008a
+G$TL1$0$0 == 0x008b
+_TL1 = 0x008b
+G$TH0$0$0 == 0x008c
+_TH0 = 0x008c
+G$TH1$0$0 == 0x008d
+_TH1 = 0x008d
+G$P1$0$0 == 0x0090
+_P1 = 0x0090
+G$SCON$0$0 == 0x0098
+_SCON = 0x0098
+G$SBUF$0$0 == 0x0099
+_SBUF = 0x0099
+G$P2$0$0 == 0x00a0
+_P2 = 0x00a0
+G$IE$0$0 == 0x00a8
+_IE = 0x00a8
+G$P3$0$0 == 0x00b0
+_P3 = 0x00b0
+G$IP$0$0 == 0x00b8
+_IP = 0x00b8
+G$PSW$0$0 == 0x00d0
+_PSW = 0x00d0
+G$ACC$0$0 == 0x00e0
+_ACC = 0x00e0
+G$B$0$0 == 0x00f0
+_B = 0x00f0
+;--------------------------------------------------------
+; special function bits
+;--------------------------------------------------------
+ .area RSEG (DATA)
+G$P0_0$0$0 == 0x0080
+_P0_0 = 0x0080
+G$P0_1$0$0 == 0x0081
+_P0_1 = 0x0081
+G$P0_2$0$0 == 0x0082
+_P0_2 = 0x0082
+G$P0_3$0$0 == 0x0083
+_P0_3 = 0x0083
+G$P0_4$0$0 == 0x0084
+_P0_4 = 0x0084
+G$P0_5$0$0 == 0x0085
+_P0_5 = 0x0085
+G$P0_6$0$0 == 0x0086
+_P0_6 = 0x0086
+G$P0_7$0$0 == 0x0087
+_P0_7 = 0x0087
+G$IT0$0$0 == 0x0088
+_IT0 = 0x0088
+G$IE0$0$0 == 0x0089
+_IE0 = 0x0089
+G$IT1$0$0 == 0x008a
+_IT1 = 0x008a
+G$IE1$0$0 == 0x008b
+_IE1 = 0x008b
+G$TR0$0$0 == 0x008c
+_TR0 = 0x008c
+G$TF0$0$0 == 0x008d
+_TF0 = 0x008d
+G$TR1$0$0 == 0x008e
+_TR1 = 0x008e
+G$TF1$0$0 == 0x008f
+_TF1 = 0x008f
+G$P1_0$0$0 == 0x0090
+_P1_0 = 0x0090
+G$P1_1$0$0 == 0x0091
+_P1_1 = 0x0091
+G$P1_2$0$0 == 0x0092
+_P1_2 = 0x0092
+G$P1_3$0$0 == 0x0093
+_P1_3 = 0x0093
+G$P1_4$0$0 == 0x0094
+_P1_4 = 0x0094
+G$P1_5$0$0 == 0x0095
+_P1_5 = 0x0095
+G$P1_6$0$0 == 0x0096
+_P1_6 = 0x0096
+G$P1_7$0$0 == 0x0097
+_P1_7 = 0x0097
+G$RI$0$0 == 0x0098
+_RI = 0x0098
+G$TI$0$0 == 0x0099
+_TI = 0x0099
+G$RB8$0$0 == 0x009a
+_RB8 = 0x009a
+G$TB8$0$0 == 0x009b
+_TB8 = 0x009b
+G$REN$0$0 == 0x009c
+_REN = 0x009c
+G$SM2$0$0 == 0x009d
+_SM2 = 0x009d
+G$SM1$0$0 == 0x009e
+_SM1 = 0x009e
+G$SM0$0$0 == 0x009f
+_SM0 = 0x009f
+G$P2_0$0$0 == 0x00a0
+_P2_0 = 0x00a0
+G$P2_1$0$0 == 0x00a1
+_P2_1 = 0x00a1
+G$P2_2$0$0 == 0x00a2
+_P2_2 = 0x00a2
+G$P2_3$0$0 == 0x00a3
+_P2_3 = 0x00a3
+G$P2_4$0$0 == 0x00a4
+_P2_4 = 0x00a4
+G$P2_5$0$0 == 0x00a5
+_P2_5 = 0x00a5
+G$P2_6$0$0 == 0x00a6
+_P2_6 = 0x00a6
+G$P2_7$0$0 == 0x00a7
+_P2_7 = 0x00a7
+G$EX0$0$0 == 0x00a8
+_EX0 = 0x00a8
+G$ET0$0$0 == 0x00a9
+_ET0 = 0x00a9
+G$EX1$0$0 == 0x00aa
+_EX1 = 0x00aa
+G$ET1$0$0 == 0x00ab
+_ET1 = 0x00ab
+G$ES$0$0 == 0x00ac
+_ES = 0x00ac
+G$EA$0$0 == 0x00af
+_EA = 0x00af
+G$P3_0$0$0 == 0x00b0
+_P3_0 = 0x00b0
+G$P3_1$0$0 == 0x00b1
+_P3_1 = 0x00b1
+G$P3_2$0$0 == 0x00b2
+_P3_2 = 0x00b2
+G$P3_3$0$0 == 0x00b3
+_P3_3 = 0x00b3
+G$P3_4$0$0 == 0x00b4
+_P3_4 = 0x00b4
+G$P3_5$0$0 == 0x00b5
+_P3_5 = 0x00b5
+G$P3_6$0$0 == 0x00b6
+_P3_6 = 0x00b6
+G$P3_7$0$0 == 0x00b7
+_P3_7 = 0x00b7
+G$RXD$0$0 == 0x00b0
+_RXD = 0x00b0
+G$TXD$0$0 == 0x00b1
+_TXD = 0x00b1
+G$INT0$0$0 == 0x00b2
+_INT0 = 0x00b2
+G$INT1$0$0 == 0x00b3
+_INT1 = 0x00b3
+G$T0$0$0 == 0x00b4
+_T0 = 0x00b4
+G$T1$0$0 == 0x00b5
+_T1 = 0x00b5
+G$WR$0$0 == 0x00b6
+_WR = 0x00b6
+G$RD$0$0 == 0x00b7
+_RD = 0x00b7
+G$PX0$0$0 == 0x00b8
+_PX0 = 0x00b8
+G$PT0$0$0 == 0x00b9
+_PT0 = 0x00b9
+G$PX1$0$0 == 0x00ba
+_PX1 = 0x00ba
+G$PT1$0$0 == 0x00bb
+_PT1 = 0x00bb
+G$PS$0$0 == 0x00bc
+_PS = 0x00bc
+G$P$0$0 == 0x00d0
+_P = 0x00d0
+G$F1$0$0 == 0x00d1
+_F1 = 0x00d1
+G$OV$0$0 == 0x00d2
+_OV = 0x00d2
+G$RS0$0$0 == 0x00d3
+_RS0 = 0x00d3
+G$RS1$0$0 == 0x00d4
+_RS1 = 0x00d4
+G$F0$0$0 == 0x00d5
+_F0 = 0x00d5
+G$AC$0$0 == 0x00d6
+_AC = 0x00d6
+G$CY$0$0 == 0x00d7
+_CY = 0x00d7
+;--------------------------------------------------------
+; overlayable register banks
+;--------------------------------------------------------
+ .area REG_BANK_0 (REL,OVR,DATA)
+ .ds 8
+;--------------------------------------------------------
+; internal ram data
+;--------------------------------------------------------
+ .area DSEG (DATA)
+G$state$0$0==.
+_state::
+ .ds 1
+G$row$0$0==.
+_row::
+ .ds 2
+;--------------------------------------------------------
+; overlayable items in internal ram
+;--------------------------------------------------------
+ .area OSEG (OVR,DATA)
+;--------------------------------------------------------
+; Stack segment in internal ram
+;--------------------------------------------------------
+ .area SSEG (DATA)
+__start__stack:
+ .ds 1
+
+;--------------------------------------------------------
+; indirectly addressable internal ram data
+;--------------------------------------------------------
+ .area ISEG (DATA)
+;--------------------------------------------------------
+; absolute internal ram data
+;--------------------------------------------------------
+ .area IABS (ABS,DATA)
+ .area IABS (ABS,DATA)
+;--------------------------------------------------------
+; bit data
+;--------------------------------------------------------
+ .area BSEG (BIT)
+;--------------------------------------------------------
+; paged external ram data
+;--------------------------------------------------------
+ .area PSEG (PAG,XDATA)
+;--------------------------------------------------------
+; external ram data
+;--------------------------------------------------------
+ .area XSEG (XDATA)
+;--------------------------------------------------------
+; absolute external ram data
+;--------------------------------------------------------
+ .area XABS (ABS,XDATA)
+;--------------------------------------------------------
+; external initialized ram data
+;--------------------------------------------------------
+ .area XISEG (XDATA)
+ .area HOME (CODE)
+ .area GSINIT0 (CODE)
+ .area GSINIT1 (CODE)
+ .area GSINIT2 (CODE)
+ .area GSINIT3 (CODE)
+ .area GSINIT4 (CODE)
+ .area GSINIT5 (CODE)
+ .area GSINIT (CODE)
+ .area GSFINAL (CODE)
+ .area CSEG (CODE)
+;--------------------------------------------------------
+; interrupt vector
+;--------------------------------------------------------
+ .area HOME (CODE)
+__interrupt_vect:
+ ljmp __sdcc_gsinit_startup
+;--------------------------------------------------------
+; global & static initialisations
+;--------------------------------------------------------
+ .area HOME (CODE)
+ .area GSINIT (CODE)
+ .area GSFINAL (CODE)
+ .area GSINIT (CODE)
+ .globl __sdcc_gsinit_startup
+ .globl __sdcc_program_startup
+ .globl __start__stack
+ .globl __mcs51_genXINIT
+ .globl __mcs51_genXRAMCLEAR
+ .globl __mcs51_genRAMCLEAR
+ .area GSFINAL (CODE)
+ ljmp __sdcc_program_startup
+;--------------------------------------------------------
+; Home
+;--------------------------------------------------------
+ .area HOME (CODE)
+ .area HOME (CODE)
+__sdcc_program_startup:
+ lcall _main
+; return from main will lock up
+ sjmp .
+;--------------------------------------------------------
+; code
+;--------------------------------------------------------
+ .area CSEG (CODE)
+;------------------------------------------------------------
+;Allocation info for local variables in function 'main'
+;------------------------------------------------------------
+;------------------------------------------------------------
+ G$main$0$0 ==.
+ C$keypad_display.c$38$0$0 ==.
+; keypad_display.c:38: int main()
+; -----------------------------------------
+; function main
+; -----------------------------------------
+_main:
+ ar2 = 0x02
+ ar3 = 0x03
+ ar4 = 0x04
+ ar5 = 0x05
+ ar6 = 0x06
+ ar7 = 0x07
+ ar0 = 0x00
+ ar1 = 0x01
+ C$keypad_display.c$40$1$1 ==.
+; keypad_display.c:40: while(1) {
+00123$:
+ C$keypad_display.c$41$2$2 ==.
+; keypad_display.c:41: for(row=0; row<4; row++) {
+ clr a
+ mov _row,a
+ mov (_row + 1),a
+00118$:
+ clr c
+ mov a,_row
+ subb a,#0x04
+ mov a,(_row + 1)
+ xrl a,#0x80
+ subb a,#0x80
+ jnc 00123$
+ C$keypad_display.c$42$3$3 ==.
+; keypad_display.c:42: P1=keypad[row];
+ mov a,_row
+ add a,#_keypad
+ mov dpl,a
+ mov a,(_row + 1)
+ addc a,#(_keypad >> 8)
+ mov dph,a
+ clr a
+ movc a,@a+dptr
+ mov _P1,a
+ C$keypad_display.c$48$3$3 ==.
+; keypad_display.c:48: _endasm;
+
+ mov _state, P1
+
+ C$keypad_display.c$53$3$3 ==.
+; keypad_display.c:53: state&=0x0f;
+ anl _state,#0x0F
+ C$keypad_display.c$54$3$3 ==.
+; keypad_display.c:54: state^=0x0f;
+ xrl _state,#0x0F
+ C$keypad_display.c$56$3$3 ==.
+; keypad_display.c:56: if(state & 1) {
+ mov a,_state
+ jnb acc.0,00111$
+ C$keypad_display.c$57$4$4 ==.
+; keypad_display.c:57: state=0;
+ mov _state,#0x00
+ sjmp 00112$
+00111$:
+ C$keypad_display.c$58$3$3 ==.
+; keypad_display.c:58: } else if(state & 2) {
+ mov a,_state
+ jnb acc.1,00108$
+ C$keypad_display.c$59$4$5 ==.
+; keypad_display.c:59: state=1;
+ mov _state,#0x01
+ sjmp 00112$
+00108$:
+ C$keypad_display.c$60$3$3 ==.
+; keypad_display.c:60: } else if(state & 4) {
+ mov a,_state
+ jnb acc.2,00105$
+ C$keypad_display.c$61$4$6 ==.
+; keypad_display.c:61: state=2;
+ mov _state,#0x02
+ sjmp 00112$
+00105$:
+ C$keypad_display.c$62$3$3 ==.
+; keypad_display.c:62: } else if(state & 8) {
+ mov a,_state
+ jb acc.3,00142$
+ ljmp 00120$
+00142$:
+ C$keypad_display.c$63$4$7 ==.
+; keypad_display.c:63: state=3;
+ mov _state,#0x03
+ C$keypad_display.c$65$3$3 ==.
+; keypad_display.c:65: continue;
+00112$:
+ C$keypad_display.c$68$3$3 ==.
+; keypad_display.c:68: switch(row) {
+ clr a
+ cjne a,_row,00143$
+ clr a
+ cjne a,(_row + 1),00143$
+ sjmp 00113$
+00143$:
+ mov a,#0x01
+ cjne a,_row,00144$
+ clr a
+ cjne a,(_row + 1),00144$
+ sjmp 00114$
+00144$:
+ mov a,#0x02
+ cjne a,_row,00145$
+ clr a
+ cjne a,(_row + 1),00145$
+ sjmp 00115$
+00145$:
+ mov a,#0x03
+ cjne a,_row,00146$
+ clr a
+ cjne a,(_row + 1),00146$
+ sjmp 00116$
+00146$:
+ C$keypad_display.c$69$4$9 ==.
+; keypad_display.c:69: case 0:
+ sjmp 00120$
+00113$:
+ C$keypad_display.c$70$4$9 ==.
+; keypad_display.c:70: P3=display_0[state];
+ mov a,_state
+ mov dptr,#_display_0
+ movc a,@a+dptr
+ mov _P3,a
+ C$keypad_display.c$71$4$9 ==.
+; keypad_display.c:71: break;
+ C$keypad_display.c$72$4$9 ==.
+; keypad_display.c:72: case 1:
+ sjmp 00120$
+00114$:
+ C$keypad_display.c$73$4$9 ==.
+; keypad_display.c:73: P3=display_1[state];
+ mov a,_state
+ mov dptr,#_display_1
+ movc a,@a+dptr
+ mov _P3,a
+ C$keypad_display.c$74$4$9 ==.
+; keypad_display.c:74: break;
+ C$keypad_display.c$75$4$9 ==.
+; keypad_display.c:75: case 2:
+ sjmp 00120$
+00115$:
+ C$keypad_display.c$76$4$9 ==.
+; keypad_display.c:76: P3=display_2[state];
+ mov a,_state
+ mov dptr,#_display_2
+ movc a,@a+dptr
+ mov _P3,a
+ C$keypad_display.c$77$4$9 ==.
+; keypad_display.c:77: break;
+ C$keypad_display.c$78$4$9 ==.
+; keypad_display.c:78: case 3:
+ sjmp 00120$
+00116$:
+ C$keypad_display.c$79$4$9 ==.
+; keypad_display.c:79: P3=display_3[state];
+ mov a,_state
+ mov dptr,#_display_3
+ movc a,@a+dptr
+ mov _P3,a
+ C$keypad_display.c$81$2$2 ==.
+; keypad_display.c:81: }
+00120$:
+ C$keypad_display.c$41$2$2 ==.
+; keypad_display.c:41: for(row=0; row<4; row++) {
+ inc _row
+ clr a
+ cjne a,_row,00147$
+ inc (_row + 1)
+00147$:
+ C$keypad_display.c$84$1$1 ==.
+ XG$main$0$0 ==.
+ ljmp 00118$
+ .area CSEG (CODE)
+ .area CONST (CODE)
+Fkeypad_display$keypad$0$0 == .
+_keypad:
+ .db #0xEF
+ .db #0xDF
+ .db #0xBF
+ .db #0x7F
+Fkeypad_display$display_0$0$0 == .
+_display_0:
+ .db #0xF9
+ .db #0x64
+ .db #0x70
+ .db #0x48
+Fkeypad_display$display_1$0$0 == .
+_display_1:
+ .db #0x59
+ .db #0x52
+ .db #0x42
+ .db #0x40
+Fkeypad_display$display_2$0$0 == .
+_display_2:
+ .db #0xF8
+ .db #0x40
+ .db #0x50
+ .db #0xC6
+Fkeypad_display$display_3$0$0 == .
+_display_3:
+ .db #0x79
+ .db #0xC0
+ .db #0x49
+ .db #0xC0
+ .area XINIT (CODE)
+ .area CABS (ABS,CODE)
diff --git a/demo/keypad_display.c b/demo/keypad_display.c
new file mode 100644
index 0000000..e6cadf6
--- /dev/null
+++ b/demo/keypad_display.c
@@ -0,0 +1,84 @@
+/**
+ * Demonstration code for MCU 8051 IDE
+ *
+ * Create virtual multiplexed LED display
+ * [Main menu] -> [Virtual HW] -> [Open]
+ * and open file keypad_display.vhw .
+ * Then press F2 and F9 to start simulation.
+ *
+ * Notes:
+ * F9 - stop simulation
+ * F2 - shutdown simulator
+ *
+ * @file keypad_display.c
+ */
+
+#include <8051.h>
+#define USE_INLINE_ASM 1
+
+static const char keypad[] = {
+ 0xEF, 0xDF, 0xBF, 0x7F
+};
+static const char display_0[] = {
+ 0xf9, 0x64, 0x70, 0x48
+};
+static const char display_1[] = {
+ 0x59, 0x52, 0x42, 0x40
+};
+static const char display_2[] = {
+ 0xf8, 0x40, 0x50, 0xc6
+};
+static const char display_3[] = {
+ 0x79, 0xc0, 0x49, 0xc0
+};
+
+char state;
+int row;
+
+int main()
+{
+ while(1) {
+ for(row=0; row<4; row++) {
+ P1=keypad[row];
+
+ #if USE_INLINE_ASM
+ // Inline assembler
+ _asm
+ mov _state, P1
+ _endasm;
+ #else
+ state=P1;
+ #endif
+
+ state&=0x0f;
+ state^=0x0f;
+
+ if(state & 1) {
+ state=0;
+ } else if(state & 2) {
+ state=1;
+ } else if(state & 4) {
+ state=2;
+ } else if(state & 8) {
+ state=3;
+ } else {
+ continue;
+ }
+
+ switch(row) {
+ case 0:
+ P3=display_0[state];
+ break;
+ case 1:
+ P3=display_1[state];
+ break;
+ case 2:
+ P3=display_2[state];
+ break;
+ case 3:
+ P3=display_3[state];
+ break;
+ }
+ }
+ }
+}
diff --git a/demo/keypad_display.cdb b/demo/keypad_display.cdb
new file mode 100644
index 0000000..a0420fc
--- /dev/null
+++ b/demo/keypad_display.cdb
@@ -0,0 +1,328 @@
+M:keypad_display
+F:G$main$0$0({2}DF,SI:S),C,0,0,0,0,0
+S:G$state$0$0({1}SC:S),E,0,0
+S:G$row$0$0({2}SI:S),E,0,0
+S:G$P0$0$0({1}SC:U),I,0,0
+S:G$SP$0$0({1}SC:U),I,0,0
+S:G$DPL$0$0({1}SC:U),I,0,0
+S:G$DPH$0$0({1}SC:U),I,0,0
+S:G$PCON$0$0({1}SC:U),I,0,0
+S:G$TCON$0$0({1}SC:U),I,0,0
+S:G$TMOD$0$0({1}SC:U),I,0,0
+S:G$TL0$0$0({1}SC:U),I,0,0
+S:G$TL1$0$0({1}SC:U),I,0,0
+S:G$TH0$0$0({1}SC:U),I,0,0
+S:G$TH1$0$0({1}SC:U),I,0,0
+S:G$P1$0$0({1}SC:U),I,0,0
+S:G$SCON$0$0({1}SC:U),I,0,0
+S:G$SBUF$0$0({1}SC:U),I,0,0
+S:G$P2$0$0({1}SC:U),I,0,0
+S:G$IE$0$0({1}SC:U),I,0,0
+S:G$P3$0$0({1}SC:U),I,0,0
+S:G$IP$0$0({1}SC:U),I,0,0
+S:G$PSW$0$0({1}SC:U),I,0,0
+S:G$ACC$0$0({1}SC:U),I,0,0
+S:G$B$0$0({1}SC:U),I,0,0
+S:G$P0_0$0$0({1}SX:U),J,0,0
+S:G$P0_1$0$0({1}SX:U),J,0,0
+S:G$P0_2$0$0({1}SX:U),J,0,0
+S:G$P0_3$0$0({1}SX:U),J,0,0
+S:G$P0_4$0$0({1}SX:U),J,0,0
+S:G$P0_5$0$0({1}SX:U),J,0,0
+S:G$P0_6$0$0({1}SX:U),J,0,0
+S:G$P0_7$0$0({1}SX:U),J,0,0
+S:G$IT0$0$0({1}SX:U),J,0,0
+S:G$IE0$0$0({1}SX:U),J,0,0
+S:G$IT1$0$0({1}SX:U),J,0,0
+S:G$IE1$0$0({1}SX:U),J,0,0
+S:G$TR0$0$0({1}SX:U),J,0,0
+S:G$TF0$0$0({1}SX:U),J,0,0
+S:G$TR1$0$0({1}SX:U),J,0,0
+S:G$TF1$0$0({1}SX:U),J,0,0
+S:G$P1_0$0$0({1}SX:U),J,0,0
+S:G$P1_1$0$0({1}SX:U),J,0,0
+S:G$P1_2$0$0({1}SX:U),J,0,0
+S:G$P1_3$0$0({1}SX:U),J,0,0
+S:G$P1_4$0$0({1}SX:U),J,0,0
+S:G$P1_5$0$0({1}SX:U),J,0,0
+S:G$P1_6$0$0({1}SX:U),J,0,0
+S:G$P1_7$0$0({1}SX:U),J,0,0
+S:G$RI$0$0({1}SX:U),J,0,0
+S:G$TI$0$0({1}SX:U),J,0,0
+S:G$RB8$0$0({1}SX:U),J,0,0
+S:G$TB8$0$0({1}SX:U),J,0,0
+S:G$REN$0$0({1}SX:U),J,0,0
+S:G$SM2$0$0({1}SX:U),J,0,0
+S:G$SM1$0$0({1}SX:U),J,0,0
+S:G$SM0$0$0({1}SX:U),J,0,0
+S:G$P2_0$0$0({1}SX:U),J,0,0
+S:G$P2_1$0$0({1}SX:U),J,0,0
+S:G$P2_2$0$0({1}SX:U),J,0,0
+S:G$P2_3$0$0({1}SX:U),J,0,0
+S:G$P2_4$0$0({1}SX:U),J,0,0
+S:G$P2_5$0$0({1}SX:U),J,0,0
+S:G$P2_6$0$0({1}SX:U),J,0,0
+S:G$P2_7$0$0({1}SX:U),J,0,0
+S:G$EX0$0$0({1}SX:U),J,0,0
+S:G$ET0$0$0({1}SX:U),J,0,0
+S:G$EX1$0$0({1}SX:U),J,0,0
+S:G$ET1$0$0({1}SX:U),J,0,0
+S:G$ES$0$0({1}SX:U),J,0,0
+S:G$EA$0$0({1}SX:U),J,0,0
+S:G$P3_0$0$0({1}SX:U),J,0,0
+S:G$P3_1$0$0({1}SX:U),J,0,0
+S:G$P3_2$0$0({1}SX:U),J,0,0
+S:G$P3_3$0$0({1}SX:U),J,0,0
+S:G$P3_4$0$0({1}SX:U),J,0,0
+S:G$P3_5$0$0({1}SX:U),J,0,0
+S:G$P3_6$0$0({1}SX:U),J,0,0
+S:G$P3_7$0$0({1}SX:U),J,0,0
+S:G$RXD$0$0({1}SX:U),J,0,0
+S:G$TXD$0$0({1}SX:U),J,0,0
+S:G$INT0$0$0({1}SX:U),J,0,0
+S:G$INT1$0$0({1}SX:U),J,0,0
+S:G$T0$0$0({1}SX:U),J,0,0
+S:G$T1$0$0({1}SX:U),J,0,0
+S:G$WR$0$0({1}SX:U),J,0,0
+S:G$RD$0$0({1}SX:U),J,0,0
+S:G$PX0$0$0({1}SX:U),J,0,0
+S:G$PT0$0$0({1}SX:U),J,0,0
+S:G$PX1$0$0({1}SX:U),J,0,0
+S:G$PT1$0$0({1}SX:U),J,0,0
+S:G$PS$0$0({1}SX:U),J,0,0
+S:G$P$0$0({1}SX:U),J,0,0
+S:G$F1$0$0({1}SX:U),J,0,0
+S:G$OV$0$0({1}SX:U),J,0,0
+S:G$RS0$0$0({1}SX:U),J,0,0
+S:G$RS1$0$0({1}SX:U),J,0,0
+S:G$F0$0$0({1}SX:U),J,0,0
+S:G$AC$0$0({1}SX:U),J,0,0
+S:G$CY$0$0({1}SX:U),J,0,0
+S:G$main$0$0({2}DF,SI:S),C,0,0
+S:Fkeypad_display$keypad$0$0({4}DA4,SC:S),D,0,0
+S:Fkeypad_display$display_0$0$0({4}DA4,SC:S),D,0,0
+S:Fkeypad_display$display_1$0$0({4}DA4,SC:S),D,0,0
+S:Fkeypad_display$display_2$0$0({4}DA4,SC:S),D,0,0
+S:Fkeypad_display$display_3$0$0({4}DA4,SC:S),D,0,0
+L:G$P0$0$0:80
+L:G$P0_0$0$0:80
+L:G$P0_1$0$0:81
+L:G$SP$0$0:81
+L:G$DPL$0$0:82
+L:G$P0_2$0$0:82
+L:G$DPH$0$0:83
+L:G$P0_3$0$0:83
+L:G$P0_4$0$0:84
+L:G$P0_5$0$0:85
+L:G$P0_6$0$0:86
+L:G$P0_7$0$0:87
+L:G$PCON$0$0:87
+L:G$IT0$0$0:88
+L:G$TCON$0$0:88
+L:G$IE0$0$0:89
+L:G$TMOD$0$0:89
+L:G$IT1$0$0:8A
+L:G$TL0$0$0:8A
+L:G$IE1$0$0:8B
+L:G$TL1$0$0:8B
+L:G$TH0$0$0:8C
+L:G$TR0$0$0:8C
+L:G$TF0$0$0:8D
+L:G$TH1$0$0:8D
+L:G$TR1$0$0:8E
+L:G$TF1$0$0:8F
+L:G$P1$0$0:90
+L:G$P1_0$0$0:90
+L:G$P1_1$0$0:91
+L:G$P1_2$0$0:92
+L:G$P1_3$0$0:93
+L:G$P1_4$0$0:94
+L:G$P1_5$0$0:95
+L:G$P1_6$0$0:96
+L:G$P1_7$0$0:97
+L:G$RI$0$0:98
+L:G$SCON$0$0:98
+L:G$SBUF$0$0:99
+L:G$TI$0$0:99
+L:G$RB8$0$0:9A
+L:G$TB8$0$0:9B
+L:G$REN$0$0:9C
+L:G$SM2$0$0:9D
+L:G$SM1$0$0:9E
+L:G$SM0$0$0:9F
+L:G$P2$0$0:A0
+L:G$P2_0$0$0:A0
+L:G$P2_1$0$0:A1
+L:G$P2_2$0$0:A2
+L:G$P2_3$0$0:A3
+L:G$P2_4$0$0:A4
+L:G$P2_5$0$0:A5
+L:G$P2_6$0$0:A6
+L:G$P2_7$0$0:A7
+L:G$EX0$0$0:A8
+L:G$IE$0$0:A8
+L:G$ET0$0$0:A9
+L:G$EX1$0$0:AA
+L:G$ET1$0$0:AB
+L:G$ES$0$0:AC
+L:G$EA$0$0:AF
+L:G$P3$0$0:B0
+L:G$P3_0$0$0:B0
+L:G$RXD$0$0:B0
+L:G$P3_1$0$0:B1
+L:G$TXD$0$0:B1
+L:G$INT0$0$0:B2
+L:G$P3_2$0$0:B2
+L:G$INT1$0$0:B3
+L:G$P3_3$0$0:B3
+L:G$P3_4$0$0:B4
+L:G$T0$0$0:B4
+L:G$P3_5$0$0:B5
+L:G$T1$0$0:B5
+L:G$P3_6$0$0:B6
+L:G$WR$0$0:B6
+L:G$P3_7$0$0:B7
+L:G$RD$0$0:B7
+L:G$IP$0$0:B8
+L:G$PX0$0$0:B8
+L:G$PT0$0$0:B9
+L:G$PX1$0$0:BA
+L:G$PT1$0$0:BB
+L:G$PS$0$0:BC
+L:G$P$0$0:D0
+L:G$PSW$0$0:D0
+L:G$F1$0$0:D1
+L:G$OV$0$0:D2
+L:G$RS0$0$0:D3
+L:G$RS1$0$0:D4
+L:G$F0$0$0:D5
+L:G$AC$0$0:D6
+L:G$CY$0$0:D7
+L:G$ACC$0$0:E0
+L:G$B$0$0:F0
+L:G$state$0$0:8
+L:G$row$0$0:9
+L:A$keypad_display$381:0
+L:A$keypad_display$403:3
+L:A$keypad_display$405:6
+L:A$keypad_display$396:61
+L:A$keypad_display$434:64
+L:C$keypad_display.c$38$0$0:64
+L:C$keypad_display.c$40$1$1:64
+L:G$main$0$0:64
+L:A$keypad_display$435:65
+L:A$keypad_display$436:67
+L:A$keypad_display$438:69
+L:A$keypad_display$439:6A
+L:A$keypad_display$440:6C
+L:A$keypad_display$441:6E
+L:A$keypad_display$442:70
+L:A$keypad_display$443:72
+L:A$keypad_display$444:74
+L:A$keypad_display$447:76
+L:C$keypad_display.c$42$3$3:76
+L:A$keypad_display$448:78
+L:A$keypad_display$449:7A
+L:A$keypad_display$450:7C
+L:A$keypad_display$451:7E
+L:A$keypad_display$452:80
+L:A$keypad_display$453:82
+L:A$keypad_display$454:83
+L:A$keypad_display$455:84
+L:A$keypad_display$459:86
+L:C$keypad_display.c$48$3$3:86
+L:A$keypad_display$463:89
+L:C$keypad_display.c$53$3$3:89
+L:A$keypad_display$466:8C
+L:C$keypad_display.c$54$3$3:8C
+L:A$keypad_display$469:8F
+L:C$keypad_display.c$56$3$3:8F
+L:A$keypad_display$470:91
+L:A$keypad_display$473:94
+L:C$keypad_display.c$57$4$4:94
+L:A$keypad_display$474:97
+L:A$keypad_display$478:99
+L:C$keypad_display.c$58$3$3:99
+L:A$keypad_display$479:9B
+L:A$keypad_display$482:9E
+L:C$keypad_display.c$59$4$5:9E
+L:A$keypad_display$483:A1
+L:A$keypad_display$487:A3
+L:C$keypad_display.c$60$3$3:A3
+L:A$keypad_display$488:A5
+L:A$keypad_display$491:A8
+L:C$keypad_display.c$61$4$6:A8
+L:A$keypad_display$492:AB
+L:A$keypad_display$496:AD
+L:C$keypad_display.c$62$3$3:AD
+L:A$keypad_display$497:AF
+L:A$keypad_display$498:B2
+L:A$keypad_display$502:B5
+L:C$keypad_display.c$63$4$7:B5
+L:A$keypad_display$508:B8
+L:C$keypad_display.c$65$3$3:B8
+L:C$keypad_display.c$68$3$3:B8
+L:A$keypad_display$509:B9
+L:A$keypad_display$510:BC
+L:A$keypad_display$511:BD
+L:A$keypad_display$512:C0
+L:A$keypad_display$514:C2
+L:A$keypad_display$515:C4
+L:A$keypad_display$516:C7
+L:A$keypad_display$517:C8
+L:A$keypad_display$518:CB
+L:A$keypad_display$520:CD
+L:A$keypad_display$521:CF
+L:A$keypad_display$522:D2
+L:A$keypad_display$523:D3
+L:A$keypad_display$524:D6
+L:A$keypad_display$526:D8
+L:A$keypad_display$527:DA
+L:A$keypad_display$528:DD
+L:A$keypad_display$529:DE
+L:A$keypad_display$530:E1
+L:A$keypad_display$534:E3
+L:C$keypad_display.c$69$4$9:E3
+L:A$keypad_display$538:E5
+L:C$keypad_display.c$70$4$9:E5
+L:A$keypad_display$539:E7
+L:A$keypad_display$540:EA
+L:A$keypad_display$541:EB
+L:A$keypad_display$546:ED
+L:C$keypad_display.c$71$4$9:ED
+L:C$keypad_display.c$72$4$9:ED
+L:A$keypad_display$550:EF
+L:C$keypad_display.c$73$4$9:EF
+L:A$keypad_display$551:F1
+L:A$keypad_display$552:F4
+L:A$keypad_display$553:F5
+L:A$keypad_display$558:F7
+L:C$keypad_display.c$74$4$9:F7
+L:C$keypad_display.c$75$4$9:F7
+L:A$keypad_display$562:F9
+L:C$keypad_display.c$76$4$9:F9
+L:A$keypad_display$563:FB
+L:A$keypad_display$564:FE
+L:A$keypad_display$565:FF
+L:A$keypad_display$570:101
+L:C$keypad_display.c$77$4$9:101
+L:C$keypad_display.c$78$4$9:101
+L:A$keypad_display$574:103
+L:C$keypad_display.c$79$4$9:103
+L:A$keypad_display$575:105
+L:A$keypad_display$576:108
+L:A$keypad_display$577:109
+L:A$keypad_display$583:10B
+L:C$keypad_display.c$41$2$2:10B
+L:C$keypad_display.c$81$2$2:10B
+L:A$keypad_display$584:10D
+L:A$keypad_display$585:10E
+L:A$keypad_display$586:111
+L:A$keypad_display$590:113
+L:C$keypad_display.c$84$1$1:113
+L:XG$main$0$0:113
+L:Fkeypad_display$keypad$0$0:11A
+L:Fkeypad_display$display_0$0$0:11E
+L:Fkeypad_display$display_1$0$0:122
+L:Fkeypad_display$display_2$0$0:126
+L:Fkeypad_display$display_3$0$0:12A
diff --git a/demo/keypad_display.hashes b/demo/keypad_display.hashes
new file mode 100644
index 0000000..55868bd
--- /dev/null
+++ b/demo/keypad_display.hashes
@@ -0,0 +1 @@
+E44E4DC2094E8EB729FE653002B40A33 "keypad_display.c"
diff --git a/demo/keypad_display.hex b/demo/keypad_display.hex
new file mode 100644
index 0000000..b62bfae
--- /dev/null
+++ b/demo/keypad_display.hex
@@ -0,0 +1,49 @@
+:03000000020008F3
+:0300610002000397
+:0500030012006480FE04
+:05006400E4F509F50AB6
+:0A006900C3E5099404E50A648094DD
+:0A0073008050EEE509241AF582E53D
+:0A007D000A3401F583E493F5908541
+:06008700900853080F630E
+:08008D00080FE50830E00575DD
+:040095000800801FC0
+:0A009900E50830E105750801801547
+:0A00A300E50830E205750802800B45
+:0800AD00E50820E30302010B4A
+:0300B500750803C8
+:0A00B800E4B50906E4B50A0280234E
+:0A00C2007401B50906E4B50A0280D6
+:0100CC002211
+:0A00CD007402B50906E4B50A0280CA
+:0100D7002107
+:0A00D8007403B50906E4B50A0280BE
+:0100E20020FD
+:0200E300802675
+:0A00E500E50890011E93F5B0801CA1
+:0A00EF00E50890012293F5B080129D
+:0A00F900E50890012693F5B0800899
+:08010300E50890012A93F5B014
+:07010B000509E4B509020536
+:010112000AE2
+:030113000200697E
+:04011A00EFDFBF7FD5
+:04011E00F9647048C8
+:0401220059524240AC
+:04012600F84050C687
+:04012A0079C049C08F
+:06003700E478FFF6D8FD9D
+:080015007900E94400601B7A48
+:05001D000090012E78A7
+:030022000075A0C6
+:0A00250000E493F2A308B8000205FE
+:08002F00A0D9F4DAF275A0FF7C
+:08003D007800E84400600A7934
+:030045000075A0A3
+:0600480000E4F309D8FCFE
+:08004E007800E84400600C7921
+:0B00560000900000E4F0A3D8FCD9FAF1
+:0300080075810AF5
+:0A000B00120116E5826003020003F3
+:0401160075820022CC
+:00000001FF
diff --git a/demo/keypad_display.ihx b/demo/keypad_display.ihx
new file mode 100644
index 0000000..b62bfae
--- /dev/null
+++ b/demo/keypad_display.ihx
@@ -0,0 +1,49 @@
+:03000000020008F3
+:0300610002000397
+:0500030012006480FE04
+:05006400E4F509F50AB6
+:0A006900C3E5099404E50A648094DD
+:0A0073008050EEE509241AF582E53D
+:0A007D000A3401F583E493F5908541
+:06008700900853080F630E
+:08008D00080FE50830E00575DD
+:040095000800801FC0
+:0A009900E50830E105750801801547
+:0A00A300E50830E205750802800B45
+:0800AD00E50820E30302010B4A
+:0300B500750803C8
+:0A00B800E4B50906E4B50A0280234E
+:0A00C2007401B50906E4B50A0280D6
+:0100CC002211
+:0A00CD007402B50906E4B50A0280CA
+:0100D7002107
+:0A00D8007403B50906E4B50A0280BE
+:0100E20020FD
+:0200E300802675
+:0A00E500E50890011E93F5B0801CA1
+:0A00EF00E50890012293F5B080129D
+:0A00F900E50890012693F5B0800899
+:08010300E50890012A93F5B014
+:07010B000509E4B509020536
+:010112000AE2
+:030113000200697E
+:04011A00EFDFBF7FD5
+:04011E00F9647048C8
+:0401220059524240AC
+:04012600F84050C687
+:04012A0079C049C08F
+:06003700E478FFF6D8FD9D
+:080015007900E94400601B7A48
+:05001D000090012E78A7
+:030022000075A0C6
+:0A00250000E493F2A308B8000205FE
+:08002F00A0D9F4DAF275A0FF7C
+:08003D007800E84400600A7934
+:030045000075A0A3
+:0600480000E4F309D8FCFE
+:08004E007800E84400600C7921
+:0B00560000900000E4F0A3D8FCD9FAF1
+:0300080075810AF5
+:0A000B00120116E5826003020003F3
+:0401160075820022CC
+:00000001FF
diff --git a/demo/keypad_display.lnk b/demo/keypad_display.lnk
new file mode 100644
index 0000000..9287b22
--- /dev/null
+++ b/demo/keypad_display.lnk
@@ -0,0 +1,19 @@
+-myuxi
+-Y
+-a 0x0100
+-v 0x0000
+-w 0x0800
+-z
+-b HOME = 0x0000
+-b ISEG = 0x0000
+-b BSEG = 0x0000
+-k /usr/libexec/sdcc/../share/sdcc/lib/small
+-k /usr/share/sdcc/lib/small
+-l mcs51
+-l libsdcc
+-l libint
+-l liblong
+-l libfloat
+keypad_display.rel
+
+-e
diff --git a/demo/keypad_display.lst b/demo/keypad_display.lst
new file mode 100644
index 0000000..439d5d9
--- /dev/null
+++ b/demo/keypad_display.lst
@@ -0,0 +1,624 @@
+ 1 ;--------------------------------------------------------
+ 2 ; File Created by SDCC : free open source ANSI-C Compiler
+ 3 ; Version 2.9.0 #5416 (Oct 6 2009) (UNIX)
+ 4 ; This file was generated Tue Oct 27 23:03:55 2009
+ 5 ;--------------------------------------------------------
+ 6 .module keypad_display
+ 7 .optsdcc -mmcs51 --model-small
+ 8
+ 9 ;--------------------------------------------------------
+ 10 ; Public variables in this module
+ 11 ;--------------------------------------------------------
+ 12 .globl _main
+ 13 .globl _CY
+ 14 .globl _AC
+ 15 .globl _F0
+ 16 .globl _RS1
+ 17 .globl _RS0
+ 18 .globl _OV
+ 19 .globl _F1
+ 20 .globl _P
+ 21 .globl _PS
+ 22 .globl _PT1
+ 23 .globl _PX1
+ 24 .globl _PT0
+ 25 .globl _PX0
+ 26 .globl _RD
+ 27 .globl _WR
+ 28 .globl _T1
+ 29 .globl _T0
+ 30 .globl _INT1
+ 31 .globl _INT0
+ 32 .globl _TXD
+ 33 .globl _RXD
+ 34 .globl _P3_7
+ 35 .globl _P3_6
+ 36 .globl _P3_5
+ 37 .globl _P3_4
+ 38 .globl _P3_3
+ 39 .globl _P3_2
+ 40 .globl _P3_1
+ 41 .globl _P3_0
+ 42 .globl _EA
+ 43 .globl _ES
+ 44 .globl _ET1
+ 45 .globl _EX1
+ 46 .globl _ET0
+ 47 .globl _EX0
+ 48 .globl _P2_7
+ 49 .globl _P2_6
+ 50 .globl _P2_5
+ 51 .globl _P2_4
+ 52 .globl _P2_3
+ 53 .globl _P2_2
+ 54 .globl _P2_1
+ 55 .globl _P2_0
+ 56 .globl _SM0
+ 57 .globl _SM1
+ 58 .globl _SM2
+ 59 .globl _REN
+ 60 .globl _TB8
+ 61 .globl _RB8
+ 62 .globl _TI
+ 63 .globl _RI
+ 64 .globl _P1_7
+ 65 .globl _P1_6
+ 66 .globl _P1_5
+ 67 .globl _P1_4
+ 68 .globl _P1_3
+ 69 .globl _P1_2
+ 70 .globl _P1_1
+ 71 .globl _P1_0
+ 72 .globl _TF1
+ 73 .globl _TR1
+ 74 .globl _TF0
+ 75 .globl _TR0
+ 76 .globl _IE1
+ 77 .globl _IT1
+ 78 .globl _IE0
+ 79 .globl _IT0
+ 80 .globl _P0_7
+ 81 .globl _P0_6
+ 82 .globl _P0_5
+ 83 .globl _P0_4
+ 84 .globl _P0_3
+ 85 .globl _P0_2
+ 86 .globl _P0_1
+ 87 .globl _P0_0
+ 88 .globl _B
+ 89 .globl _ACC
+ 90 .globl _PSW
+ 91 .globl _IP
+ 92 .globl _P3
+ 93 .globl _IE
+ 94 .globl _P2
+ 95 .globl _SBUF
+ 96 .globl _SCON
+ 97 .globl _P1
+ 98 .globl _TH1
+ 99 .globl _TH0
+ 100 .globl _TL1
+ 101 .globl _TL0
+ 102 .globl _TMOD
+ 103 .globl _TCON
+ 104 .globl _PCON
+ 105 .globl _DPH
+ 106 .globl _DPL
+ 107 .globl _SP
+ 108 .globl _P0
+ 109 .globl _row
+ 110 .globl _state
+ 111 ;--------------------------------------------------------
+ 112 ; special function registers
+ 113 ;--------------------------------------------------------
+ 114 .area RSEG (DATA)
+ 0080 115 G$P0$0$0 == 0x0080
+ 0080 116 _P0 = 0x0080
+ 0081 117 G$SP$0$0 == 0x0081
+ 0081 118 _SP = 0x0081
+ 0082 119 G$DPL$0$0 == 0x0082
+ 0082 120 _DPL = 0x0082
+ 0083 121 G$DPH$0$0 == 0x0083
+ 0083 122 _DPH = 0x0083
+ 0087 123 G$PCON$0$0 == 0x0087
+ 0087 124 _PCON = 0x0087
+ 0088 125 G$TCON$0$0 == 0x0088
+ 0088 126 _TCON = 0x0088
+ 0089 127 G$TMOD$0$0 == 0x0089
+ 0089 128 _TMOD = 0x0089
+ 008A 129 G$TL0$0$0 == 0x008a
+ 008A 130 _TL0 = 0x008a
+ 008B 131 G$TL1$0$0 == 0x008b
+ 008B 132 _TL1 = 0x008b
+ 008C 133 G$TH0$0$0 == 0x008c
+ 008C 134 _TH0 = 0x008c
+ 008D 135 G$TH1$0$0 == 0x008d
+ 008D 136 _TH1 = 0x008d
+ 0090 137 G$P1$0$0 == 0x0090
+ 0090 138 _P1 = 0x0090
+ 0098 139 G$SCON$0$0 == 0x0098
+ 0098 140 _SCON = 0x0098
+ 0099 141 G$SBUF$0$0 == 0x0099
+ 0099 142 _SBUF = 0x0099
+ 00A0 143 G$P2$0$0 == 0x00a0
+ 00A0 144 _P2 = 0x00a0
+ 00A8 145 G$IE$0$0 == 0x00a8
+ 00A8 146 _IE = 0x00a8
+ 00B0 147 G$P3$0$0 == 0x00b0
+ 00B0 148 _P3 = 0x00b0
+ 00B8 149 G$IP$0$0 == 0x00b8
+ 00B8 150 _IP = 0x00b8
+ 00D0 151 G$PSW$0$0 == 0x00d0
+ 00D0 152 _PSW = 0x00d0
+ 00E0 153 G$ACC$0$0 == 0x00e0
+ 00E0 154 _ACC = 0x00e0
+ 00F0 155 G$B$0$0 == 0x00f0
+ 00F0 156 _B = 0x00f0
+ 157 ;--------------------------------------------------------
+ 158 ; special function bits
+ 159 ;--------------------------------------------------------
+ 160 .area RSEG (DATA)
+ 0080 161 G$P0_0$0$0 == 0x0080
+ 0080 162 _P0_0 = 0x0080
+ 0081 163 G$P0_1$0$0 == 0x0081
+ 0081 164 _P0_1 = 0x0081
+ 0082 165 G$P0_2$0$0 == 0x0082
+ 0082 166 _P0_2 = 0x0082
+ 0083 167 G$P0_3$0$0 == 0x0083
+ 0083 168 _P0_3 = 0x0083
+ 0084 169 G$P0_4$0$0 == 0x0084
+ 0084 170 _P0_4 = 0x0084
+ 0085 171 G$P0_5$0$0 == 0x0085
+ 0085 172 _P0_5 = 0x0085
+ 0086 173 G$P0_6$0$0 == 0x0086
+ 0086 174 _P0_6 = 0x0086
+ 0087 175 G$P0_7$0$0 == 0x0087
+ 0087 176 _P0_7 = 0x0087
+ 0088 177 G$IT0$0$0 == 0x0088
+ 0088 178 _IT0 = 0x0088
+ 0089 179 G$IE0$0$0 == 0x0089
+ 0089 180 _IE0 = 0x0089
+ 008A 181 G$IT1$0$0 == 0x008a
+ 008A 182 _IT1 = 0x008a
+ 008B 183 G$IE1$0$0 == 0x008b
+ 008B 184 _IE1 = 0x008b
+ 008C 185 G$TR0$0$0 == 0x008c
+ 008C 186 _TR0 = 0x008c
+ 008D 187 G$TF0$0$0 == 0x008d
+ 008D 188 _TF0 = 0x008d
+ 008E 189 G$TR1$0$0 == 0x008e
+ 008E 190 _TR1 = 0x008e
+ 008F 191 G$TF1$0$0 == 0x008f
+ 008F 192 _TF1 = 0x008f
+ 0090 193 G$P1_0$0$0 == 0x0090
+ 0090 194 _P1_0 = 0x0090
+ 0091 195 G$P1_1$0$0 == 0x0091
+ 0091 196 _P1_1 = 0x0091
+ 0092 197 G$P1_2$0$0 == 0x0092
+ 0092 198 _P1_2 = 0x0092
+ 0093 199 G$P1_3$0$0 == 0x0093
+ 0093 200 _P1_3 = 0x0093
+ 0094 201 G$P1_4$0$0 == 0x0094
+ 0094 202 _P1_4 = 0x0094
+ 0095 203 G$P1_5$0$0 == 0x0095
+ 0095 204 _P1_5 = 0x0095
+ 0096 205 G$P1_6$0$0 == 0x0096
+ 0096 206 _P1_6 = 0x0096
+ 0097 207 G$P1_7$0$0 == 0x0097
+ 0097 208 _P1_7 = 0x0097
+ 0098 209 G$RI$0$0 == 0x0098
+ 0098 210 _RI = 0x0098
+ 0099 211 G$TI$0$0 == 0x0099
+ 0099 212 _TI = 0x0099
+ 009A 213 G$RB8$0$0 == 0x009a
+ 009A 214 _RB8 = 0x009a
+ 009B 215 G$TB8$0$0 == 0x009b
+ 009B 216 _TB8 = 0x009b
+ 009C 217 G$REN$0$0 == 0x009c
+ 009C 218 _REN = 0x009c
+ 009D 219 G$SM2$0$0 == 0x009d
+ 009D 220 _SM2 = 0x009d
+ 009E 221 G$SM1$0$0 == 0x009e
+ 009E 222 _SM1 = 0x009e
+ 009F 223 G$SM0$0$0 == 0x009f
+ 009F 224 _SM0 = 0x009f
+ 00A0 225 G$P2_0$0$0 == 0x00a0
+ 00A0 226 _P2_0 = 0x00a0
+ 00A1 227 G$P2_1$0$0 == 0x00a1
+ 00A1 228 _P2_1 = 0x00a1
+ 00A2 229 G$P2_2$0$0 == 0x00a2
+ 00A2 230 _P2_2 = 0x00a2
+ 00A3 231 G$P2_3$0$0 == 0x00a3
+ 00A3 232 _P2_3 = 0x00a3
+ 00A4 233 G$P2_4$0$0 == 0x00a4
+ 00A4 234 _P2_4 = 0x00a4
+ 00A5 235 G$P2_5$0$0 == 0x00a5
+ 00A5 236 _P2_5 = 0x00a5
+ 00A6 237 G$P2_6$0$0 == 0x00a6
+ 00A6 238 _P2_6 = 0x00a6
+ 00A7 239 G$P2_7$0$0 == 0x00a7
+ 00A7 240 _P2_7 = 0x00a7
+ 00A8 241 G$EX0$0$0 == 0x00a8
+ 00A8 242 _EX0 = 0x00a8
+ 00A9 243 G$ET0$0$0 == 0x00a9
+ 00A9 244 _ET0 = 0x00a9
+ 00AA 245 G$EX1$0$0 == 0x00aa
+ 00AA 246 _EX1 = 0x00aa
+ 00AB 247 G$ET1$0$0 == 0x00ab
+ 00AB 248 _ET1 = 0x00ab
+ 00AC 249 G$ES$0$0 == 0x00ac
+ 00AC 250 _ES = 0x00ac
+ 00AF 251 G$EA$0$0 == 0x00af
+ 00AF 252 _EA = 0x00af
+ 00B0 253 G$P3_0$0$0 == 0x00b0
+ 00B0 254 _P3_0 = 0x00b0
+ 00B1 255 G$P3_1$0$0 == 0x00b1
+ 00B1 256 _P3_1 = 0x00b1
+ 00B2 257 G$P3_2$0$0 == 0x00b2
+ 00B2 258 _P3_2 = 0x00b2
+ 00B3 259 G$P3_3$0$0 == 0x00b3
+ 00B3 260 _P3_3 = 0x00b3
+ 00B4 261 G$P3_4$0$0 == 0x00b4
+ 00B4 262 _P3_4 = 0x00b4
+ 00B5 263 G$P3_5$0$0 == 0x00b5
+ 00B5 264 _P3_5 = 0x00b5
+ 00B6 265 G$P3_6$0$0 == 0x00b6
+ 00B6 266 _P3_6 = 0x00b6
+ 00B7 267 G$P3_7$0$0 == 0x00b7
+ 00B7 268 _P3_7 = 0x00b7
+ 00B0 269 G$RXD$0$0 == 0x00b0
+ 00B0 270 _RXD = 0x00b0
+ 00B1 271 G$TXD$0$0 == 0x00b1
+ 00B1 272 _TXD = 0x00b1
+ 00B2 273 G$INT0$0$0 == 0x00b2
+ 00B2 274 _INT0 = 0x00b2
+ 00B3 275 G$INT1$0$0 == 0x00b3
+ 00B3 276 _INT1 = 0x00b3
+ 00B4 277 G$T0$0$0 == 0x00b4
+ 00B4 278 _T0 = 0x00b4
+ 00B5 279 G$T1$0$0 == 0x00b5
+ 00B5 280 _T1 = 0x00b5
+ 00B6 281 G$WR$0$0 == 0x00b6
+ 00B6 282 _WR = 0x00b6
+ 00B7 283 G$RD$0$0 == 0x00b7
+ 00B7 284 _RD = 0x00b7
+ 00B8 285 G$PX0$0$0 == 0x00b8
+ 00B8 286 _PX0 = 0x00b8
+ 00B9 287 G$PT0$0$0 == 0x00b9
+ 00B9 288 _PT0 = 0x00b9
+ 00BA 289 G$PX1$0$0 == 0x00ba
+ 00BA 290 _PX1 = 0x00ba
+ 00BB 291 G$PT1$0$0 == 0x00bb
+ 00BB 292 _PT1 = 0x00bb
+ 00BC 293 G$PS$0$0 == 0x00bc
+ 00BC 294 _PS = 0x00bc
+ 00D0 295 G$P$0$0 == 0x00d0
+ 00D0 296 _P = 0x00d0
+ 00D1 297 G$F1$0$0 == 0x00d1
+ 00D1 298 _F1 = 0x00d1
+ 00D2 299 G$OV$0$0 == 0x00d2
+ 00D2 300 _OV = 0x00d2
+ 00D3 301 G$RS0$0$0 == 0x00d3
+ 00D3 302 _RS0 = 0x00d3
+ 00D4 303 G$RS1$0$0 == 0x00d4
+ 00D4 304 _RS1 = 0x00d4
+ 00D5 305 G$F0$0$0 == 0x00d5
+ 00D5 306 _F0 = 0x00d5
+ 00D6 307 G$AC$0$0 == 0x00d6
+ 00D6 308 _AC = 0x00d6
+ 00D7 309 G$CY$0$0 == 0x00d7
+ 00D7 310 _CY = 0x00d7
+ 311 ;--------------------------------------------------------
+ 312 ; overlayable register banks
+ 313 ;--------------------------------------------------------
+ 314 .area REG_BANK_0 (REL,OVR,DATA)
+ 0000 315 .ds 8
+ 316 ;--------------------------------------------------------
+ 317 ; internal ram data
+ 318 ;--------------------------------------------------------
+ 319 .area DSEG (DATA)
+ 0000 320 G$state$0$0==.
+ 0000 321 _state::
+ 0000 322 .ds 1
+ 0001 323 G$row$0$0==.
+ 0001 324 _row::
+ 0001 325 .ds 2
+ 326 ;--------------------------------------------------------
+ 327 ; overlayable items in internal ram
+ 328 ;--------------------------------------------------------
+ 329 .area OSEG (OVR,DATA)
+ 330 ;--------------------------------------------------------
+ 331 ; Stack segment in internal ram
+ 332 ;--------------------------------------------------------
+ 333 .area SSEG (DATA)
+ 0000 334 __start__stack:
+ 0000 335 .ds 1
+ 336
+ 337 ;--------------------------------------------------------
+ 338 ; indirectly addressable internal ram data
+ 339 ;--------------------------------------------------------
+ 340 .area ISEG (DATA)
+ 341 ;--------------------------------------------------------
+ 342 ; absolute internal ram data
+ 343 ;--------------------------------------------------------
+ 344 .area IABS (ABS,DATA)
+ 345 .area IABS (ABS,DATA)
+ 346 ;--------------------------------------------------------
+ 347 ; bit data
+ 348 ;--------------------------------------------------------
+ 349 .area BSEG (BIT)
+ 350 ;--------------------------------------------------------
+ 351 ; paged external ram data
+ 352 ;--------------------------------------------------------
+ 353 .area PSEG (PAG,XDATA)
+ 354 ;--------------------------------------------------------
+ 355 ; external ram data
+ 356 ;--------------------------------------------------------
+ 357 .area XSEG (XDATA)
+ 358 ;--------------------------------------------------------
+ 359 ; absolute external ram data
+ 360 ;--------------------------------------------------------
+ 361 .area XABS (ABS,XDATA)
+ 362 ;--------------------------------------------------------
+ 363 ; external initialized ram data
+ 364 ;--------------------------------------------------------
+ 365 .area XISEG (XDATA)
+ 366 .area HOME (CODE)
+ 367 .area GSINIT0 (CODE)
+ 368 .area GSINIT1 (CODE)
+ 369 .area GSINIT2 (CODE)
+ 370 .area GSINIT3 (CODE)
+ 371 .area GSINIT4 (CODE)
+ 372 .area GSINIT5 (CODE)
+ 373 .area GSINIT (CODE)
+ 374 .area GSFINAL (CODE)
+ 375 .area CSEG (CODE)
+ 376 ;--------------------------------------------------------
+ 377 ; interrupt vector
+ 378 ;--------------------------------------------------------
+ 379 .area HOME (CODE)
+ 0000 380 __interrupt_vect:
+ 0000 02s00r00 381 ljmp __sdcc_gsinit_startup
+ 382 ;--------------------------------------------------------
+ 383 ; global & static initialisations
+ 384 ;--------------------------------------------------------
+ 385 .area HOME (CODE)
+ 386 .area GSINIT (CODE)
+ 387 .area GSFINAL (CODE)
+ 388 .area GSINIT (CODE)
+ 389 .globl __sdcc_gsinit_startup
+ 390 .globl __sdcc_program_startup
+ 391 .globl __start__stack
+ 392 .globl __mcs51_genXINIT
+ 393 .globl __mcs51_genXRAMCLEAR
+ 394 .globl __mcs51_genRAMCLEAR
+ 395 .area GSFINAL (CODE)
+ 0000 02s00r03 396 ljmp __sdcc_program_startup
+ 397 ;--------------------------------------------------------
+ 398 ; Home
+ 399 ;--------------------------------------------------------
+ 400 .area HOME (CODE)
+ 401 .area HOME (CODE)
+ 0003 402 __sdcc_program_startup:
+ 0003 12s00r00 403 lcall _main
+ 404 ; return from main will lock up
+ 0006 80 FE 405 sjmp .
+ 406 ;--------------------------------------------------------
+ 407 ; code
+ 408 ;--------------------------------------------------------
+ 409 .area CSEG (CODE)
+ 410 ;------------------------------------------------------------
+ 411 ;Allocation info for local variables in function 'main'
+ 412 ;------------------------------------------------------------
+ 413 ;------------------------------------------------------------
+ 0000 414 G$main$0$0 ==.
+ 0000 415 C$keypad_display.c$38$0$0 ==.
+ 416 ; keypad_display.c:38: int main()
+ 417 ; -----------------------------------------
+ 418 ; function main
+ 419 ; -----------------------------------------
+ 0000 420 _main:
+ 0002 421 ar2 = 0x02
+ 0003 422 ar3 = 0x03
+ 0004 423 ar4 = 0x04
+ 0005 424 ar5 = 0x05
+ 0006 425 ar6 = 0x06
+ 0007 426 ar7 = 0x07
+ 0000 427 ar0 = 0x00
+ 0001 428 ar1 = 0x01
+ 0000 429 C$keypad_display.c$40$1$1 ==.
+ 430 ; keypad_display.c:40: while(1) {
+ 0000 431 00123$:
+ 0000 432 C$keypad_display.c$41$2$2 ==.
+ 433 ; keypad_display.c:41: for(row=0; row<4; row++) {
+ 0000 E4 434 clr a
+ 0001 F5*01 435 mov _row,a
+ 0003 F5*02 436 mov (_row + 1),a
+ 0005 437 00118$:
+ 0005 C3 438 clr c
+ 0006 E5*01 439 mov a,_row
+ 0008 94 04 440 subb a,#0x04
+ 000A E5*02 441 mov a,(_row + 1)
+ 000C 64 80 442 xrl a,#0x80
+ 000E 94 80 443 subb a,#0x80
+ 0010 50 EE 444 jnc 00123$
+ 0012 445 C$keypad_display.c$42$3$3 ==.
+ 446 ; keypad_display.c:42: P1=keypad[row];
+ 0012 E5*01 447 mov a,_row
+ 0014 24r00 448 add a,#_keypad
+ 0016 F5 82 449 mov dpl,a
+ 0018 E5*02 450 mov a,(_row + 1)
+ 001A 34s00 451 addc a,#(_keypad >> 8)
+ 001C F5 83 452 mov dph,a
+ 001E E4 453 clr a
+ 001F 93 454 movc a,@a+dptr
+ 0020 F5 90 455 mov _P1,a
+ 0022 456 C$keypad_display.c$48$3$3 ==.
+ 457 ; keypad_display.c:48: _endasm;
+ 458
+ 0022 85 90*00 459 mov _state, P1
+ 460
+ 0025 461 C$keypad_display.c$53$3$3 ==.
+ 462 ; keypad_display.c:53: state&=0x0f;
+ 0025 53r00 0F 463 anl _state,#0x0F
+ 0028 464 C$keypad_display.c$54$3$3 ==.
+ 465 ; keypad_display.c:54: state^=0x0f;
+ 0028 63r00 0F 466 xrl _state,#0x0F
+ 002B 467 C$keypad_display.c$56$3$3 ==.
+ 468 ; keypad_display.c:56: if(state & 1) {
+ 002B E5*00 469 mov a,_state
+ 002D 30 E0 05 470 jnb acc.0,00111$
+ 0030 471 C$keypad_display.c$57$4$4 ==.
+ 472 ; keypad_display.c:57: state=0;
+ 0030 75*00 00 473 mov _state,#0x00
+ 0033 80 1F 474 sjmp 00112$
+ 0035 475 00111$:
+ 0035 476 C$keypad_display.c$58$3$3 ==.
+ 477 ; keypad_display.c:58: } else if(state & 2) {
+ 0035 E5*00 478 mov a,_state
+ 0037 30 E1 05 479 jnb acc.1,00108$
+ 003A 480 C$keypad_display.c$59$4$5 ==.
+ 481 ; keypad_display.c:59: state=1;
+ 003A 75*00 01 482 mov _state,#0x01
+ 003D 80 15 483 sjmp 00112$
+ 003F 484 00108$:
+ 003F 485 C$keypad_display.c$60$3$3 ==.
+ 486 ; keypad_display.c:60: } else if(state & 4) {
+ 003F E5*00 487 mov a,_state
+ 0041 30 E2 05 488 jnb acc.2,00105$
+ 0044 489 C$keypad_display.c$61$4$6 ==.
+ 490 ; keypad_display.c:61: state=2;
+ 0044 75*00 02 491 mov _state,#0x02
+ 0047 80 0B 492 sjmp 00112$
+ 0049 493 00105$:
+ 0049 494 C$keypad_display.c$62$3$3 ==.
+ 495 ; keypad_display.c:62: } else if(state & 8) {
+ 0049 E5*00 496 mov a,_state
+ 004B 20 E3 03 497 jb acc.3,00142$
+ 004E 02s00rA7 498 ljmp 00120$
+ 0051 499 00142$:
+ 0051 500 C$keypad_display.c$63$4$7 ==.
+ 501 ; keypad_display.c:63: state=3;
+ 0051 75*00 03 502 mov _state,#0x03
+ 0054 503 C$keypad_display.c$65$3$3 ==.
+ 504 ; keypad_display.c:65: continue;
+ 0054 505 00112$:
+ 0054 506 C$keypad_display.c$68$3$3 ==.
+ 507 ; keypad_display.c:68: switch(row) {
+ 0054 E4 508 clr a
+ 0055 B5*01 06 509 cjne a,_row,00143$
+ 0058 E4 510 clr a
+ 0059 B5*02 02 511 cjne a,(_row + 1),00143$
+ 005C 80 23 512 sjmp 00113$
+ 005E 513 00143$:
+ 005E 74 01 514 mov a,#0x01
+ 0060 B5*01 06 515 cjne a,_row,00144$
+ 0063 E4 516 clr a
+ 0064 B5*02 02 517 cjne a,(_row + 1),00144$
+ 0067 80 22 518 sjmp 00114$
+ 0069 519 00144$:
+ 0069 74 02 520 mov a,#0x02
+ 006B B5*01 06 521 cjne a,_row,00145$
+ 006E E4 522 clr a
+ 006F B5*02 02 523 cjne a,(_row + 1),00145$
+ 0072 80 21 524 sjmp 00115$
+ 0074 525 00145$:
+ 0074 74 03 526 mov a,#0x03
+ 0076 B5*01 06 527 cjne a,_row,00146$
+ 0079 E4 528 clr a
+ 007A B5*02 02 529 cjne a,(_row + 1),00146$
+ 007D 80 20 530 sjmp 00116$
+ 007F 531 00146$:
+ 007F 532 C$keypad_display.c$69$4$9 ==.
+ 533 ; keypad_display.c:69: case 0:
+ 007F 80 26 534 sjmp 00120$
+ 0081 535 00113$:
+ 0081 536 C$keypad_display.c$70$4$9 ==.
+ 537 ; keypad_display.c:70: P3=display_0[state];
+ 0081 E5*00 538 mov a,_state
+ 0083 90s00r04 539 mov dptr,#_display_0
+ 0086 93 540 movc a,@a+dptr
+ 0087 F5 B0 541 mov _P3,a
+ 0089 542 C$keypad_display.c$71$4$9 ==.
+ 543 ; keypad_display.c:71: break;
+ 0089 544 C$keypad_display.c$72$4$9 ==.
+ 545 ; keypad_display.c:72: case 1:
+ 0089 80 1C 546 sjmp 00120$
+ 008B 547 00114$:
+ 008B 548 C$keypad_display.c$73$4$9 ==.
+ 549 ; keypad_display.c:73: P3=display_1[state];
+ 008B E5*00 550 mov a,_state
+ 008D 90s00r08 551 mov dptr,#_display_1
+ 0090 93 552 movc a,@a+dptr
+ 0091 F5 B0 553 mov _P3,a
+ 0093 554 C$keypad_display.c$74$4$9 ==.
+ 555 ; keypad_display.c:74: break;
+ 0093 556 C$keypad_display.c$75$4$9 ==.
+ 557 ; keypad_display.c:75: case 2:
+ 0093 80 12 558 sjmp 00120$
+ 0095 559 00115$:
+ 0095 560 C$keypad_display.c$76$4$9 ==.
+ 561 ; keypad_display.c:76: P3=display_2[state];
+ 0095 E5*00 562 mov a,_state
+ 0097 90s00r0C 563 mov dptr,#_display_2
+ 009A 93 564 movc a,@a+dptr
+ 009B F5 B0 565 mov _P3,a
+ 009D 566 C$keypad_display.c$77$4$9 ==.
+ 567 ; keypad_display.c:77: break;
+ 009D 568 C$keypad_display.c$78$4$9 ==.
+ 569 ; keypad_display.c:78: case 3:
+ 009D 80 08 570 sjmp 00120$
+ 009F 571 00116$:
+ 009F 572 C$keypad_display.c$79$4$9 ==.
+ 573 ; keypad_display.c:79: P3=display_3[state];
+ 009F E5*00 574 mov a,_state
+ 00A1 90s00r10 575 mov dptr,#_display_3
+ 00A4 93 576 movc a,@a+dptr
+ 00A5 F5 B0 577 mov _P3,a
+ 00A7 578 C$keypad_display.c$81$2$2 ==.
+ 579 ; keypad_display.c:81: }
+ 00A7 580 00120$:
+ 00A7 581 C$keypad_display.c$41$2$2 ==.
+ 582 ; keypad_display.c:41: for(row=0; row<4; row++) {
+ 00A7 05*01 583 inc _row
+ 00A9 E4 584 clr a
+ 00AA B5*01 02 585 cjne a,_row,00147$
+ 00AD 05*02 586 inc (_row + 1)
+ 00AF 587 00147$:
+ 00AF 588 C$keypad_display.c$84$1$1 ==.
+ 00AF 589 XG$main$0$0 ==.
+ 00AF 02s00r05 590 ljmp 00118$
+ 591 .area CSEG (CODE)
+ 592 .area CONST (CODE)
+ 0000 593 Fkeypad_display$keypad$0$0 == .
+ 0000 594 _keypad:
+ 0000 EF 595 .db #0xEF
+ 0001 DF 596 .db #0xDF
+ 0002 BF 597 .db #0xBF
+ 0003 7F 598 .db #0x7F
+ 0004 599 Fkeypad_display$display_0$0$0 == .
+ 0004 600 _display_0:
+ 0004 F9 601 .db #0xF9
+ 0005 64 602 .db #0x64
+ 0006 70 603 .db #0x70
+ 0007 48 604 .db #0x48
+ 0008 605 Fkeypad_display$display_1$0$0 == .
+ 0008 606 _display_1:
+ 0008 59 607 .db #0x59
+ 0009 52 608 .db #0x52
+ 000A 42 609 .db #0x42
+ 000B 40 610 .db #0x40
+ 000C 611 Fkeypad_display$display_2$0$0 == .
+ 000C 612 _display_2:
+ 000C F8 613 .db #0xF8
+ 000D 40 614 .db #0x40
+ 000E 50 615 .db #0x50
+ 000F C6 616 .db #0xC6
+ 0010 617 Fkeypad_display$display_3$0$0 == .
+ 0010 618 _display_3:
+ 0010 79 619 .db #0x79
+ 0011 C0 620 .db #0xC0
+ 0012 49 621 .db #0x49
+ 0013 C0 622 .db #0xC0
+ 623 .area XINIT (CODE)
+ 624 .area CABS (ABS,CODE)
diff --git a/demo/keypad_display.map b/demo/keypad_display.map
new file mode 100644
index 0000000..276738d
--- /dev/null
+++ b/demo/keypad_display.map
@@ -0,0 +1,536 @@
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+CABS 0000 0000 = 0. bytes (ABS,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:FFFFFF00 s_BSEG
+ 0C:0000 l_BIT_BANK
+ 0C:0000 l_BSEG
+ 0C:0000 l_BSEG_BYTES
+ 0C:0000 l_CABS
+ 0C:0000 l_GSINIT
+ 0C:0000 l_GSINIT1
+ 0C:0000 l_GSINIT5
+ 0C:0000 l_IABS
+ 0C:0000 l_ISEG
+ 0C:0000 l_OSEG
+ 0C:0000 l_PSEG
+ 0C:0000 l_REG_BANK_1
+ 0C:0000 l_REG_BANK_2
+ 0C:0000 l_REG_BANK_3
+ 0C:0000 l_RSEG
+ 0C:0000 l_XABS
+ 0C:0000 l_XINIT
+ 0C:0000 l_XISEG
+ 0C:0000 l_XSEG
+ 0C:0000 l__CODE
+ 0C:0000 s_BSEG_BYTES
+ 0C:0000 s_CABS
+ 0C:0000 s_DSEG
+ 0C:0000 s_HOME
+ 0C:0000 s_IABS
+ 0C:0000 s_ISEG
+ 0C:0000 s_PSEG
+ 0C:0000 s_REG_BANK_0
+ 0C:0000 s_XABS
+ 0C:0000 s_XISEG
+ 0C:0000 s_XSEG
+ 0C:0003 l_GSFINAL
+ 0C:0003 l_GSINIT0
+ 0C:0008 l_HOME
+ 0C:0008 l_REG_BANK_0
+ 0C:0008 s_GSINIT0
+ 0C:0008 s_REG_BANK_1
+ 0C:000A l_GSINIT2
+ 0C:000B s_GSINIT1
+ 0C:000B s_GSINIT2
+ 0C:000B s_RSEG
+ 0C:000B s_SSEG
+ 0C:0010 s_REG_BANK_2
+ 0C:0014 l_CONST
+ 0C:0015 s_GSINIT3
+ 0C:0018 s_BIT_BANK
+ 0C:0018 s_OSEG
+ 0C:0018 s_REG_BANK_3
+ 0C:0020 s__CODE
+ 0C:0022 l_GSINIT3
+ 0C:002A l_GSINIT4
+ 0C:0037 s_GSINIT4
+ 0C:0061 s_GSFINAL
+ 0C:0061 s_GSINIT
+ 0C:0061 s_GSINIT5
+ 0C:0064 s_CSEG
+ 0C:0080 l_DSEG
+ 0C:00B6 l_CSEG
+ 0C:00F5 l_SSEG
+ 0C:0100 l_IRAM
+ 0C:011A s_CONST
+ 0C:012E s_XINIT
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+. .ABS. 0000 0000 = 0. bytes (ABS,CON)
+
+ Value Global
+ -------- --------------------------------
+ 0080 G$P0$0$0
+ 0080 G$P0_0$0$0
+ 0080 _P0
+ 0080 _P0_0
+ 0081 G$P0_1$0$0
+ 0081 G$SP$0$0
+ 0081 _P0_1
+ 0081 _SP
+ 0082 G$DPL$0$0
+ 0082 G$P0_2$0$0
+ 0082 _DPL
+ 0082 _P0_2
+ 0083 G$DPH$0$0
+ 0083 G$P0_3$0$0
+ 0083 _DPH
+ 0083 _P0_3
+ 0084 G$P0_4$0$0
+ 0084 _P0_4
+ 0085 G$P0_5$0$0
+ 0085 _P0_5
+ 0086 G$P0_6$0$0
+ 0086 _P0_6
+ 0087 G$P0_7$0$0
+ 0087 G$PCON$0$0
+ 0087 _P0_7
+ 0087 _PCON
+ 0088 G$IT0$0$0
+ 0088 G$TCON$0$0
+ 0088 _IT0
+ 0088 _TCON
+ 0089 G$IE0$0$0
+ 0089 G$TMOD$0$0
+ 0089 _IE0
+ 0089 _TMOD
+ 008A G$IT1$0$0
+ 008A G$TL0$0$0
+ 008A _IT1
+ 008A _TL0
+ 008B G$IE1$0$0
+ 008B G$TL1$0$0
+ 008B _IE1
+ 008B _TL1
+ 008C G$TH0$0$0
+ 008C G$TR0$0$0
+ 008C _TH0
+ 008C _TR0
+ 008D G$TF0$0$0
+ 008D G$TH1$0$0
+ 008D _TF0
+ 008D _TH1
+ 008E G$TR1$0$0
+ 008E _TR1
+ 008F G$TF1$0$0
+ 008F _TF1
+ 0090 G$P1$0$0
+ 0090 G$P1_0$0$0
+ 0090 _P1
+ 0090 _P1_0
+ 0091 G$P1_1$0$0
+ 0091 _P1_1
+ 0092 G$P1_2$0$0
+ 0092 _P1_2
+ 0093 G$P1_3$0$0
+ 0093 _P1_3
+ 0094 G$P1_4$0$0
+ 0094 _P1_4
+ 0095 G$P1_5$0$0
+ 0095 _P1_5
+ 0096 G$P1_6$0$0
+ 0096 _P1_6
+ 0097 G$P1_7$0$0
+ 0097 _P1_7
+ 0098 G$RI$0$0
+ 0098 G$SCON$0$0
+ 0098 _RI
+ 0098 _SCON
+ 0099 G$SBUF$0$0
+ 0099 G$TI$0$0
+ 0099 _SBUF
+ 0099 _TI
+ 009A G$RB8$0$0
+ 009A _RB8
+ 009B G$TB8$0$0
+ 009B _TB8
+ 009C G$REN$0$0
+ 009C _REN
+ 009D G$SM2$0$0
+ 009D _SM2
+ 009E G$SM1$0$0
+ 009E _SM1
+ 009F G$SM0$0$0
+ 009F _SM0
+ 00A0 G$P2$0$0
+ 00A0 G$P2_0$0$0
+ 00A0 _P2
+ 00A0 _P2_0
+ 00A0 __XPAGE
+ 00A1 G$P2_1$0$0
+ 00A1 _P2_1
+ 00A2 G$P2_2$0$0
+ 00A2 _P2_2
+ 00A3 G$P2_3$0$0
+ 00A3 _P2_3
+ 00A4 G$P2_4$0$0
+ 00A4 _P2_4
+ 00A5 G$P2_5$0$0
+ 00A5 _P2_5
+ 00A6 G$P2_6$0$0
+ 00A6 _P2_6
+ 00A7 G$P2_7$0$0
+ 00A7 _P2_7
+ 00A8 G$EX0$0$0
+ 00A8 G$IE$0$0
+ 00A8 _EX0
+ 00A8 _IE
+ 00A9 G$ET0$0$0
+ 00A9 _ET0
+ 00AA G$EX1$0$0
+ 00AA _EX1
+ 00AB G$ET1$0$0
+ 00AB _ET1
+ 00AC G$ES$0$0
+ 00AC _ES
+ 00AF G$EA$0$0
+ 00AF _EA
+ 00B0 G$P3$0$0
+ 00B0 G$P3_0$0$0
+ 00B0 G$RXD$0$0
+ 00B0 _P3
+ 00B0 _P3_0
+ 00B0 _RXD
+ 00B1 G$P3_1$0$0
+ 00B1 G$TXD$0$0
+ 00B1 _P3_1
+ 00B1 _TXD
+ 00B2 G$INT0$0$0
+ 00B2 G$P3_2$0$0
+ 00B2 _INT0
+ 00B2 _P3_2
+ 00B3 G$INT1$0$0
+ 00B3 G$P3_3$0$0
+ 00B3 _INT1
+ 00B3 _P3_3
+ 00B4 G$P3_4$0$0
+ 00B4 G$T0$0$0
+ 00B4 _P3_4
+ 00B4 _T0
+ 00B5 G$P3_5$0$0
+ 00B5 G$T1$0$0
+ 00B5 _P3_5
+ 00B5 _T1
+ 00B6 G$P3_6$0$0
+ 00B6 G$WR$0$0
+ 00B6 _P3_6
+ 00B6 _WR
+ 00B7 G$P3_7$0$0
+ 00B7 G$RD$0$0
+ 00B7 _P3_7
+ 00B7 _RD
+ 00B8 G$IP$0$0
+ 00B8 G$PX0$0$0
+ 00B8 _IP
+ 00B8 _PX0
+ 00B9 G$PT0$0$0
+ 00B9 _PT0
+ 00BA G$PX1$0$0
+ 00BA _PX1
+ 00BB G$PT1$0$0
+ 00BB _PT1
+ 00BC G$PS$0$0
+ 00BC _PS
+ 00D0 G$P$0$0
+ 00D0 G$PSW$0$0
+ 00D0 _P
+ 00D0 _PSW
+ 00D1 G$F1$0$0
+ 00D1 _F1
+ 00D2 G$OV$0$0
+ 00D2 _OV
+ 00D3 G$RS0$0$0
+ 00D3 _RS0
+ 00D4 G$RS1$0$0
+ 00D4 _RS1
+ 00D5 G$F0$0$0
+ 00D5 _F0
+ 00D6 G$AC$0$0
+ 00D6 _AC
+ 00D7 G$CY$0$0
+ 00D7 _CY
+ 00E0 G$ACC$0$0
+ 00E0 _ACC
+ 00F0 G$B$0$0
+ 00F0 _B
+
+
+
+
+
+
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+DSEG 0000 0080 = 128. bytes (REL,CON)
+
+ Value Global
+ -------- --------------------------------
+ 0008 G$state$0$0
+ 0008 _state
+ 0009 G$row$0$0
+ 0009 _row
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+SSEG 000B 00F5 = 245. bytes (REL,OVR)
+
+ Value Global
+ -------- --------------------------------
+ 000B __start__stack
+
+
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+HOME 0000 0008 = 8. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0000 A$keypad_display$381
+ 0C:0003 A$keypad_display$403
+ 0C:0003 __sdcc_program_startup
+ 0C:0006 A$keypad_display$405
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT0 0008 0003 = 3. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0008 __sdcc_gsinit_startup
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT3 0015 0022 = 34. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0015 __mcs51_genXINIT
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT4 0037 002A = 42. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0037 __mcs51_genRAMCLEAR
+ 0C:003D __mcs51_genXRAMCLEAR
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSFINAL 0061 0003 = 3. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0061 A$keypad_display$396
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+CSEG 0064 00B6 = 182. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0064 A$keypad_display$434
+ 0C:0064 C$keypad_display.c$38$0$0
+ 0C:0064 C$keypad_display.c$40$1$1
+ 0C:0064 G$main$0$0
+ 0C:0064 _main
+ 0C:0065 A$keypad_display$435
+ 0C:0067 A$keypad_display$436
+ 0C:0069 A$keypad_display$438
+ 0C:006A A$keypad_display$439
+ 0C:006C A$keypad_display$440
+ 0C:006E A$keypad_display$441
+ 0C:0070 A$keypad_display$442
+ 0C:0072 A$keypad_display$443
+ 0C:0074 A$keypad_display$444
+ 0C:0076 A$keypad_display$447
+ 0C:0076 C$keypad_display.c$42$3$3
+ 0C:0078 A$keypad_display$448
+ 0C:007A A$keypad_display$449
+ 0C:007C A$keypad_display$450
+ 0C:007E A$keypad_display$451
+ 0C:0080 A$keypad_display$452
+ 0C:0082 A$keypad_display$453
+ 0C:0083 A$keypad_display$454
+ 0C:0084 A$keypad_display$455
+ 0C:0086 A$keypad_display$459
+ 0C:0086 C$keypad_display.c$48$3$3
+ 0C:0089 A$keypad_display$463
+ 0C:0089 C$keypad_display.c$53$3$3
+ 0C:008C A$keypad_display$466
+ 0C:008C C$keypad_display.c$54$3$3
+ 0C:008F A$keypad_display$469
+ 0C:008F C$keypad_display.c$56$3$3
+ 0C:0091 A$keypad_display$470
+ 0C:0094 A$keypad_display$473
+ 0C:0094 C$keypad_display.c$57$4$4
+ 0C:0097 A$keypad_display$474
+ 0C:0099 A$keypad_display$478
+ 0C:0099 C$keypad_display.c$58$3$3
+ 0C:009B A$keypad_display$479
+ 0C:009E A$keypad_display$482
+ 0C:009E C$keypad_display.c$59$4$5
+ 0C:00A1 A$keypad_display$483
+ 0C:00A3 A$keypad_display$487
+ 0C:00A3 C$keypad_display.c$60$3$3
+ 0C:00A5 A$keypad_display$488
+ 0C:00A8 A$keypad_display$491
+ 0C:00A8 C$keypad_display.c$61$4$6
+ 0C:00AB A$keypad_display$492
+ 0C:00AD A$keypad_display$496
+ 0C:00AD C$keypad_display.c$62$3$3
+ 0C:00AF A$keypad_display$497
+ 0C:00B2 A$keypad_display$498
+ 0C:00B5 A$keypad_display$502
+ 0C:00B5 C$keypad_display.c$63$4$7
+ 0C:00B8 A$keypad_display$508
+ 0C:00B8 C$keypad_display.c$65$3$3
+ 0C:00B8 C$keypad_display.c$68$3$3
+ 0C:00B9 A$keypad_display$509
+ 0C:00BC A$keypad_display$510
+ 0C:00BD A$keypad_display$511
+ 0C:00C0 A$keypad_display$512
+ 0C:00C2 A$keypad_display$514
+ 0C:00C4 A$keypad_display$515
+ 0C:00C7 A$keypad_display$516
+ 0C:00C8 A$keypad_display$517
+ 0C:00CB A$keypad_display$518
+ 0C:00CD A$keypad_display$520
+ 0C:00CF A$keypad_display$521
+ 0C:00D2 A$keypad_display$522
+ 0C:00D3 A$keypad_display$523
+ 0C:00D6 A$keypad_display$524
+ 0C:00D8 A$keypad_display$526
+ 0C:00DA A$keypad_display$527
+ 0C:00DD A$keypad_display$528
+ 0C:00DE A$keypad_display$529
+ 0C:00E1 A$keypad_display$530
+ 0C:00E3 A$keypad_display$534
+ 0C:00E3 C$keypad_display.c$69$4$9
+ 0C:00E5 A$keypad_display$538
+ 0C:00E5 C$keypad_display.c$70$4$9
+ 0C:00E7 A$keypad_display$539
+ 0C:00EA A$keypad_display$540
+ 0C:00EB A$keypad_display$541
+ 0C:00ED A$keypad_display$546
+ 0C:00ED C$keypad_display.c$71$4$9
+ 0C:00ED C$keypad_display.c$72$4$9
+ 0C:00EF A$keypad_display$550
+ 0C:00EF C$keypad_display.c$73$4$9
+ 0C:00F1 A$keypad_display$551
+ 0C:00F4 A$keypad_display$552
+ 0C:00F5 A$keypad_display$553
+ 0C:00F7 A$keypad_display$558
+ 0C:00F7 C$keypad_display.c$74$4$9
+ 0C:00F7 C$keypad_display.c$75$4$9
+ 0C:00F9 A$keypad_display$562
+ 0C:00F9 C$keypad_display.c$76$4$9
+ 0C:00FB A$keypad_display$563
+ 0C:00FE A$keypad_display$564
+ 0C:00FF A$keypad_display$565
+ 0C:0101 A$keypad_display$570
+ 0C:0101 C$keypad_display.c$77$4$9
+ 0C:0101 C$keypad_display.c$78$4$9
+ 0C:0103 A$keypad_display$574
+ 0C:0103 C$keypad_display.c$79$4$9
+ 0C:0105 A$keypad_display$575
+ 0C:0108 A$keypad_display$576
+ 0C:0109 A$keypad_display$577
+ 0C:010B A$keypad_display$583
+ 0C:010B C$keypad_display.c$41$2$2
+ 0C:010B C$keypad_display.c$81$2$2
+ 0C:010D A$keypad_display$584
+ 0C:010E A$keypad_display$585
+ 0C:0111 A$keypad_display$586
+ 0C:0113 A$keypad_display$590
+ 0C:0113 C$keypad_display.c$84$1$1
+ 0C:0113 XG$main$0$0
+ 0C:0116 __sdcc_external_startup
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+CONST 011A 0014 = 20. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:011A Fkeypad_display$keypad$0$0
+ 0C:011E Fkeypad_display$display_0$0$0
+ 0C:0122 Fkeypad_display$display_1$0$0
+ 0C:0126 Fkeypad_display$display_2$0$0
+ 0C:012A Fkeypad_display$display_3$0$0
+
+ ASxxxx Linker V01.75 + NoICE + SDCC Feb 1999, page 1.
+
+Files Linked [ module(s) ]
+
+keypad_display.rel
+
+Libraries Linked [ object file ]
+
+/usr/share/sdcc/lib/small/mcs51.lib [ crtclear.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtxinit.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtxclear.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtpagesfr.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtstart.rel ]
+/usr/share/sdcc/lib/small/libsdcc.lib [ _startup.rel ]
+
+ ASxxxx Linker V01.75 + NoICE + SDCC Feb 1999, page 2.
+
+User Base Address Definitions
+
+HOME = 0x0000
+ISEG = 0x0000
+BSEG = 0x0000
+
+ \ No newline at end of file
diff --git a/demo/keypad_display.mem b/demo/keypad_display.mem
new file mode 100644
index 0000000..a205eff
--- /dev/null
+++ b/demo/keypad_display.mem
@@ -0,0 +1,28 @@
+Internal RAM layout:
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+0x00:|0|0|0|0|0|0|0|0|a|a|a|S|S|S|S|S|
+0x10:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x20:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x30:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x40:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x50:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x60:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x70:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x80:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x90:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xa0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xb0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xc0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xd0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xe0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xf0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute
+
+Stack starts at: 0x0b (sp set to 0x0a) with 245 bytes available.
+
+Other memory:
+ Name Start End Size Max
+ ---------------- -------- -------- -------- --------
+ PAGED EXT. RAM 0 0
+ EXTERNAL RAM 0 0
+ ROM/EPROM/FLASH 0x0000 0x012d 302 2048
diff --git a/demo/keypad_display.rel b/demo/keypad_display.rel
new file mode 100644
index 0000000..c4d3129
--- /dev/null
+++ b/demo/keypad_display.rel
@@ -0,0 +1,490 @@
+;!FILE keypad_display.asm
+XH
+H 1A areas 147 global symbols
+M keypad_display
+O -mmcs51 --model-small
+S G$EX0$0$0 Def00A8
+S G$IT0$0$0 Def0088
+S G$TH1$0$0 Def008D
+S _P1 Def0090
+S G$RXD$0$0 Def00B0
+S G$EX1$0$0 Def00AA
+S G$TB8$0$0 Def009B
+S G$IT1$0$0 Def008A
+S G$IE$0$0 Def00A8
+S _P2 Def00A0
+S _B Def00F0
+S _SP Def0081
+S _P3 Def00B0
+S _PS Def00BC
+S G$TXD$0$0 Def00B1
+S G$SM0$0$0 Def009F
+S G$TL0$0$0 Def008A
+S _T0 Def00B4
+S G$SM1$0$0 Def009E
+S G$TL1$0$0 Def008B
+S _T1 Def00B5
+S _OV Def00D2
+S G$SM2$0$0 Def009D
+S _ACC Def00E0
+S __mcs51_genRAMCLEAR Ref0000
+S G$PT0$0$0 Def00B9
+S G$RS0$0$0 Def00D3
+S G$PT1$0$0 Def00BB
+S _WR Def00B6
+S G$F0$0$0 Def00D5
+S G$RS1$0$0 Def00D4
+S G$RD$0$0 Def00B7
+S G$TR0$0$0 Def008C
+S G$F1$0$0 Def00D1
+S G$TR1$0$0 Def008E
+S G$PX0$0$0 Def00B8
+S G$ES$0$0 Def00AC
+S G$PX1$0$0 Def00BA
+S G$IP$0$0 Def00B8
+S G$PSW$0$0 Def00D0
+S G$RI$0$0 Def0098
+S _P0_0 Def0080
+S G$CY$0$0 Def00D7
+S _PCON Def0087
+S _SBUF Def0099
+S _P0_1 Def0081
+S _P1_0 Def0090
+S _P Def00D0
+S G$TI$0$0 Def0099
+S _P0_2 Def0082
+S _P1_1 Def0091
+S _P2_0 Def00A0
+S _P0_3 Def0083
+S _P1_2 Def0092
+S _P2_1 Def00A1
+S _P3_0 Def00B0
+S _SCON Def0098
+S _P0_4 Def0084
+S _P1_3 Def0093
+S _P2_2 Def00A2
+S _P3_1 Def00B1
+S G$P0$0$0 Def0080
+S _TCON Def0088
+S _TMOD Def0089
+S _P0_5 Def0085
+S _P1_4 Def0094
+S _P2_3 Def00A3
+S _P3_2 Def00B2
+S G$P1$0$0 Def0090
+S _P0_6 Def0086
+S _P1_5 Def0095
+S _P2_4 Def00A4
+S _P3_3 Def00B3
+S G$B$0$0 Def00F0
+S G$P2$0$0 Def00A0
+S _P0_7 Def0087
+S _P1_6 Def0096
+S _P2_5 Def00A5
+S _P3_4 Def00B4
+S G$PS$0$0 Def00BC
+S G$P3$0$0 Def00B0
+S G$SP$0$0 Def0081
+S _P1_7 Def0097
+S _P2_6 Def00A6
+S _P3_5 Def00B5
+S G$T0$0$0 Def00B4
+S _P2_7 Def00A7
+S _P3_6 Def00B6
+S G$OV$0$0 Def00D2
+S G$T1$0$0 Def00B5
+S _P3_7 Def00B7
+S G$ACC$0$0 Def00E0
+S _INT0 Def00B2
+S _DPH Def0083
+S _INT1 Def00B3
+S G$WR$0$0 Def00B6
+S _IE0 Def0089
+S _IE1 Def008B
+S _DPL Def0082
+S G$P0_0$0$0 Def0080
+S G$P$0$0 Def00D0
+S G$P1_0$0$0 Def0090
+S G$P0_1$0$0 Def0081
+S G$SBUF$0$0 Def0099
+S G$PCON$0$0 Def0087
+S _AC Def00D6
+S G$P2_0$0$0 Def00A0
+S G$P1_1$0$0 Def0091
+S G$P0_2$0$0 Def0082
+S _REN Def009C
+S G$P3_0$0$0 Def00B0
+S G$P2_1$0$0 Def00A1
+S G$P1_2$0$0 Def0092
+S G$P0_3$0$0 Def0083
+S _EA Def00AF
+S G$P3_1$0$0 Def00B1
+S G$P2_2$0$0 Def00A2
+S G$P1_3$0$0 Def0093
+S G$P0_4$0$0 Def0084
+S G$SCON$0$0 Def0098
+S G$P3_2$0$0 Def00B2
+S G$P2_3$0$0 Def00A3
+S G$P1_4$0$0 Def0094
+S G$P0_5$0$0 Def0085
+S G$TMOD$0$0 Def0089
+S G$TCON$0$0 Def0088
+S G$P3_3$0$0 Def00B3
+S G$P2_4$0$0 Def00A4
+S G$P1_5$0$0 Def0095
+S G$P0_6$0$0 Def0086
+S _ET0 Def00A9
+S G$P3_4$0$0 Def00B4
+S G$P2_5$0$0 Def00A5
+S G$P1_6$0$0 Def0096
+S G$P0_7$0$0 Def0087
+S _TF0 Def008D
+S _ET1 Def00AB
+S G$P3_5$0$0 Def00B5
+S G$P2_6$0$0 Def00A6
+S G$P1_7$0$0 Def0097
+S _TF1 Def008F
+S G$P3_6$0$0 Def00B6
+S G$P2_7$0$0 Def00A7
+S _TH0 Def008C
+S _RB8 Def009A
+S __mcs51_genXINIT Ref0000
+S G$P3_7$0$0 Def00B7
+S _TH1 Def008D
+S _IT0 Def0088
+S _EX0 Def00A8
+S _IE Def00A8
+S _IT1 Def008A
+S _TB8 Def009B
+S _EX1 Def00AA
+S _RXD Def00B0
+S G$INT0$0$0 Def00B2
+S G$INT1$0$0 Def00B3
+S G$DPH$0$0 Def0083
+S _TL0 Def008A
+S _SM0 Def009F
+S _TXD Def00B1
+S _TL1 Def008B
+S _SM1 Def009E
+S G$IE0$0$0 Def0089
+S _SM2 Def009D
+S G$IE1$0$0 Def008B
+S G$DPL$0$0 Def0082
+S _PT0 Def00B9
+S _PT1 Def00BB
+S _RS0 Def00D3
+S _TR0 Def008C
+S _RD Def00B7
+S _RS1 Def00D4
+S _F0 Def00D5
+S _TR1 Def008E
+S _F1 Def00D1
+S G$AC$0$0 Def00D6
+S _ES Def00AC
+S _PX0 Def00B8
+S G$REN$0$0 Def009C
+S _IP Def00B8
+S _PX1 Def00BA
+S G$EA$0$0 Def00AF
+S _PSW Def00D0
+S __sdcc_gsinit_startup Ref0000
+S _RI Def0098
+S _CY Def00D7
+S G$ET0$0$0 Def00A9
+S _TI Def0099
+S G$ET1$0$0 Def00AB
+S G$TF0$0$0 Def008D
+S G$TF1$0$0 Def008F
+S __mcs51_genXRAMCLEAR Ref0000
+S G$RB8$0$0 Def009A
+S G$TH0$0$0 Def008C
+S _P0 Def0080
+A _CODE size 0 flags 0 addr 0
+A RSEG size 0 flags 0 addr 0
+A REG_BANK_0 size 8 flags 4 addr 0
+A DSEG size 3 flags 0 addr 0
+S _state Def0000
+S G$row$0$0 Def0001
+S G$state$0$0 Def0000
+S _row Def0001
+A OSEG size 0 flags 4 addr 0
+A SSEG size 1 flags 0 addr 0
+S __start__stack Def0000
+A ISEG size 0 flags 0 addr 0
+A IABS size 0 flags 8 addr 0
+A BSEG size 0 flags 80 addr 0
+A PSEG size 0 flags 50 addr 0
+A XSEG size 0 flags 40 addr 0
+A XABS size 0 flags 48 addr 0
+A XISEG size 0 flags 40 addr 0
+A HOME size 8 flags 20 addr 0
+S A$keypad_display$403 Def0003
+S A$keypad_display$405 Def0006
+S A$keypad_display$381 Def0000
+S __sdcc_program_startup Def0003
+A GSINIT0 size 0 flags 20 addr 0
+A GSINIT1 size 0 flags 20 addr 0
+A GSINIT2 size 0 flags 20 addr 0
+A GSINIT3 size 0 flags 20 addr 0
+A GSINIT4 size 0 flags 20 addr 0
+A GSINIT5 size 0 flags 20 addr 0
+A GSINIT size 0 flags 20 addr 0
+A GSFINAL size 3 flags 20 addr 0
+S A$keypad_display$396 Def0000
+A CSEG size B2 flags 20 addr 0
+S _main Def0000
+S XG$main$0$0 Def00AF
+S A$keypad_display$510 Def0058
+S A$keypad_display$520 Def0069
+S A$keypad_display$511 Def0059
+S A$keypad_display$502 Def0051
+S A$keypad_display$530 Def007D
+S A$keypad_display$521 Def006B
+S A$keypad_display$512 Def005C
+S A$keypad_display$440 Def0008
+S A$keypad_display$540 Def0086
+S A$keypad_display$522 Def006E
+S A$keypad_display$450 Def0018
+S A$keypad_display$441 Def000A
+S A$keypad_display$550 Def008B
+S A$keypad_display$541 Def0087
+S A$keypad_display$523 Def006F
+S A$keypad_display$514 Def005E
+S A$keypad_display$451 Def001A
+S A$keypad_display$442 Def000C
+S A$keypad_display$551 Def008D
+S A$keypad_display$524 Def0072
+S A$keypad_display$515 Def0060
+S A$keypad_display$470 Def002D
+S A$keypad_display$452 Def001C
+S A$keypad_display$443 Def000E
+S A$keypad_display$434 Def0000
+S A$keypad_display$570 Def009D
+S A$keypad_display$552 Def0090
+S A$keypad_display$534 Def007F
+S A$keypad_display$516 Def0063
+S A$keypad_display$453 Def001E
+S A$keypad_display$444 Def0010
+S A$keypad_display$435 Def0001
+S G$main$0$0 Def0000
+S A$keypad_display$562 Def0095
+S A$keypad_display$553 Def0091
+S A$keypad_display$526 Def0074
+S A$keypad_display$517 Def0064
+S A$keypad_display$508 Def0054
+S A$keypad_display$463 Def0025
+S A$keypad_display$454 Def001F
+S A$keypad_display$436 Def0003
+S A$keypad_display$590 Def00AF
+S A$keypad_display$563 Def0097
+S A$keypad_display$527 Def0076
+S A$keypad_display$518 Def0067
+S A$keypad_display$509 Def0055
+S A$keypad_display$491 Def0044
+S A$keypad_display$482 Def003A
+S A$keypad_display$473 Def0030
+S A$keypad_display$455 Def0020
+S A$keypad_display$564 Def009A
+S A$keypad_display$546 Def0089
+S A$keypad_display$528 Def0079
+S A$keypad_display$492 Def0047
+S A$keypad_display$483 Def003D
+S A$keypad_display$474 Def0033
+S A$keypad_display$447 Def0012
+S A$keypad_display$438 Def0005
+S A$keypad_display$583 Def00A7
+S A$keypad_display$574 Def009F
+S A$keypad_display$565 Def009B
+S A$keypad_display$538 Def0081
+S A$keypad_display$529 Def007A
+S A$keypad_display$466 Def0028
+S A$keypad_display$448 Def0014
+S A$keypad_display$439 Def0006
+S A$keypad_display$584 Def00A9
+S A$keypad_display$575 Def00A1
+S A$keypad_display$539 Def0083
+S A$keypad_display$449 Def0016
+S C$keypad_display.c$40$1$1 Def0000
+S A$keypad_display$585 Def00AA
+S A$keypad_display$576 Def00A4
+S A$keypad_display$558 Def0093
+S A$keypad_display$459 Def0022
+S A$keypad_display$586 Def00AD
+S A$keypad_display$577 Def00A5
+S A$keypad_display$496 Def0049
+S A$keypad_display$487 Def003F
+S A$keypad_display$478 Def0035
+S A$keypad_display$469 Def002B
+S A$keypad_display$497 Def004B
+S A$keypad_display$488 Def0041
+S A$keypad_display$479 Def0037
+S C$keypad_display.c$41$2$2 Def00A7
+S A$keypad_display$498 Def004E
+S C$keypad_display.c$38$0$0 Def0000
+S C$keypad_display.c$60$3$3 Def003F
+S C$keypad_display.c$42$3$3 Def0012
+S C$keypad_display.c$81$2$2 Def00A7
+S C$keypad_display.c$84$1$1 Def00AF
+S C$keypad_display.c$62$3$3 Def0049
+S C$keypad_display.c$53$3$3 Def0025
+S C$keypad_display.c$54$3$3 Def0028
+S C$keypad_display.c$65$3$3 Def0054
+S C$keypad_display.c$61$4$6 Def0044
+S C$keypad_display.c$56$3$3 Def002B
+S C$keypad_display.c$48$3$3 Def0022
+S C$keypad_display.c$58$3$3 Def0035
+S C$keypad_display.c$70$4$9 Def0081
+S C$keypad_display.c$68$3$3 Def0054
+S C$keypad_display.c$63$4$7 Def0051
+S C$keypad_display.c$57$4$4 Def0030
+S C$keypad_display.c$71$4$9 Def0089
+S C$keypad_display.c$72$4$9 Def0089
+S C$keypad_display.c$73$4$9 Def008B
+S C$keypad_display.c$59$4$5 Def003A
+S C$keypad_display.c$74$4$9 Def0093
+S C$keypad_display.c$75$4$9 Def0093
+S C$keypad_display.c$76$4$9 Def0095
+S C$keypad_display.c$77$4$9 Def009D
+S C$keypad_display.c$78$4$9 Def009D
+S C$keypad_display.c$69$4$9 Def007F
+S C$keypad_display.c$79$4$9 Def009F
+A CONST size 14 flags 20 addr 0
+S Fkeypad_display$keypad$0$0 Def0000
+S Fkeypad_display$display_0$0$0 Def0004
+S Fkeypad_display$display_1$0$0 Def0008
+S Fkeypad_display$display_2$0$0 Def000C
+S Fkeypad_display$display_3$0$0 Def0010
+A XINIT size 0 flags 20 addr 0
+A CABS size 0 flags 28 addr 0
+T 00 00
+R 00 00 00 02
+T 00 00
+R 00 00 00 03
+T 00 00
+R 00 00 00 03
+T 00 01
+R 00 00 00 03
+T 00 01
+R 00 00 00 03
+T 00 00
+R 00 00 00 05
+T 00 00
+R 00 00 00 05
+T 00 00
+R 00 00 00 0D
+T 00 00 02 00 00
+R 00 00 00 0D 02 03 00 B8
+T 00 00 02 00 03
+R 00 00 00 15 00 03 00 0D
+T 00 03
+R 00 00 00 0D
+T 00 03 12 00 00 80 FE
+R 00 00 00 0D 00 03 00 16
+T 00 00
+R 00 00 00 16
+T 00 00
+R 00 00 00 16
+T 00 00 E4 F5 00 00 01 F5 00 00 02
+R 00 00 00 16 F1 21 04 00 03 F1 21 08 00 03
+T 00 05
+R 00 00 00 16
+T 00 05 C3 E5 00 00 01 94 04 E5 00 00 02 64 80 94
+R 00 00 00 16 F1 21 04 00 03 F1 21 0A 00 03
+T 00 0F 80 50 EE E5 00 00 01 24 00 00 00 F5 82 E5
+R 00 00 00 16 F1 21 06 00 03 F1 01 0A 00 17
+T 00 19 00 00 02 34 00 00 00 F5 83 E4 93 F5 90 85
+R 00 00 00 16 F1 21 02 00 03 F1 81 06 00 17
+T 00 23 90 00 00 00 53 00 00 00 0F 63
+R 00 00 00 16 F1 21 03 00 03 F1 01 07 00 03
+T 00 29 00 00 00 0F E5 00 00 00 30 E0 05 75
+R 00 00 00 16 F1 01 02 00 03 F1 21 07 00 03
+T 00 31 00 00 00 00 80 1F
+R 00 00 00 16 F1 21 02 00 03
+T 00 35
+R 00 00 00 16
+T 00 35 E5 00 00 00 30 E1 05 75 00 00 00 01 80 15
+R 00 00 00 16 F1 21 03 00 03 F1 21 0A 00 03
+T 00 3F
+R 00 00 00 16
+T 00 3F E5 00 00 00 30 E2 05 75 00 00 00 02 80 0B
+R 00 00 00 16 F1 21 03 00 03 F1 21 0A 00 03
+T 00 49
+R 00 00 00 16
+T 00 49 E5 00 00 00 20 E3 03 02 00 A7
+R 00 00 00 16 F1 21 03 00 03 00 0A 00 16
+T 00 51
+R 00 00 00 16
+T 00 51 75 00 00 00 03
+R 00 00 00 16 F1 21 03 00 03
+T 00 54
+R 00 00 00 16
+T 00 54 E4 B5 00 00 01 06 E4 B5 00 00 02 02 80 23
+R 00 00 00 16 F1 21 04 00 03 F1 21 0A 00 03
+T 00 5E
+R 00 00 00 16
+T 00 5E 74 01 B5 00 00 01 06 E4 B5 00 00 02 02 80
+R 00 00 00 16 F1 21 05 00 03 F1 21 0B 00 03
+T 00 68 22
+R 00 00 00 16
+T 00 69
+R 00 00 00 16
+T 00 69 74 02 B5 00 00 01 06 E4 B5 00 00 02 02 80
+R 00 00 00 16 F1 21 05 00 03 F1 21 0B 00 03
+T 00 73 21
+R 00 00 00 16
+T 00 74
+R 00 00 00 16
+T 00 74 74 03 B5 00 00 01 06 E4 B5 00 00 02 02 80
+R 00 00 00 16 F1 21 05 00 03 F1 21 0B 00 03
+T 00 7E 20
+R 00 00 00 16
+T 00 7F
+R 00 00 00 16
+T 00 7F 80 26
+R 00 00 00 16
+T 00 81
+R 00 00 00 16
+T 00 81 E5 00 00 00 90 00 04 93 F5 B0 80 1C
+R 00 00 00 16 F1 21 03 00 03 00 07 00 17
+T 00 8B
+R 00 00 00 16
+T 00 8B E5 00 00 00 90 00 08 93 F5 B0 80 12
+R 00 00 00 16 F1 21 03 00 03 00 07 00 17
+T 00 95
+R 00 00 00 16
+T 00 95 E5 00 00 00 90 00 0C 93 F5 B0 80 08
+R 00 00 00 16 F1 21 03 00 03 00 07 00 17
+T 00 9F
+R 00 00 00 16
+T 00 9F E5 00 00 00 90 00 10 93 F5 B0
+R 00 00 00 16 F1 21 03 00 03 00 07 00 17
+T 00 A7
+R 00 00 00 16
+T 00 A7 05 00 00 01 E4 B5 00 00 01 02 05
+R 00 00 00 16 F1 21 03 00 03 F1 21 08 00 03
+T 00 AE 00 00 02
+R 00 00 00 16 F1 21 02 00 03
+T 00 AF
+R 00 00 00 16
+T 00 AF 02 00 05
+R 00 00 00 16 00 03 00 16
+T 00 00
+R 00 00 00 17
+T 00 00 EF DF BF 7F
+R 00 00 00 17
+T 00 04
+R 00 00 00 17
+T 00 04 F9 64 70 48
+R 00 00 00 17
+T 00 08
+R 00 00 00 17
+T 00 08 59 52 42 40
+R 00 00 00 17
+T 00 0C
+R 00 00 00 17
+T 00 0C F8 40 50 C6
+R 00 00 00 17
+T 00 10
+R 00 00 00 17
+T 00 10 79 C0 49 C0
+R 00 00 00 17
diff --git a/demo/keypad_display.rst b/demo/keypad_display.rst
new file mode 100644
index 0000000..e013b8e
--- /dev/null
+++ b/demo/keypad_display.rst
@@ -0,0 +1,624 @@
+ 1 ;--------------------------------------------------------
+ 2 ; File Created by SDCC : free open source ANSI-C Compiler
+ 3 ; Version 2.9.0 #5416 (Oct 6 2009) (UNIX)
+ 4 ; This file was generated Tue Oct 27 23:03:55 2009
+ 5 ;--------------------------------------------------------
+ 6 .module keypad_display
+ 7 .optsdcc -mmcs51 --model-small
+ 8
+ 9 ;--------------------------------------------------------
+ 10 ; Public variables in this module
+ 11 ;--------------------------------------------------------
+ 12 .globl _main
+ 13 .globl _CY
+ 14 .globl _AC
+ 15 .globl _F0
+ 16 .globl _RS1
+ 17 .globl _RS0
+ 18 .globl _OV
+ 19 .globl _F1
+ 20 .globl _P
+ 21 .globl _PS
+ 22 .globl _PT1
+ 23 .globl _PX1
+ 24 .globl _PT0
+ 25 .globl _PX0
+ 26 .globl _RD
+ 27 .globl _WR
+ 28 .globl _T1
+ 29 .globl _T0
+ 30 .globl _INT1
+ 31 .globl _INT0
+ 32 .globl _TXD
+ 33 .globl _RXD
+ 34 .globl _P3_7
+ 35 .globl _P3_6
+ 36 .globl _P3_5
+ 37 .globl _P3_4
+ 38 .globl _P3_3
+ 39 .globl _P3_2
+ 40 .globl _P3_1
+ 41 .globl _P3_0
+ 42 .globl _EA
+ 43 .globl _ES
+ 44 .globl _ET1
+ 45 .globl _EX1
+ 46 .globl _ET0
+ 47 .globl _EX0
+ 48 .globl _P2_7
+ 49 .globl _P2_6
+ 50 .globl _P2_5
+ 51 .globl _P2_4
+ 52 .globl _P2_3
+ 53 .globl _P2_2
+ 54 .globl _P2_1
+ 55 .globl _P2_0
+ 56 .globl _SM0
+ 57 .globl _SM1
+ 58 .globl _SM2
+ 59 .globl _REN
+ 60 .globl _TB8
+ 61 .globl _RB8
+ 62 .globl _TI
+ 63 .globl _RI
+ 64 .globl _P1_7
+ 65 .globl _P1_6
+ 66 .globl _P1_5
+ 67 .globl _P1_4
+ 68 .globl _P1_3
+ 69 .globl _P1_2
+ 70 .globl _P1_1
+ 71 .globl _P1_0
+ 72 .globl _TF1
+ 73 .globl _TR1
+ 74 .globl _TF0
+ 75 .globl _TR0
+ 76 .globl _IE1
+ 77 .globl _IT1
+ 78 .globl _IE0
+ 79 .globl _IT0
+ 80 .globl _P0_7
+ 81 .globl _P0_6
+ 82 .globl _P0_5
+ 83 .globl _P0_4
+ 84 .globl _P0_3
+ 85 .globl _P0_2
+ 86 .globl _P0_1
+ 87 .globl _P0_0
+ 88 .globl _B
+ 89 .globl _ACC
+ 90 .globl _PSW
+ 91 .globl _IP
+ 92 .globl _P3
+ 93 .globl _IE
+ 94 .globl _P2
+ 95 .globl _SBUF
+ 96 .globl _SCON
+ 97 .globl _P1
+ 98 .globl _TH1
+ 99 .globl _TH0
+ 100 .globl _TL1
+ 101 .globl _TL0
+ 102 .globl _TMOD
+ 103 .globl _TCON
+ 104 .globl _PCON
+ 105 .globl _DPH
+ 106 .globl _DPL
+ 107 .globl _SP
+ 108 .globl _P0
+ 109 .globl _row
+ 110 .globl _state
+ 111 ;--------------------------------------------------------
+ 112 ; special function registers
+ 113 ;--------------------------------------------------------
+ 114 .area RSEG (DATA)
+ 0080 115 G$P0$0$0 == 0x0080
+ 0080 116 _P0 = 0x0080
+ 0081 117 G$SP$0$0 == 0x0081
+ 0081 118 _SP = 0x0081
+ 0082 119 G$DPL$0$0 == 0x0082
+ 0082 120 _DPL = 0x0082
+ 0083 121 G$DPH$0$0 == 0x0083
+ 0083 122 _DPH = 0x0083
+ 0087 123 G$PCON$0$0 == 0x0087
+ 0087 124 _PCON = 0x0087
+ 0088 125 G$TCON$0$0 == 0x0088
+ 0088 126 _TCON = 0x0088
+ 0089 127 G$TMOD$0$0 == 0x0089
+ 0089 128 _TMOD = 0x0089
+ 008A 129 G$TL0$0$0 == 0x008a
+ 008A 130 _TL0 = 0x008a
+ 008B 131 G$TL1$0$0 == 0x008b
+ 008B 132 _TL1 = 0x008b
+ 008C 133 G$TH0$0$0 == 0x008c
+ 008C 134 _TH0 = 0x008c
+ 008D 135 G$TH1$0$0 == 0x008d
+ 008D 136 _TH1 = 0x008d
+ 0090 137 G$P1$0$0 == 0x0090
+ 0090 138 _P1 = 0x0090
+ 0098 139 G$SCON$0$0 == 0x0098
+ 0098 140 _SCON = 0x0098
+ 0099 141 G$SBUF$0$0 == 0x0099
+ 0099 142 _SBUF = 0x0099
+ 00A0 143 G$P2$0$0 == 0x00a0
+ 00A0 144 _P2 = 0x00a0
+ 00A8 145 G$IE$0$0 == 0x00a8
+ 00A8 146 _IE = 0x00a8
+ 00B0 147 G$P3$0$0 == 0x00b0
+ 00B0 148 _P3 = 0x00b0
+ 00B8 149 G$IP$0$0 == 0x00b8
+ 00B8 150 _IP = 0x00b8
+ 00D0 151 G$PSW$0$0 == 0x00d0
+ 00D0 152 _PSW = 0x00d0
+ 00E0 153 G$ACC$0$0 == 0x00e0
+ 00E0 154 _ACC = 0x00e0
+ 00F0 155 G$B$0$0 == 0x00f0
+ 00F0 156 _B = 0x00f0
+ 157 ;--------------------------------------------------------
+ 158 ; special function bits
+ 159 ;--------------------------------------------------------
+ 160 .area RSEG (DATA)
+ 0080 161 G$P0_0$0$0 == 0x0080
+ 0080 162 _P0_0 = 0x0080
+ 0081 163 G$P0_1$0$0 == 0x0081
+ 0081 164 _P0_1 = 0x0081
+ 0082 165 G$P0_2$0$0 == 0x0082
+ 0082 166 _P0_2 = 0x0082
+ 0083 167 G$P0_3$0$0 == 0x0083
+ 0083 168 _P0_3 = 0x0083
+ 0084 169 G$P0_4$0$0 == 0x0084
+ 0084 170 _P0_4 = 0x0084
+ 0085 171 G$P0_5$0$0 == 0x0085
+ 0085 172 _P0_5 = 0x0085
+ 0086 173 G$P0_6$0$0 == 0x0086
+ 0086 174 _P0_6 = 0x0086
+ 0087 175 G$P0_7$0$0 == 0x0087
+ 0087 176 _P0_7 = 0x0087
+ 0088 177 G$IT0$0$0 == 0x0088
+ 0088 178 _IT0 = 0x0088
+ 0089 179 G$IE0$0$0 == 0x0089
+ 0089 180 _IE0 = 0x0089
+ 008A 181 G$IT1$0$0 == 0x008a
+ 008A 182 _IT1 = 0x008a
+ 008B 183 G$IE1$0$0 == 0x008b
+ 008B 184 _IE1 = 0x008b
+ 008C 185 G$TR0$0$0 == 0x008c
+ 008C 186 _TR0 = 0x008c
+ 008D 187 G$TF0$0$0 == 0x008d
+ 008D 188 _TF0 = 0x008d
+ 008E 189 G$TR1$0$0 == 0x008e
+ 008E 190 _TR1 = 0x008e
+ 008F 191 G$TF1$0$0 == 0x008f
+ 008F 192 _TF1 = 0x008f
+ 0090 193 G$P1_0$0$0 == 0x0090
+ 0090 194 _P1_0 = 0x0090
+ 0091 195 G$P1_1$0$0 == 0x0091
+ 0091 196 _P1_1 = 0x0091
+ 0092 197 G$P1_2$0$0 == 0x0092
+ 0092 198 _P1_2 = 0x0092
+ 0093 199 G$P1_3$0$0 == 0x0093
+ 0093 200 _P1_3 = 0x0093
+ 0094 201 G$P1_4$0$0 == 0x0094
+ 0094 202 _P1_4 = 0x0094
+ 0095 203 G$P1_5$0$0 == 0x0095
+ 0095 204 _P1_5 = 0x0095
+ 0096 205 G$P1_6$0$0 == 0x0096
+ 0096 206 _P1_6 = 0x0096
+ 0097 207 G$P1_7$0$0 == 0x0097
+ 0097 208 _P1_7 = 0x0097
+ 0098 209 G$RI$0$0 == 0x0098
+ 0098 210 _RI = 0x0098
+ 0099 211 G$TI$0$0 == 0x0099
+ 0099 212 _TI = 0x0099
+ 009A 213 G$RB8$0$0 == 0x009a
+ 009A 214 _RB8 = 0x009a
+ 009B 215 G$TB8$0$0 == 0x009b
+ 009B 216 _TB8 = 0x009b
+ 009C 217 G$REN$0$0 == 0x009c
+ 009C 218 _REN = 0x009c
+ 009D 219 G$SM2$0$0 == 0x009d
+ 009D 220 _SM2 = 0x009d
+ 009E 221 G$SM1$0$0 == 0x009e
+ 009E 222 _SM1 = 0x009e
+ 009F 223 G$SM0$0$0 == 0x009f
+ 009F 224 _SM0 = 0x009f
+ 00A0 225 G$P2_0$0$0 == 0x00a0
+ 00A0 226 _P2_0 = 0x00a0
+ 00A1 227 G$P2_1$0$0 == 0x00a1
+ 00A1 228 _P2_1 = 0x00a1
+ 00A2 229 G$P2_2$0$0 == 0x00a2
+ 00A2 230 _P2_2 = 0x00a2
+ 00A3 231 G$P2_3$0$0 == 0x00a3
+ 00A3 232 _P2_3 = 0x00a3
+ 00A4 233 G$P2_4$0$0 == 0x00a4
+ 00A4 234 _P2_4 = 0x00a4
+ 00A5 235 G$P2_5$0$0 == 0x00a5
+ 00A5 236 _P2_5 = 0x00a5
+ 00A6 237 G$P2_6$0$0 == 0x00a6
+ 00A6 238 _P2_6 = 0x00a6
+ 00A7 239 G$P2_7$0$0 == 0x00a7
+ 00A7 240 _P2_7 = 0x00a7
+ 00A8 241 G$EX0$0$0 == 0x00a8
+ 00A8 242 _EX0 = 0x00a8
+ 00A9 243 G$ET0$0$0 == 0x00a9
+ 00A9 244 _ET0 = 0x00a9
+ 00AA 245 G$EX1$0$0 == 0x00aa
+ 00AA 246 _EX1 = 0x00aa
+ 00AB 247 G$ET1$0$0 == 0x00ab
+ 00AB 248 _ET1 = 0x00ab
+ 00AC 249 G$ES$0$0 == 0x00ac
+ 00AC 250 _ES = 0x00ac
+ 00AF 251 G$EA$0$0 == 0x00af
+ 00AF 252 _EA = 0x00af
+ 00B0 253 G$P3_0$0$0 == 0x00b0
+ 00B0 254 _P3_0 = 0x00b0
+ 00B1 255 G$P3_1$0$0 == 0x00b1
+ 00B1 256 _P3_1 = 0x00b1
+ 00B2 257 G$P3_2$0$0 == 0x00b2
+ 00B2 258 _P3_2 = 0x00b2
+ 00B3 259 G$P3_3$0$0 == 0x00b3
+ 00B3 260 _P3_3 = 0x00b3
+ 00B4 261 G$P3_4$0$0 == 0x00b4
+ 00B4 262 _P3_4 = 0x00b4
+ 00B5 263 G$P3_5$0$0 == 0x00b5
+ 00B5 264 _P3_5 = 0x00b5
+ 00B6 265 G$P3_6$0$0 == 0x00b6
+ 00B6 266 _P3_6 = 0x00b6
+ 00B7 267 G$P3_7$0$0 == 0x00b7
+ 00B7 268 _P3_7 = 0x00b7
+ 00B0 269 G$RXD$0$0 == 0x00b0
+ 00B0 270 _RXD = 0x00b0
+ 00B1 271 G$TXD$0$0 == 0x00b1
+ 00B1 272 _TXD = 0x00b1
+ 00B2 273 G$INT0$0$0 == 0x00b2
+ 00B2 274 _INT0 = 0x00b2
+ 00B3 275 G$INT1$0$0 == 0x00b3
+ 00B3 276 _INT1 = 0x00b3
+ 00B4 277 G$T0$0$0 == 0x00b4
+ 00B4 278 _T0 = 0x00b4
+ 00B5 279 G$T1$0$0 == 0x00b5
+ 00B5 280 _T1 = 0x00b5
+ 00B6 281 G$WR$0$0 == 0x00b6
+ 00B6 282 _WR = 0x00b6
+ 00B7 283 G$RD$0$0 == 0x00b7
+ 00B7 284 _RD = 0x00b7
+ 00B8 285 G$PX0$0$0 == 0x00b8
+ 00B8 286 _PX0 = 0x00b8
+ 00B9 287 G$PT0$0$0 == 0x00b9
+ 00B9 288 _PT0 = 0x00b9
+ 00BA 289 G$PX1$0$0 == 0x00ba
+ 00BA 290 _PX1 = 0x00ba
+ 00BB 291 G$PT1$0$0 == 0x00bb
+ 00BB 292 _PT1 = 0x00bb
+ 00BC 293 G$PS$0$0 == 0x00bc
+ 00BC 294 _PS = 0x00bc
+ 00D0 295 G$P$0$0 == 0x00d0
+ 00D0 296 _P = 0x00d0
+ 00D1 297 G$F1$0$0 == 0x00d1
+ 00D1 298 _F1 = 0x00d1
+ 00D2 299 G$OV$0$0 == 0x00d2
+ 00D2 300 _OV = 0x00d2
+ 00D3 301 G$RS0$0$0 == 0x00d3
+ 00D3 302 _RS0 = 0x00d3
+ 00D4 303 G$RS1$0$0 == 0x00d4
+ 00D4 304 _RS1 = 0x00d4
+ 00D5 305 G$F0$0$0 == 0x00d5
+ 00D5 306 _F0 = 0x00d5
+ 00D6 307 G$AC$0$0 == 0x00d6
+ 00D6 308 _AC = 0x00d6
+ 00D7 309 G$CY$0$0 == 0x00d7
+ 00D7 310 _CY = 0x00d7
+ 311 ;--------------------------------------------------------
+ 312 ; overlayable register banks
+ 313 ;--------------------------------------------------------
+ 314 .area REG_BANK_0 (REL,OVR,DATA)
+ 0000 315 .ds 8
+ 316 ;--------------------------------------------------------
+ 317 ; internal ram data
+ 318 ;--------------------------------------------------------
+ 319 .area DSEG (DATA)
+ 0000 320 G$state$0$0==.
+ 0008 321 _state::
+ 0008 322 .ds 1
+ 0001 323 G$row$0$0==.
+ 0009 324 _row::
+ 0009 325 .ds 2
+ 326 ;--------------------------------------------------------
+ 327 ; overlayable items in internal ram
+ 328 ;--------------------------------------------------------
+ 329 .area OSEG (OVR,DATA)
+ 330 ;--------------------------------------------------------
+ 331 ; Stack segment in internal ram
+ 332 ;--------------------------------------------------------
+ 333 .area SSEG (DATA)
+ 000B 334 __start__stack:
+ 000B 335 .ds 1
+ 336
+ 337 ;--------------------------------------------------------
+ 338 ; indirectly addressable internal ram data
+ 339 ;--------------------------------------------------------
+ 340 .area ISEG (DATA)
+ 341 ;--------------------------------------------------------
+ 342 ; absolute internal ram data
+ 343 ;--------------------------------------------------------
+ 344 .area IABS (ABS,DATA)
+ 345 .area IABS (ABS,DATA)
+ 346 ;--------------------------------------------------------
+ 347 ; bit data
+ 348 ;--------------------------------------------------------
+ 349 .area BSEG (BIT)
+ 350 ;--------------------------------------------------------
+ 351 ; paged external ram data
+ 352 ;--------------------------------------------------------
+ 353 .area PSEG (PAG,XDATA)
+ 354 ;--------------------------------------------------------
+ 355 ; external ram data
+ 356 ;--------------------------------------------------------
+ 357 .area XSEG (XDATA)
+ 358 ;--------------------------------------------------------
+ 359 ; absolute external ram data
+ 360 ;--------------------------------------------------------
+ 361 .area XABS (ABS,XDATA)
+ 362 ;--------------------------------------------------------
+ 363 ; external initialized ram data
+ 364 ;--------------------------------------------------------
+ 365 .area XISEG (XDATA)
+ 366 .area HOME (CODE)
+ 367 .area GSINIT0 (CODE)
+ 368 .area GSINIT1 (CODE)
+ 369 .area GSINIT2 (CODE)
+ 370 .area GSINIT3 (CODE)
+ 371 .area GSINIT4 (CODE)
+ 372 .area GSINIT5 (CODE)
+ 373 .area GSINIT (CODE)
+ 374 .area GSFINAL (CODE)
+ 375 .area CSEG (CODE)
+ 376 ;--------------------------------------------------------
+ 377 ; interrupt vector
+ 378 ;--------------------------------------------------------
+ 379 .area HOME (CODE)
+ 0000 380 __interrupt_vect:
+ 0000 02 00 08 381 ljmp __sdcc_gsinit_startup
+ 382 ;--------------------------------------------------------
+ 383 ; global & static initialisations
+ 384 ;--------------------------------------------------------
+ 385 .area HOME (CODE)
+ 386 .area GSINIT (CODE)
+ 387 .area GSFINAL (CODE)
+ 388 .area GSINIT (CODE)
+ 389 .globl __sdcc_gsinit_startup
+ 390 .globl __sdcc_program_startup
+ 391 .globl __start__stack
+ 392 .globl __mcs51_genXINIT
+ 393 .globl __mcs51_genXRAMCLEAR
+ 394 .globl __mcs51_genRAMCLEAR
+ 395 .area GSFINAL (CODE)
+ 0061 02 00 03 396 ljmp __sdcc_program_startup
+ 397 ;--------------------------------------------------------
+ 398 ; Home
+ 399 ;--------------------------------------------------------
+ 400 .area HOME (CODE)
+ 401 .area HOME (CODE)
+ 0003 402 __sdcc_program_startup:
+ 0003 12 00 64 403 lcall _main
+ 404 ; return from main will lock up
+ 0006 80 FE 405 sjmp .
+ 406 ;--------------------------------------------------------
+ 407 ; code
+ 408 ;--------------------------------------------------------
+ 409 .area CSEG (CODE)
+ 410 ;------------------------------------------------------------
+ 411 ;Allocation info for local variables in function 'main'
+ 412 ;------------------------------------------------------------
+ 413 ;------------------------------------------------------------
+ 0000 414 G$main$0$0 ==.
+ 0000 415 C$keypad_display.c$38$0$0 ==.
+ 416 ; keypad_display.c:38: int main()
+ 417 ; -----------------------------------------
+ 418 ; function main
+ 419 ; -----------------------------------------
+ 0064 420 _main:
+ 0002 421 ar2 = 0x02
+ 0003 422 ar3 = 0x03
+ 0004 423 ar4 = 0x04
+ 0005 424 ar5 = 0x05
+ 0006 425 ar6 = 0x06
+ 0007 426 ar7 = 0x07
+ 0000 427 ar0 = 0x00
+ 0001 428 ar1 = 0x01
+ 0000 429 C$keypad_display.c$40$1$1 ==.
+ 430 ; keypad_display.c:40: while(1) {
+ 0064 431 00123$:
+ 0000 432 C$keypad_display.c$41$2$2 ==.
+ 433 ; keypad_display.c:41: for(row=0; row<4; row++) {
+ 0064 E4 434 clr a
+ 0065 F5 09 435 mov _row,a
+ 0067 F5 0A 436 mov (_row + 1),a
+ 0069 437 00118$:
+ 0069 C3 438 clr c
+ 006A E5 09 439 mov a,_row
+ 006C 94 04 440 subb a,#0x04
+ 006E E5 0A 441 mov a,(_row + 1)
+ 0070 64 80 442 xrl a,#0x80
+ 0072 94 80 443 subb a,#0x80
+ 0074 50 EE 444 jnc 00123$
+ 0012 445 C$keypad_display.c$42$3$3 ==.
+ 446 ; keypad_display.c:42: P1=keypad[row];
+ 0076 E5 09 447 mov a,_row
+ 0078 24 1A 448 add a,#_keypad
+ 007A F5 82 449 mov dpl,a
+ 007C E5 0A 450 mov a,(_row + 1)
+ 007E 34 01 451 addc a,#(_keypad >> 8)
+ 0080 F5 83 452 mov dph,a
+ 0082 E4 453 clr a
+ 0083 93 454 movc a,@a+dptr
+ 0084 F5 90 455 mov _P1,a
+ 0022 456 C$keypad_display.c$48$3$3 ==.
+ 457 ; keypad_display.c:48: _endasm;
+ 458
+ 0086 85 90 08 459 mov _state, P1
+ 460
+ 0025 461 C$keypad_display.c$53$3$3 ==.
+ 462 ; keypad_display.c:53: state&=0x0f;
+ 0089 53 08 0F 463 anl _state,#0x0F
+ 0028 464 C$keypad_display.c$54$3$3 ==.
+ 465 ; keypad_display.c:54: state^=0x0f;
+ 008C 63 08 0F 466 xrl _state,#0x0F
+ 002B 467 C$keypad_display.c$56$3$3 ==.
+ 468 ; keypad_display.c:56: if(state & 1) {
+ 008F E5 08 469 mov a,_state
+ 0091 30 E0 05 470 jnb acc.0,00111$
+ 0030 471 C$keypad_display.c$57$4$4 ==.
+ 472 ; keypad_display.c:57: state=0;
+ 0094 75 08 00 473 mov _state,#0x00
+ 0097 80 1F 474 sjmp 00112$
+ 0099 475 00111$:
+ 0035 476 C$keypad_display.c$58$3$3 ==.
+ 477 ; keypad_display.c:58: } else if(state & 2) {
+ 0099 E5 08 478 mov a,_state
+ 009B 30 E1 05 479 jnb acc.1,00108$
+ 003A 480 C$keypad_display.c$59$4$5 ==.
+ 481 ; keypad_display.c:59: state=1;
+ 009E 75 08 01 482 mov _state,#0x01
+ 00A1 80 15 483 sjmp 00112$
+ 00A3 484 00108$:
+ 003F 485 C$keypad_display.c$60$3$3 ==.
+ 486 ; keypad_display.c:60: } else if(state & 4) {
+ 00A3 E5 08 487 mov a,_state
+ 00A5 30 E2 05 488 jnb acc.2,00105$
+ 0044 489 C$keypad_display.c$61$4$6 ==.
+ 490 ; keypad_display.c:61: state=2;
+ 00A8 75 08 02 491 mov _state,#0x02
+ 00AB 80 0B 492 sjmp 00112$
+ 00AD 493 00105$:
+ 0049 494 C$keypad_display.c$62$3$3 ==.
+ 495 ; keypad_display.c:62: } else if(state & 8) {
+ 00AD E5 08 496 mov a,_state
+ 00AF 20 E3 03 497 jb acc.3,00142$
+ 00B2 02 01 0B 498 ljmp 00120$
+ 00B5 499 00142$:
+ 0051 500 C$keypad_display.c$63$4$7 ==.
+ 501 ; keypad_display.c:63: state=3;
+ 00B5 75 08 03 502 mov _state,#0x03
+ 0054 503 C$keypad_display.c$65$3$3 ==.
+ 504 ; keypad_display.c:65: continue;
+ 00B8 505 00112$:
+ 0054 506 C$keypad_display.c$68$3$3 ==.
+ 507 ; keypad_display.c:68: switch(row) {
+ 00B8 E4 508 clr a
+ 00B9 B5 09 06 509 cjne a,_row,00143$
+ 00BC E4 510 clr a
+ 00BD B5 0A 02 511 cjne a,(_row + 1),00143$
+ 00C0 80 23 512 sjmp 00113$
+ 00C2 513 00143$:
+ 00C2 74 01 514 mov a,#0x01
+ 00C4 B5 09 06 515 cjne a,_row,00144$
+ 00C7 E4 516 clr a
+ 00C8 B5 0A 02 517 cjne a,(_row + 1),00144$
+ 00CB 80 22 518 sjmp 00114$
+ 00CD 519 00144$:
+ 00CD 74 02 520 mov a,#0x02
+ 00CF B5 09 06 521 cjne a,_row,00145$
+ 00D2 E4 522 clr a
+ 00D3 B5 0A 02 523 cjne a,(_row + 1),00145$
+ 00D6 80 21 524 sjmp 00115$
+ 00D8 525 00145$:
+ 00D8 74 03 526 mov a,#0x03
+ 00DA B5 09 06 527 cjne a,_row,00146$
+ 00DD E4 528 clr a
+ 00DE B5 0A 02 529 cjne a,(_row + 1),00146$
+ 00E1 80 20 530 sjmp 00116$
+ 00E3 531 00146$:
+ 007F 532 C$keypad_display.c$69$4$9 ==.
+ 533 ; keypad_display.c:69: case 0:
+ 00E3 80 26 534 sjmp 00120$
+ 00E5 535 00113$:
+ 0081 536 C$keypad_display.c$70$4$9 ==.
+ 537 ; keypad_display.c:70: P3=display_0[state];
+ 00E5 E5 08 538 mov a,_state
+ 00E7 90 01 1E 539 mov dptr,#_display_0
+ 00EA 93 540 movc a,@a+dptr
+ 00EB F5 B0 541 mov _P3,a
+ 0089 542 C$keypad_display.c$71$4$9 ==.
+ 543 ; keypad_display.c:71: break;
+ 0089 544 C$keypad_display.c$72$4$9 ==.
+ 545 ; keypad_display.c:72: case 1:
+ 00ED 80 1C 546 sjmp 00120$
+ 00EF 547 00114$:
+ 008B 548 C$keypad_display.c$73$4$9 ==.
+ 549 ; keypad_display.c:73: P3=display_1[state];
+ 00EF E5 08 550 mov a,_state
+ 00F1 90 01 22 551 mov dptr,#_display_1
+ 00F4 93 552 movc a,@a+dptr
+ 00F5 F5 B0 553 mov _P3,a
+ 0093 554 C$keypad_display.c$74$4$9 ==.
+ 555 ; keypad_display.c:74: break;
+ 0093 556 C$keypad_display.c$75$4$9 ==.
+ 557 ; keypad_display.c:75: case 2:
+ 00F7 80 12 558 sjmp 00120$
+ 00F9 559 00115$:
+ 0095 560 C$keypad_display.c$76$4$9 ==.
+ 561 ; keypad_display.c:76: P3=display_2[state];
+ 00F9 E5 08 562 mov a,_state
+ 00FB 90 01 26 563 mov dptr,#_display_2
+ 00FE 93 564 movc a,@a+dptr
+ 00FF F5 B0 565 mov _P3,a
+ 009D 566 C$keypad_display.c$77$4$9 ==.
+ 567 ; keypad_display.c:77: break;
+ 009D 568 C$keypad_display.c$78$4$9 ==.
+ 569 ; keypad_display.c:78: case 3:
+ 0101 80 08 570 sjmp 00120$
+ 0103 571 00116$:
+ 009F 572 C$keypad_display.c$79$4$9 ==.
+ 573 ; keypad_display.c:79: P3=display_3[state];
+ 0103 E5 08 574 mov a,_state
+ 0105 90 01 2A 575 mov dptr,#_display_3
+ 0108 93 576 movc a,@a+dptr
+ 0109 F5 B0 577 mov _P3,a
+ 00A7 578 C$keypad_display.c$81$2$2 ==.
+ 579 ; keypad_display.c:81: }
+ 010B 580 00120$:
+ 00A7 581 C$keypad_display.c$41$2$2 ==.
+ 582 ; keypad_display.c:41: for(row=0; row<4; row++) {
+ 010B 05 09 583 inc _row
+ 010D E4 584 clr a
+ 010E B5 09 02 585 cjne a,_row,00147$
+ 0111 05 0A 586 inc (_row + 1)
+ 0113 587 00147$:
+ 00AF 588 C$keypad_display.c$84$1$1 ==.
+ 00AF 589 XG$main$0$0 ==.
+ 0113 02 00 69 590 ljmp 00118$
+ 591 .area CSEG (CODE)
+ 592 .area CONST (CODE)
+ 0000 593 Fkeypad_display$keypad$0$0 == .
+ 011A 594 _keypad:
+ 011A EF 595 .db #0xEF
+ 011B DF 596 .db #0xDF
+ 011C BF 597 .db #0xBF
+ 011D 7F 598 .db #0x7F
+ 0004 599 Fkeypad_display$display_0$0$0 == .
+ 011E 600 _display_0:
+ 011E F9 601 .db #0xF9
+ 011F 64 602 .db #0x64
+ 0120 70 603 .db #0x70
+ 0121 48 604 .db #0x48
+ 0008 605 Fkeypad_display$display_1$0$0 == .
+ 0122 606 _display_1:
+ 0122 59 607 .db #0x59
+ 0123 52 608 .db #0x52
+ 0124 42 609 .db #0x42
+ 0125 40 610 .db #0x40
+ 000C 611 Fkeypad_display$display_2$0$0 == .
+ 0126 612 _display_2:
+ 0126 F8 613 .db #0xF8
+ 0127 40 614 .db #0x40
+ 0128 50 615 .db #0x50
+ 0129 C6 616 .db #0xC6
+ 0010 617 Fkeypad_display$display_3$0$0 == .
+ 012A 618 _display_3:
+ 012A 79 619 .db #0x79
+ 012B C0 620 .db #0xC0
+ 012C 49 621 .db #0x49
+ 012D C0 622 .db #0xC0
+ 623 .area XINIT (CODE)
+ 624 .area CABS (ABS,CODE)
diff --git a/demo/keypad_display.sym b/demo/keypad_display.sym
new file mode 100644
index 0000000..eded721
--- /dev/null
+++ b/demo/keypad_display.sym
@@ -0,0 +1,712 @@
+ ASxxxx Assembler V01.70 + NoICE + SDCC mods + Flat24 Feb-1999 (Intel 8051), page 1.
+
+Symbol Table
+
+ A 00D6
+ D A$keypad_display$381 0000 GR
+ 15 A$keypad_display$396 0000 GR
+ D A$keypad_display$403 0003 GR
+ D A$keypad_display$405 0006 GR
+ 16 A$keypad_display$434 0000 GR
+ 16 A$keypad_display$435 0001 GR
+ 16 A$keypad_display$436 0003 GR
+ 16 A$keypad_display$438 0005 GR
+ 16 A$keypad_display$439 0006 GR
+ 16 A$keypad_display$440 0008 GR
+ 16 A$keypad_display$441 000A GR
+ 16 A$keypad_display$442 000C GR
+ 16 A$keypad_display$443 000E GR
+ 16 A$keypad_display$444 0010 GR
+ 16 A$keypad_display$447 0012 GR
+ 16 A$keypad_display$448 0014 GR
+ 16 A$keypad_display$449 0016 GR
+ 16 A$keypad_display$450 0018 GR
+ 16 A$keypad_display$451 001A GR
+ 16 A$keypad_display$452 001C GR
+ 16 A$keypad_display$453 001E GR
+ 16 A$keypad_display$454 001F GR
+ 16 A$keypad_display$455 0020 GR
+ 16 A$keypad_display$459 0022 GR
+ 16 A$keypad_display$463 0025 GR
+ 16 A$keypad_display$466 0028 GR
+ 16 A$keypad_display$469 002B GR
+ 16 A$keypad_display$470 002D GR
+ 16 A$keypad_display$473 0030 GR
+ 16 A$keypad_display$474 0033 GR
+ 16 A$keypad_display$478 0035 GR
+ 16 A$keypad_display$479 0037 GR
+ 16 A$keypad_display$482 003A GR
+ 16 A$keypad_display$483 003D GR
+ 16 A$keypad_display$487 003F GR
+ 16 A$keypad_display$488 0041 GR
+ 16 A$keypad_display$491 0044 GR
+ 16 A$keypad_display$492 0047 GR
+ 16 A$keypad_display$496 0049 GR
+ 16 A$keypad_display$497 004B GR
+ 16 A$keypad_display$498 004E GR
+ 16 A$keypad_display$502 0051 GR
+ 16 A$keypad_display$508 0054 GR
+ 16 A$keypad_display$509 0055 GR
+ 16 A$keypad_display$510 0058 GR
+ 16 A$keypad_display$511 0059 GR
+ 16 A$keypad_display$512 005C GR
+ 16 A$keypad_display$514 005E GR
+ 16 A$keypad_display$515 0060 GR
+ 16 A$keypad_display$516 0063 GR
+ 16 A$keypad_display$517 0064 GR
+ 16 A$keypad_display$518 0067 GR
+ 16 A$keypad_display$520 0069 GR
+ 16 A$keypad_display$521 006B GR
+ 16 A$keypad_display$522 006E GR
+ 16 A$keypad_display$523 006F GR
+ 16 A$keypad_display$524 0072 GR
+ 16 A$keypad_display$526 0074 GR
+ 16 A$keypad_display$527 0076 GR
+ 16 A$keypad_display$528 0079 GR
+ 16 A$keypad_display$529 007A GR
+ 16 A$keypad_display$530 007D GR
+ 16 A$keypad_display$534 007F GR
+ 16 A$keypad_display$538 0081 GR
+ 16 A$keypad_display$539 0083 GR
+ 16 A$keypad_display$540 0086 GR
+ 16 A$keypad_display$541 0087 GR
+ 16 A$keypad_display$546 0089 GR
+ 16 A$keypad_display$550 008B GR
+ 16 A$keypad_display$551 008D GR
+ 16 A$keypad_display$552 0090 GR
+ 16 A$keypad_display$553 0091 GR
+ 16 A$keypad_display$558 0093 GR
+ 16 A$keypad_display$562 0095 GR
+ 16 A$keypad_display$563 0097 GR
+ 16 A$keypad_display$564 009A GR
+ 16 A$keypad_display$565 009B GR
+ 16 A$keypad_display$570 009D GR
+ 16 A$keypad_display$574 009F GR
+ 16 A$keypad_display$575 00A1 GR
+ 16 A$keypad_display$576 00A4 GR
+ 16 A$keypad_display$577 00A5 GR
+ 16 A$keypad_display$583 00A7 GR
+ 16 A$keypad_display$584 00A9 GR
+ 16 A$keypad_display$585 00AA GR
+ 16 A$keypad_display$586 00AD GR
+ 16 A$keypad_display$590 00AF GR
+ AC 00D6
+ ACC 00E0
+ ACC.0 00E0
+ ACC.1 00E1
+ ACC.2 00E2
+ ACC.3 00E3
+ ACC.4 00E4
+ ACC.5 00E5
+ ACC.6 00E6
+ ACC.7 00E7
+ B 00F0
+ B.0 00F0
+ B.1 00F1
+ B.2 00F2
+ B.3 00F3
+ B.4 00F4
+ B.5 00F5
+ B.6 00F6
+ B.7 00F7
+ 16 C$keypad_display.c$38$0$0 = 0000 GR
+ 16 C$keypad_display.c$40$1$1 = 0000 GR
+ 16 C$keypad_display.c$41$2$2 = 00A7 GR
+ 16 C$keypad_display.c$42$3$3 = 0012 GR
+ 16 C$keypad_display.c$48$3$3 = 0022 GR
+ 16 C$keypad_display.c$53$3$3 = 0025 GR
+ 16 C$keypad_display.c$54$3$3 = 0028 GR
+ 16 C$keypad_display.c$56$3$3 = 002B GR
+ 16 C$keypad_display.c$57$4$4 = 0030 GR
+ 16 C$keypad_display.c$58$3$3 = 0035 GR
+ 16 C$keypad_display.c$59$4$5 = 003A GR
+ 16 C$keypad_display.c$60$3$3 = 003F GR
+ 16 C$keypad_display.c$61$4$6 = 0044 GR
+ 16 C$keypad_display.c$62$3$3 = 0049 GR
+ 16 C$keypad_display.c$63$4$7 = 0051 GR
+ 16 C$keypad_display.c$65$3$3 = 0054 GR
+ 16 C$keypad_display.c$68$3$3 = 0054 GR
+ 16 C$keypad_display.c$69$4$9 = 007F GR
+ 16 C$keypad_display.c$70$4$9 = 0081 GR
+ 16 C$keypad_display.c$71$4$9 = 0089 GR
+ 16 C$keypad_display.c$72$4$9 = 0089 GR
+ 16 C$keypad_display.c$73$4$9 = 008B GR
+ 16 C$keypad_display.c$74$4$9 = 0093 GR
+ 16 C$keypad_display.c$75$4$9 = 0093 GR
+ 16 C$keypad_display.c$76$4$9 = 0095 GR
+ 16 C$keypad_display.c$77$4$9 = 009D GR
+ 16 C$keypad_display.c$78$4$9 = 009D GR
+ 16 C$keypad_display.c$79$4$9 = 009F GR
+ 16 C$keypad_display.c$81$2$2 = 00A7 GR
+ 16 C$keypad_display.c$84$1$1 = 00AF GR
+ CPRL2 00C8
+ CT2 00C9
+ CY 00D7
+ DPH 0083
+ DPL 0082
+ EA 00AF
+ ES 00AC
+ ET0 00A9
+ ET1 00AB
+ ET2 00AD
+ EX0 00A8
+ EX1 00AA
+ EXEN2 00CB
+ EXF2 00CE
+ F0 00D5
+ 17 Fkeypad_display$display_0$0$0 = 0004 GR
+ 17 Fkeypad_display$display_1$0$0 = 0008 GR
+ 17 Fkeypad_display$display_2$0$0 = 000C GR
+ 17 Fkeypad_display$display_3$0$0 = 0010 GR
+ 17 Fkeypad_display$keypad$0$0 = 0000 GR
+ G$AC$0$0 = 00D6 G
+ G$ACC$0$0 = 00E0 G
+ G$B$0$0 = 00F0 G
+ G$CY$0$0 = 00D7 G
+ G$DPH$0$0 = 0083 G
+ G$DPL$0$0 = 0082 G
+ G$EA$0$0 = 00AF G
+ G$ES$0$0 = 00AC G
+ G$ET0$0$0 = 00A9 G
+ G$ET1$0$0 = 00AB G
+ G$EX0$0$0 = 00A8 G
+ G$EX1$0$0 = 00AA G
+ G$F0$0$0 = 00D5 G
+ G$F1$0$0 = 00D1 G
+ G$IE$0$0 = 00A8 G
+ G$IE0$0$0 = 0089 G
+ G$IE1$0$0 = 008B G
+ G$INT0$0$0 = 00B2 G
+ G$INT1$0$0 = 00B3 G
+ G$IP$0$0 = 00B8 G
+ G$IT0$0$0 = 0088 G
+ G$IT1$0$0 = 008A G
+ G$OV$0$0 = 00D2 G
+ G$P$0$0 = 00D0 G
+ G$P0$0$0 = 0080 G
+ G$P0_0$0$0 = 0080 G
+ G$P0_1$0$0 = 0081 G
+ G$P0_2$0$0 = 0082 G
+ G$P0_3$0$0 = 0083 G
+ G$P0_4$0$0 = 0084 G
+ G$P0_5$0$0 = 0085 G
+ G$P0_6$0$0 = 0086 G
+ G$P0_7$0$0 = 0087 G
+ G$P1$0$0 = 0090 G
+ G$P1_0$0$0 = 0090 G
+ G$P1_1$0$0 = 0091 G
+ G$P1_2$0$0 = 0092 G
+ G$P1_3$0$0 = 0093 G
+ G$P1_4$0$0 = 0094 G
+ G$P1_5$0$0 = 0095 G
+ G$P1_6$0$0 = 0096 G
+ G$P1_7$0$0 = 0097 G
+ G$P2$0$0 = 00A0 G
+ G$P2_0$0$0 = 00A0 G
+ G$P2_1$0$0 = 00A1 G
+ G$P2_2$0$0 = 00A2 G
+ G$P2_3$0$0 = 00A3 G
+ G$P2_4$0$0 = 00A4 G
+ G$P2_5$0$0 = 00A5 G
+ G$P2_6$0$0 = 00A6 G
+ G$P2_7$0$0 = 00A7 G
+ G$P3$0$0 = 00B0 G
+ G$P3_0$0$0 = 00B0 G
+ G$P3_1$0$0 = 00B1 G
+ G$P3_2$0$0 = 00B2 G
+ G$P3_3$0$0 = 00B3 G
+ G$P3_4$0$0 = 00B4 G
+ G$P3_5$0$0 = 00B5 G
+ G$P3_6$0$0 = 00B6 G
+ G$P3_7$0$0 = 00B7 G
+ G$PCON$0$0 = 0087 G
+ G$PS$0$0 = 00BC G
+ G$PSW$0$0 = 00D0 G
+ G$PT0$0$0 = 00B9 G
+ G$PT1$0$0 = 00BB G
+ G$PX0$0$0 = 00B8 G
+ G$PX1$0$0 = 00BA G
+ G$RB8$0$0 = 009A G
+ G$RD$0$0 = 00B7 G
+ G$REN$0$0 = 009C G
+ G$RI$0$0 = 0098 G
+ G$RS0$0$0 = 00D3 G
+ G$RS1$0$0 = 00D4 G
+ G$RXD$0$0 = 00B0 G
+ G$SBUF$0$0 = 0099 G
+ G$SCON$0$0 = 0098 G
+ G$SM0$0$0 = 009F G
+ G$SM1$0$0 = 009E G
+ G$SM2$0$0 = 009D G
+ G$SP$0$0 = 0081 G
+ G$T0$0$0 = 00B4 G
+ G$T1$0$0 = 00B5 G
+ G$TB8$0$0 = 009B G
+ G$TCON$0$0 = 0088 G
+ G$TF0$0$0 = 008D G
+ G$TF1$0$0 = 008F G
+ G$TH0$0$0 = 008C G
+ G$TH1$0$0 = 008D G
+ G$TI$0$0 = 0099 G
+ G$TL0$0$0 = 008A G
+ G$TL1$0$0 = 008B G
+ G$TMOD$0$0 = 0089 G
+ G$TR0$0$0 = 008C G
+ G$TR1$0$0 = 008E G
+ G$TXD$0$0 = 00B1 G
+ G$WR$0$0 = 00B6 G
+ 16 G$main$0$0 = 0000 GR
+ 3 G$row$0$0 = 0001 GR
+ 3 G$state$0$0 = 0000 GR
+ IE 00A8
+ IE.0 00A8
+ IE.1 00A9
+ IE.2 00AA
+ IE.3 00AB
+ IE.4 00AC
+ IE.5 00AD
+ IE.7 00AF
+ IE0 0089
+ IE1 008B
+ INT0 00B2
+ INT1 00B3
+ IP 00B8
+ IP.0 00B8
+ IP.1 00B9
+ IP.2 00BA
+ IP.3 00BB
+ IP.4 00BC
+ IP.5 00BD
+ IT0 0088
+ IT1 008A
+ OV 00D2
+ P 00D0
+ P0 0080
+ P0.0 0080
+ P0.1 0081
+ P0.2 0082
+ P0.3 0083
+ P0.4 0084
+ P0.5 0085
+ P0.6 0086
+ P0.7 0087
+ P1 0090
+ P1.0 0090
+ P1.1 0091
+ P1.2 0092
+ P1.3 0093
+ P1.4 0094
+ P1.5 0095
+ P1.6 0096
+ P1.7 0097
+ P2 00A0
+ P2.0 00A0
+ P2.1 00A1
+ P2.2 00A2
+ P2.3 00A3
+ P2.4 00A4
+ P2.5 00A5
+ P2.6 00A6
+ P2.7 00A7
+ P3 00B0
+ P3.0 00B0
+ P3.1 00B1
+ P3.2 00B2
+ P3.3 00B3
+ P3.4 00B4
+ P3.5 00B5
+ P3.6 00B6
+ P3.7 00B7
+ PCON 0087
+ PS 00BC
+ PSW 00D0
+ PSW.0 00D0
+ PSW.1 00D1
+ PSW.2 00D2
+ PSW.3 00D3
+ PSW.4 00D4
+ PSW.5 00D5
+ PSW.6 00D6
+ PSW.7 00D7
+ PT0 00B9
+ PT1 00BB
+ PT2 00BD
+ PX0 00B8
+ PX1 00BA
+ RB8 009A
+ RCAP2H 00CB
+ RCAP2L 00CA
+ RCLK 00CD
+ REN 009C
+ RI 0098
+ RS0 00D3
+ RS1 00D4
+ RXD 00B0
+ SBUF 0099
+ SCON 0098
+ SCON.0 0098
+ SCON.1 0099
+ SCON.2 009A
+ SCON.3 009B
+ SCON.4 009C
+ SCON.5 009D
+ SCON.6 009E
+ SCON.7 009F
+ SM0 009F
+ SM1 009E
+ SM2 009D
+ SP 0081
+ T2CON 00C8
+ T2CON.0 00C8
+ T2CON.1 00C9
+ T2CON.2 00CA
+ T2CON.3 00CB
+ T2CON.4 00CC
+ T2CON.5 00CD
+ T2CON.6 00CE
+ T2CON.7 00CF
+ TB8 009B
+ TCLK 00CC
+ TCON 0088
+ TCON.0 0088
+ TCON.1 0089
+ TCON.2 008A
+ TCON.3 008B
+ TCON.4 008C
+ TCON.5 008D
+ TCON.6 008E
+ TCON.7 008F
+ TF0 008D
+ TF1 008F
+ TF2 00CF
+ TH0 008C
+ TH1 008D
+ TH2 00CD
+ TI 0099
+ TL0 008A
+ TL1 008B
+ TL2 00CC
+ TMOD 0089
+ TR0 008C
+ TR1 008E
+ TR2 00CA
+ TXD 00B1
+ 16 XG$main$0$0 = 00AF GR
+ _AC = 00D6 G
+ _ACC = 00E0 G
+ _B = 00F0 G
+ _CY = 00D7 G
+ _DPH = 0083 G
+ _DPL = 0082 G
+ _EA = 00AF G
+ _ES = 00AC G
+ _ET0 = 00A9 G
+ _ET1 = 00AB G
+ _EX0 = 00A8 G
+ _EX1 = 00AA G
+ _F0 = 00D5 G
+ _F1 = 00D1 G
+ _IE = 00A8 G
+ _IE0 = 0089 G
+ _IE1 = 008B G
+ _INT0 = 00B2 G
+ _INT1 = 00B3 G
+ _IP = 00B8 G
+ _IT0 = 0088 G
+ _IT1 = 008A G
+ _OV = 00D2 G
+ _P = 00D0 G
+ _P0 = 0080 G
+ _P0_0 = 0080 G
+ _P0_1 = 0081 G
+ _P0_2 = 0082 G
+ _P0_3 = 0083 G
+ _P0_4 = 0084 G
+ _P0_5 = 0085 G
+ _P0_6 = 0086 G
+ _P0_7 = 0087 G
+ _P1 = 0090 G
+ _P1_0 = 0090 G
+ _P1_1 = 0091 G
+ _P1_2 = 0092 G
+ _P1_3 = 0093 G
+ _P1_4 = 0094 G
+ _P1_5 = 0095 G
+ _P1_6 = 0096 G
+ _P1_7 = 0097 G
+ _P2 = 00A0 G
+ _P2_0 = 00A0 G
+ _P2_1 = 00A1 G
+ _P2_2 = 00A2 G
+ _P2_3 = 00A3 G
+ _P2_4 = 00A4 G
+ _P2_5 = 00A5 G
+ _P2_6 = 00A6 G
+ _P2_7 = 00A7 G
+ _P3 = 00B0 G
+ _P3_0 = 00B0 G
+ _P3_1 = 00B1 G
+ _P3_2 = 00B2 G
+ _P3_3 = 00B3 G
+ _P3_4 = 00B4 G
+ _P3_5 = 00B5 G
+ _P3_6 = 00B6 G
+ _P3_7 = 00B7 G
+ _PCON = 0087 G
+ _PS = 00BC G
+ _PSW = 00D0 G
+ _PT0 = 00B9 G
+ _PT1 = 00BB G
+ _PX0 = 00B8 G
+ _PX1 = 00BA G
+ _RB8 = 009A G
+ _RD = 00B7 G
+ _REN = 009C G
+ _RI = 0098 G
+ _RS0 = 00D3 G
+ _RS1 = 00D4 G
+ _RXD = 00B0 G
+ _SBUF = 0099 G
+ _SCON = 0098 G
+ _SM0 = 009F G
+ _SM1 = 009E G
+ _SM2 = 009D G
+ _SP = 0081 G
+ _T0 = 00B4 G
+ _T1 = 00B5 G
+ _TB8 = 009B G
+ _TCON = 0088 G
+ _TF0 = 008D G
+ _TF1 = 008F G
+ _TH0 = 008C G
+ _TH1 = 008D G
+ _TI = 0099 G
+ _TL0 = 008A G
+ _TL1 = 008B G
+ _TMOD = 0089 G
+ _TR0 = 008C G
+ _TR1 = 008E G
+ _TXD = 00B1 G
+ _WR = 00B6 G
+ D __interrupt_vect 0000 R
+ __mcs51_genRAMCLEAR **** GX
+ __mcs51_genXINIT **** GX
+ __mcs51_genXRAMCLEAR **** GX
+ __sdcc_gsinit_startup **** GX
+ D __sdcc_program_startup 0003 GR
+ 5 __start__stack 0000 GR
+ 17 _display_0 0004 R
+ 17 _display_1 0008 R
+ 17 _display_2 000C R
+ 17 _display_3 0010 R
+ 17 _keypad 0000 R
+ 16 _main 0000 GR
+ 3 _row 0001 GR
+ 3 _state 0000 GR
+ a 00D6
+ ac 00D6
+ acc 00E0
+ acc.0 00E0
+ acc.1 00E1
+ acc.2 00E2
+ acc.3 00E3
+ acc.4 00E4
+ acc.5 00E5
+ acc.6 00E6
+ acc.7 00E7
+ ar0 = 0000
+ ar1 = 0001
+ ar2 = 0002
+ ar3 = 0003
+ ar4 = 0004
+ ar5 = 0005
+ ar6 = 0006
+ ar7 = 0007
+ b 00F0
+ b.0 00F0
+ b.1 00F1
+ b.2 00F2
+ b.3 00F3
+ b.4 00F4
+ b.5 00F5
+ b.6 00F6
+ b.7 00F7
+ cprl2 00C8
+ ct2 00C9
+ cy 00D7
+ dph 0083
+ dpl 0082
+ ea 00AF
+ es 00AC
+ et0 00A9
+ et1 00AB
+ et2 00AD
+ ex0 00A8
+ ex1 00AA
+ exen2 00CB
+ exf2 00CE
+ f0 00D5
+ ie 00A8
+ ie.0 00A8
+ ie.1 00A9
+ ie.2 00AA
+ ie.3 00AB
+ ie.4 00AC
+ ie.5 00AD
+ ie.7 00AF
+ ie0 0089
+ ie1 008B
+ int0 00B2
+ int1 00B3
+ ip 00B8
+ ip.0 00B8
+ ip.1 00B9
+ ip.2 00BA
+ ip.3 00BB
+ ip.4 00BC
+ ip.5 00BD
+ it0 0088
+ it1 008A
+ ov 00D2
+ p 00D0
+ p0 0080
+ p0.0 0080
+ p0.1 0081
+ p0.2 0082
+ p0.3 0083
+ p0.4 0084
+ p0.5 0085
+ p0.6 0086
+ p0.7 0087
+ p1 0090
+ p1.0 0090
+ p1.1 0091
+ p1.2 0092
+ p1.3 0093
+ p1.4 0094
+ p1.5 0095
+ p1.6 0096
+ p1.7 0097
+ p2 00A0
+ p2.0 00A0
+ p2.1 00A1
+ p2.2 00A2
+ p2.3 00A3
+ p2.4 00A4
+ p2.5 00A5
+ p2.6 00A6
+ p2.7 00A7
+ p3 00B0
+ p3.0 00B0
+ p3.1 00B1
+ p3.2 00B2
+ p3.3 00B3
+ p3.4 00B4
+ p3.5 00B5
+ p3.6 00B6
+ p3.7 00B7
+ pcon 0087
+ ps 00BC
+ psw 00D0
+ psw.0 00D0
+ psw.1 00D1
+ psw.2 00D2
+ psw.3 00D3
+ psw.4 00D4
+ psw.5 00D5
+ psw.6 00D6
+ psw.7 00D7
+ pt0 00B9
+ pt1 00BB
+ pt2 00BD
+ px0 00B8
+ px1 00BA
+ rb8 009A
+ rcap2h 00CB
+ rcap2l 00CA
+ rclk 00CD
+ ren 009C
+ ri 0098
+ rs0 00D3
+ rs1 00D4
+ rxd 00B0
+ sbuf 0099
+ scon 0098
+ scon.0 0098
+ scon.1 0099
+ scon.2 009A
+ scon.3 009B
+ scon.4 009C
+ scon.5 009D
+ scon.6 009E
+ scon.7 009F
+ sm0 009F
+ sm1 009E
+ sm2 009D
+ sp 0081
+ t2con 00C8
+ t2con.0 00C8
+ t2con.1 00C9
+ t2con.2 00CA
+ t2con.3 00CB
+ t2con.4 00CC
+ t2con.5 00CD
+ t2con.6 00CE
+ t2con.7 00CF
+ tb8 009B
+ tclk 00CC
+ tcon 0088
+ tcon.0 0088
+ tcon.1 0089
+ tcon.2 008A
+ tcon.3 008B
+ tcon.4 008C
+ tcon.5 008D
+ tcon.6 008E
+ tcon.7 008F
+ tf0 008D
+ tf1 008F
+ tf2 00CF
+ th0 008C
+ th1 008D
+ th2 00CD
+ ti 0099
+ tl0 008A
+ tl1 008B
+ tl2 00CC
+ tmod 0089
+ tr0 008C
+ tr1 008E
+ tr2 00CA
+ txd 00B1
+
+ ASxxxx Assembler V01.70 + NoICE + SDCC mods + Flat24 Feb-1999 (Intel 8051), page 2.
+
+Area Table
+
+ 0 _CODE size 0 flags 0
+ 1 RSEG size 0 flags 0
+ 2 REG_BANK_0 size 8 flags 4
+ 3 DSEG size 3 flags 0
+ 4 OSEG size 0 flags 4
+ 5 SSEG size 1 flags 0
+ 6 ISEG size 0 flags 0
+ 7 IABS size 0 flags 8
+ 8 BSEG size 0 flags 80
+ 9 PSEG size 0 flags 50
+ A XSEG size 0 flags 40
+ B XABS size 0 flags 48
+ C XISEG size 0 flags 40
+ D HOME size 8 flags 20
+ E GSINIT0 size 0 flags 20
+ F GSINIT1 size 0 flags 20
+ 10 GSINIT2 size 0 flags 20
+ 11 GSINIT3 size 0 flags 20
+ 12 GSINIT4 size 0 flags 20
+ 13 GSINIT5 size 0 flags 20
+ 14 GSINIT size 0 flags 20
+ 15 GSFINAL size 3 flags 20
+ 16 CSEG size B2 flags 20
+ 17 CONST size 14 flags 20
+ 18 XINIT size 0 flags 20
+ 19 CABS size 0 flags 28
diff --git a/demo/keypad_display.vhw b/demo/keypad_display.vhw
new file mode 100644
index 0000000..0a716f1
--- /dev/null
+++ b/demo/keypad_display.vhw
@@ -0,0 +1,6 @@
+# MCU 8051 IDE: Virtual HW configuration file
+# Date: 10/27/2009
+# Project: Demo-project
+
+LedDisplay {{4 3 0 3 5 3 1 3 6 3 2 3 7 3 3 3} {4 3 0 7 5 2 1 6 6 0 2 5 7 - 3 4} 230x170+335+204 {Number of pressed key} red 1}
+MatrixKeyPad {{4 1 0 1 5 1 1 1 6 1 2 1 7 1 3 1} {4 7 0 3 5 6 1 2 6 5 2 1 7 4 3 0} 225x235+79+174 {Pres any button and wait ...} {0 0 1 0 2 1 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0} 1}
diff --git a/demo/ledmatrix.adb b/demo/ledmatrix.adb
new file mode 100644
index 0000000..d573f21
--- /dev/null
+++ b/demo/ledmatrix.adb
@@ -0,0 +1,102 @@
+M:ledmatrix
+F:G$main$0$0({2}DF,SI:S),C,0,0,0,0,0
+S:Lmain$i$1$1({2}SI:S),R,0,0,[r2,r3]
+S:G$P0$0$0({1}SC:U),I,0,0
+S:G$SP$0$0({1}SC:U),I,0,0
+S:G$DPL$0$0({1}SC:U),I,0,0
+S:G$DPH$0$0({1}SC:U),I,0,0
+S:G$PCON$0$0({1}SC:U),I,0,0
+S:G$TCON$0$0({1}SC:U),I,0,0
+S:G$TMOD$0$0({1}SC:U),I,0,0
+S:G$TL0$0$0({1}SC:U),I,0,0
+S:G$TL1$0$0({1}SC:U),I,0,0
+S:G$TH0$0$0({1}SC:U),I,0,0
+S:G$TH1$0$0({1}SC:U),I,0,0
+S:G$P1$0$0({1}SC:U),I,0,0
+S:G$SCON$0$0({1}SC:U),I,0,0
+S:G$SBUF$0$0({1}SC:U),I,0,0
+S:G$P2$0$0({1}SC:U),I,0,0
+S:G$IE$0$0({1}SC:U),I,0,0
+S:G$P3$0$0({1}SC:U),I,0,0
+S:G$IP$0$0({1}SC:U),I,0,0
+S:G$PSW$0$0({1}SC:U),I,0,0
+S:G$ACC$0$0({1}SC:U),I,0,0
+S:G$A$0$0({1}SC:U),I,0,0
+S:G$B$0$0({1}SC:U),I,0,0
+S:G$P0_0$0$0({1}SX:U),J,0,0
+S:G$P0_1$0$0({1}SX:U),J,0,0
+S:G$P0_2$0$0({1}SX:U),J,0,0
+S:G$P0_3$0$0({1}SX:U),J,0,0
+S:G$P0_4$0$0({1}SX:U),J,0,0
+S:G$P0_5$0$0({1}SX:U),J,0,0
+S:G$P0_6$0$0({1}SX:U),J,0,0
+S:G$P0_7$0$0({1}SX:U),J,0,0
+S:G$IT0$0$0({1}SX:U),J,0,0
+S:G$IE0$0$0({1}SX:U),J,0,0
+S:G$IT1$0$0({1}SX:U),J,0,0
+S:G$IE1$0$0({1}SX:U),J,0,0
+S:G$TR0$0$0({1}SX:U),J,0,0
+S:G$TF0$0$0({1}SX:U),J,0,0
+S:G$TR1$0$0({1}SX:U),J,0,0
+S:G$TF1$0$0({1}SX:U),J,0,0
+S:G$P1_0$0$0({1}SX:U),J,0,0
+S:G$P1_1$0$0({1}SX:U),J,0,0
+S:G$P1_2$0$0({1}SX:U),J,0,0
+S:G$P1_3$0$0({1}SX:U),J,0,0
+S:G$P1_4$0$0({1}SX:U),J,0,0
+S:G$P1_5$0$0({1}SX:U),J,0,0
+S:G$P1_6$0$0({1}SX:U),J,0,0
+S:G$P1_7$0$0({1}SX:U),J,0,0
+S:G$RI$0$0({1}SX:U),J,0,0
+S:G$TI$0$0({1}SX:U),J,0,0
+S:G$RB8$0$0({1}SX:U),J,0,0
+S:G$TB8$0$0({1}SX:U),J,0,0
+S:G$REN$0$0({1}SX:U),J,0,0
+S:G$SM2$0$0({1}SX:U),J,0,0
+S:G$SM1$0$0({1}SX:U),J,0,0
+S:G$SM0$0$0({1}SX:U),J,0,0
+S:G$P2_0$0$0({1}SX:U),J,0,0
+S:G$P2_1$0$0({1}SX:U),J,0,0
+S:G$P2_2$0$0({1}SX:U),J,0,0
+S:G$P2_3$0$0({1}SX:U),J,0,0
+S:G$P2_4$0$0({1}SX:U),J,0,0
+S:G$P2_5$0$0({1}SX:U),J,0,0
+S:G$P2_6$0$0({1}SX:U),J,0,0
+S:G$P2_7$0$0({1}SX:U),J,0,0
+S:G$EX0$0$0({1}SX:U),J,0,0
+S:G$ET0$0$0({1}SX:U),J,0,0
+S:G$EX1$0$0({1}SX:U),J,0,0
+S:G$ET1$0$0({1}SX:U),J,0,0
+S:G$ES$0$0({1}SX:U),J,0,0
+S:G$EA$0$0({1}SX:U),J,0,0
+S:G$P3_0$0$0({1}SX:U),J,0,0
+S:G$P3_1$0$0({1}SX:U),J,0,0
+S:G$P3_2$0$0({1}SX:U),J,0,0
+S:G$P3_3$0$0({1}SX:U),J,0,0
+S:G$P3_4$0$0({1}SX:U),J,0,0
+S:G$P3_5$0$0({1}SX:U),J,0,0
+S:G$P3_6$0$0({1}SX:U),J,0,0
+S:G$P3_7$0$0({1}SX:U),J,0,0
+S:G$RXD$0$0({1}SX:U),J,0,0
+S:G$TXD$0$0({1}SX:U),J,0,0
+S:G$INT0$0$0({1}SX:U),J,0,0
+S:G$INT1$0$0({1}SX:U),J,0,0
+S:G$T0$0$0({1}SX:U),J,0,0
+S:G$T1$0$0({1}SX:U),J,0,0
+S:G$WR$0$0({1}SX:U),J,0,0
+S:G$RD$0$0({1}SX:U),J,0,0
+S:G$PX0$0$0({1}SX:U),J,0,0
+S:G$PT0$0$0({1}SX:U),J,0,0
+S:G$PX1$0$0({1}SX:U),J,0,0
+S:G$PT1$0$0({1}SX:U),J,0,0
+S:G$PS$0$0({1}SX:U),J,0,0
+S:G$P$0$0({1}SX:U),J,0,0
+S:G$FL$0$0({1}SX:U),J,0,0
+S:G$OV$0$0({1}SX:U),J,0,0
+S:G$RS0$0$0({1}SX:U),J,0,0
+S:G$RS1$0$0({1}SX:U),J,0,0
+S:G$F0$0$0({1}SX:U),J,0,0
+S:G$AC$0$0({1}SX:U),J,0,0
+S:G$CY$0$0({1}SX:U),J,0,0
+S:G$main$0$0({2}DF,SI:S),C,0,0
+S:Fledmatrix$image$0$0({8}DA8,SC:S),D,0,0
diff --git a/demo/ledmatrix.asm b/demo/ledmatrix.asm
new file mode 100644
index 0000000..d1b8e55
--- /dev/null
+++ b/demo/ledmatrix.asm
@@ -0,0 +1,494 @@
+;--------------------------------------------------------
+; File Created by SDCC : free open source ANSI-C Compiler
+; Version 2.9.0 #5416 (Oct 6 2009) (UNIX)
+; This file was generated Mon Oct 19 23:11:07 2009
+;--------------------------------------------------------
+ .module ledmatrix
+ .optsdcc -mmcs51 --model-small
+
+;--------------------------------------------------------
+; Public variables in this module
+;--------------------------------------------------------
+ .globl _main
+ .globl _CY
+ .globl _AC
+ .globl _F0
+ .globl _RS1
+ .globl _RS0
+ .globl _OV
+ .globl _FL
+ .globl _P
+ .globl _PS
+ .globl _PT1
+ .globl _PX1
+ .globl _PT0
+ .globl _PX0
+ .globl _RD
+ .globl _WR
+ .globl _T1
+ .globl _T0
+ .globl _INT1
+ .globl _INT0
+ .globl _TXD
+ .globl _RXD
+ .globl _P3_7
+ .globl _P3_6
+ .globl _P3_5
+ .globl _P3_4
+ .globl _P3_3
+ .globl _P3_2
+ .globl _P3_1
+ .globl _P3_0
+ .globl _EA
+ .globl _ES
+ .globl _ET1
+ .globl _EX1
+ .globl _ET0
+ .globl _EX0
+ .globl _P2_7
+ .globl _P2_6
+ .globl _P2_5
+ .globl _P2_4
+ .globl _P2_3
+ .globl _P2_2
+ .globl _P2_1
+ .globl _P2_0
+ .globl _SM0
+ .globl _SM1
+ .globl _SM2
+ .globl _REN
+ .globl _TB8
+ .globl _RB8
+ .globl _TI
+ .globl _RI
+ .globl _P1_7
+ .globl _P1_6
+ .globl _P1_5
+ .globl _P1_4
+ .globl _P1_3
+ .globl _P1_2
+ .globl _P1_1
+ .globl _P1_0
+ .globl _TF1
+ .globl _TR1
+ .globl _TF0
+ .globl _TR0
+ .globl _IE1
+ .globl _IT1
+ .globl _IE0
+ .globl _IT0
+ .globl _P0_7
+ .globl _P0_6
+ .globl _P0_5
+ .globl _P0_4
+ .globl _P0_3
+ .globl _P0_2
+ .globl _P0_1
+ .globl _P0_0
+ .globl _B
+ .globl _A
+ .globl _ACC
+ .globl _PSW
+ .globl _IP
+ .globl _P3
+ .globl _IE
+ .globl _P2
+ .globl _SBUF
+ .globl _SCON
+ .globl _P1
+ .globl _TH1
+ .globl _TH0
+ .globl _TL1
+ .globl _TL0
+ .globl _TMOD
+ .globl _TCON
+ .globl _PCON
+ .globl _DPH
+ .globl _DPL
+ .globl _SP
+ .globl _P0
+;--------------------------------------------------------
+; special function registers
+;--------------------------------------------------------
+ .area RSEG (DATA)
+G$P0$0$0 == 0x0080
+_P0 = 0x0080
+G$SP$0$0 == 0x0081
+_SP = 0x0081
+G$DPL$0$0 == 0x0082
+_DPL = 0x0082
+G$DPH$0$0 == 0x0083
+_DPH = 0x0083
+G$PCON$0$0 == 0x0087
+_PCON = 0x0087
+G$TCON$0$0 == 0x0088
+_TCON = 0x0088
+G$TMOD$0$0 == 0x0089
+_TMOD = 0x0089
+G$TL0$0$0 == 0x008a
+_TL0 = 0x008a
+G$TL1$0$0 == 0x008b
+_TL1 = 0x008b
+G$TH0$0$0 == 0x008c
+_TH0 = 0x008c
+G$TH1$0$0 == 0x008d
+_TH1 = 0x008d
+G$P1$0$0 == 0x0090
+_P1 = 0x0090
+G$SCON$0$0 == 0x0098
+_SCON = 0x0098
+G$SBUF$0$0 == 0x0099
+_SBUF = 0x0099
+G$P2$0$0 == 0x00a0
+_P2 = 0x00a0
+G$IE$0$0 == 0x00a8
+_IE = 0x00a8
+G$P3$0$0 == 0x00b0
+_P3 = 0x00b0
+G$IP$0$0 == 0x00b8
+_IP = 0x00b8
+G$PSW$0$0 == 0x00d0
+_PSW = 0x00d0
+G$ACC$0$0 == 0x00e0
+_ACC = 0x00e0
+G$A$0$0 == 0x00e0
+_A = 0x00e0
+G$B$0$0 == 0x00f0
+_B = 0x00f0
+;--------------------------------------------------------
+; special function bits
+;--------------------------------------------------------
+ .area RSEG (DATA)
+G$P0_0$0$0 == 0x0080
+_P0_0 = 0x0080
+G$P0_1$0$0 == 0x0081
+_P0_1 = 0x0081
+G$P0_2$0$0 == 0x0082
+_P0_2 = 0x0082
+G$P0_3$0$0 == 0x0083
+_P0_3 = 0x0083
+G$P0_4$0$0 == 0x0084
+_P0_4 = 0x0084
+G$P0_5$0$0 == 0x0085
+_P0_5 = 0x0085
+G$P0_6$0$0 == 0x0086
+_P0_6 = 0x0086
+G$P0_7$0$0 == 0x0087
+_P0_7 = 0x0087
+G$IT0$0$0 == 0x0088
+_IT0 = 0x0088
+G$IE0$0$0 == 0x0089
+_IE0 = 0x0089
+G$IT1$0$0 == 0x008a
+_IT1 = 0x008a
+G$IE1$0$0 == 0x008b
+_IE1 = 0x008b
+G$TR0$0$0 == 0x008c
+_TR0 = 0x008c
+G$TF0$0$0 == 0x008d
+_TF0 = 0x008d
+G$TR1$0$0 == 0x008e
+_TR1 = 0x008e
+G$TF1$0$0 == 0x008f
+_TF1 = 0x008f
+G$P1_0$0$0 == 0x0090
+_P1_0 = 0x0090
+G$P1_1$0$0 == 0x0091
+_P1_1 = 0x0091
+G$P1_2$0$0 == 0x0092
+_P1_2 = 0x0092
+G$P1_3$0$0 == 0x0093
+_P1_3 = 0x0093
+G$P1_4$0$0 == 0x0094
+_P1_4 = 0x0094
+G$P1_5$0$0 == 0x0095
+_P1_5 = 0x0095
+G$P1_6$0$0 == 0x0096
+_P1_6 = 0x0096
+G$P1_7$0$0 == 0x0097
+_P1_7 = 0x0097
+G$RI$0$0 == 0x0098
+_RI = 0x0098
+G$TI$0$0 == 0x0099
+_TI = 0x0099
+G$RB8$0$0 == 0x009a
+_RB8 = 0x009a
+G$TB8$0$0 == 0x009b
+_TB8 = 0x009b
+G$REN$0$0 == 0x009c
+_REN = 0x009c
+G$SM2$0$0 == 0x009d
+_SM2 = 0x009d
+G$SM1$0$0 == 0x009e
+_SM1 = 0x009e
+G$SM0$0$0 == 0x009f
+_SM0 = 0x009f
+G$P2_0$0$0 == 0x00a0
+_P2_0 = 0x00a0
+G$P2_1$0$0 == 0x00a1
+_P2_1 = 0x00a1
+G$P2_2$0$0 == 0x00a2
+_P2_2 = 0x00a2
+G$P2_3$0$0 == 0x00a3
+_P2_3 = 0x00a3
+G$P2_4$0$0 == 0x00a4
+_P2_4 = 0x00a4
+G$P2_5$0$0 == 0x00a5
+_P2_5 = 0x00a5
+G$P2_6$0$0 == 0x00a6
+_P2_6 = 0x00a6
+G$P2_7$0$0 == 0x00a7
+_P2_7 = 0x00a7
+G$EX0$0$0 == 0x00a8
+_EX0 = 0x00a8
+G$ET0$0$0 == 0x00a9
+_ET0 = 0x00a9
+G$EX1$0$0 == 0x00aa
+_EX1 = 0x00aa
+G$ET1$0$0 == 0x00ab
+_ET1 = 0x00ab
+G$ES$0$0 == 0x00ac
+_ES = 0x00ac
+G$EA$0$0 == 0x00af
+_EA = 0x00af
+G$P3_0$0$0 == 0x00b0
+_P3_0 = 0x00b0
+G$P3_1$0$0 == 0x00b1
+_P3_1 = 0x00b1
+G$P3_2$0$0 == 0x00b2
+_P3_2 = 0x00b2
+G$P3_3$0$0 == 0x00b3
+_P3_3 = 0x00b3
+G$P3_4$0$0 == 0x00b4
+_P3_4 = 0x00b4
+G$P3_5$0$0 == 0x00b5
+_P3_5 = 0x00b5
+G$P3_6$0$0 == 0x00b6
+_P3_6 = 0x00b6
+G$P3_7$0$0 == 0x00b7
+_P3_7 = 0x00b7
+G$RXD$0$0 == 0x00b0
+_RXD = 0x00b0
+G$TXD$0$0 == 0x00b1
+_TXD = 0x00b1
+G$INT0$0$0 == 0x00b2
+_INT0 = 0x00b2
+G$INT1$0$0 == 0x00b3
+_INT1 = 0x00b3
+G$T0$0$0 == 0x00b4
+_T0 = 0x00b4
+G$T1$0$0 == 0x00b5
+_T1 = 0x00b5
+G$WR$0$0 == 0x00b6
+_WR = 0x00b6
+G$RD$0$0 == 0x00b7
+_RD = 0x00b7
+G$PX0$0$0 == 0x00b8
+_PX0 = 0x00b8
+G$PT0$0$0 == 0x00b9
+_PT0 = 0x00b9
+G$PX1$0$0 == 0x00ba
+_PX1 = 0x00ba
+G$PT1$0$0 == 0x00bb
+_PT1 = 0x00bb
+G$PS$0$0 == 0x00bc
+_PS = 0x00bc
+G$P$0$0 == 0x00d0
+_P = 0x00d0
+G$FL$0$0 == 0x00d1
+_FL = 0x00d1
+G$OV$0$0 == 0x00d2
+_OV = 0x00d2
+G$RS0$0$0 == 0x00d3
+_RS0 = 0x00d3
+G$RS1$0$0 == 0x00d4
+_RS1 = 0x00d4
+G$F0$0$0 == 0x00d5
+_F0 = 0x00d5
+G$AC$0$0 == 0x00d6
+_AC = 0x00d6
+G$CY$0$0 == 0x00d7
+_CY = 0x00d7
+;--------------------------------------------------------
+; overlayable register banks
+;--------------------------------------------------------
+ .area REG_BANK_0 (REL,OVR,DATA)
+ .ds 8
+;--------------------------------------------------------
+; internal ram data
+;--------------------------------------------------------
+ .area DSEG (DATA)
+;--------------------------------------------------------
+; overlayable items in internal ram
+;--------------------------------------------------------
+ .area OSEG (OVR,DATA)
+;--------------------------------------------------------
+; Stack segment in internal ram
+;--------------------------------------------------------
+ .area SSEG (DATA)
+__start__stack:
+ .ds 1
+
+;--------------------------------------------------------
+; indirectly addressable internal ram data
+;--------------------------------------------------------
+ .area ISEG (DATA)
+;--------------------------------------------------------
+; absolute internal ram data
+;--------------------------------------------------------
+ .area IABS (ABS,DATA)
+ .area IABS (ABS,DATA)
+;--------------------------------------------------------
+; bit data
+;--------------------------------------------------------
+ .area BSEG (BIT)
+;--------------------------------------------------------
+; paged external ram data
+;--------------------------------------------------------
+ .area PSEG (PAG,XDATA)
+;--------------------------------------------------------
+; external ram data
+;--------------------------------------------------------
+ .area XSEG (XDATA)
+;--------------------------------------------------------
+; absolute external ram data
+;--------------------------------------------------------
+ .area XABS (ABS,XDATA)
+;--------------------------------------------------------
+; external initialized ram data
+;--------------------------------------------------------
+ .area XISEG (XDATA)
+ .area HOME (CODE)
+ .area GSINIT0 (CODE)
+ .area GSINIT1 (CODE)
+ .area GSINIT2 (CODE)
+ .area GSINIT3 (CODE)
+ .area GSINIT4 (CODE)
+ .area GSINIT5 (CODE)
+ .area GSINIT (CODE)
+ .area GSFINAL (CODE)
+ .area CSEG (CODE)
+;--------------------------------------------------------
+; interrupt vector
+;--------------------------------------------------------
+ .area HOME (CODE)
+__interrupt_vect:
+ ljmp __sdcc_gsinit_startup
+;--------------------------------------------------------
+; global & static initialisations
+;--------------------------------------------------------
+ .area HOME (CODE)
+ .area GSINIT (CODE)
+ .area GSFINAL (CODE)
+ .area GSINIT (CODE)
+ .globl __sdcc_gsinit_startup
+ .globl __sdcc_program_startup
+ .globl __start__stack
+ .globl __mcs51_genXINIT
+ .globl __mcs51_genXRAMCLEAR
+ .globl __mcs51_genRAMCLEAR
+ .area GSFINAL (CODE)
+ ljmp __sdcc_program_startup
+;--------------------------------------------------------
+; Home
+;--------------------------------------------------------
+ .area HOME (CODE)
+ .area HOME (CODE)
+__sdcc_program_startup:
+ lcall _main
+; return from main will lock up
+ sjmp .
+;--------------------------------------------------------
+; code
+;--------------------------------------------------------
+ .area CSEG (CODE)
+;------------------------------------------------------------
+;Allocation info for local variables in function 'main'
+;------------------------------------------------------------
+;i Allocated to registers r2 r3
+;------------------------------------------------------------
+ G$main$0$0 ==.
+ C$ledmatrix.c$27$0$0 ==.
+; ledmatrix.c:27: int main()
+; -----------------------------------------
+; function main
+; -----------------------------------------
+_main:
+ ar2 = 0x02
+ ar3 = 0x03
+ ar4 = 0x04
+ ar5 = 0x05
+ ar6 = 0x06
+ ar7 = 0x07
+ ar0 = 0x00
+ ar1 = 0x01
+ C$ledmatrix.c$30$1$1 ==.
+; ledmatrix.c:30: while(1) {
+00102$:
+ C$ledmatrix.c$31$2$2 ==.
+; ledmatrix.c:31: for(i=0; i<8; i++) {
+ mov r2,#0x00
+ mov r3,#0x00
+00104$:
+ clr c
+ mov a,r2
+ subb a,#0x08
+ mov a,r3
+ xrl a,#0x80
+ subb a,#0x80
+ jnc 00102$
+ C$ledmatrix.c$32$3$3 ==.
+; ledmatrix.c:32: P1 = 0xff;
+ mov _P1,#0xFF
+ C$ledmatrix.c$33$3$3 ==.
+; ledmatrix.c:33: P0 = image[i];
+ mov a,r2
+ add a,#_image
+ mov dpl,a
+ mov a,r3
+ addc a,#(_image >> 8)
+ mov dph,a
+ clr a
+ movc a,@a+dptr
+ mov _P0,a
+ C$ledmatrix.c$34$3$3 ==.
+; ledmatrix.c:34: P1 = (1 << i) ^ 255;
+ mov b,r2
+ inc b
+ mov r4,#0x01
+ mov r5,#0x00
+ sjmp 00115$
+00114$:
+ mov a,r4
+ add a,r4
+ mov r4,a
+ mov a,r5
+ rlc a
+ mov r5,a
+00115$:
+ djnz b,00114$
+ mov a,#0xFF
+ xrl a,r4
+ mov _P1,a
+ C$ledmatrix.c$31$2$2 ==.
+; ledmatrix.c:31: for(i=0; i<8; i++) {
+ inc r2
+ cjne r2,#0x00,00104$
+ inc r3
+ C$ledmatrix.c$37$1$1 ==.
+ XG$main$0$0 ==.
+ sjmp 00104$
+ .area CSEG (CODE)
+ .area CONST (CODE)
+Fledmatrix$image$0$0 == .
+_image:
+ .db #0xB1
+ .db #0x9D
+ .db #0xBD
+ .db #0xB1
+ .db #0xB7
+ .db #0xB7
+ .db #0x11
+ .db #0xFF
+ .area XINIT (CODE)
+ .area CABS (ABS,CODE)
diff --git a/demo/ledmatrix.c b/demo/ledmatrix.c
new file mode 100644
index 0000000..aa1dea9
--- /dev/null
+++ b/demo/ledmatrix.c
@@ -0,0 +1,43 @@
+/**
+ * Demonstration code for <b>MCU 8051 IDE</b>
+ *
+ * Virtual HW and C language
+ * Requires MCU AT89C51 or similar ( [Project] -> [Edit project] -> [Select MCU] )
+ * @file demo_c_0.c
+ */
+
+// Create virtual LED matrix and load configuration file "ledmatrix.vhc"
+// [Virtual HW] -> [LED Matrix]
+
+// To compile the code press F11 (This code is precompiled)
+// To start simulator press F2
+// To simulate the program press F6 (animate) or F7 (step) or F8 (step over) or F9 (run)
+
+// To save some time you can use program hibernation function
+// [Simulator] -> [Resume hibernated program] and select "ledmatrix.m5hib"
+
+
+#include <at89x51.h>
+
+static const char image[] = {
+ 0xb1, 0x9d, 0xbd, 0xb1,
+ 0xb7, 0xb7, 0x11, 0xff
+};
+
+int main()
+{
+ int i;
+ while(1) {
+ for(i=0; i<8; i++) {
+ P1 = 0xff;
+ P0 = image[i];
+ P1 = (1 << i) ^ 255;
+ }
+ }
+}
+
+// Note: Sometimes people wonder how it is possible to
+// write a program for MCU in C language. So please
+// study this code or SDCC manual or another documents.
+// And please do not ask me silly questions ... :)
+// By the way my email is <martin.osmera@gmail.com>
diff --git a/demo/ledmatrix.cdb b/demo/ledmatrix.cdb
new file mode 100644
index 0000000..a049b01
--- /dev/null
+++ b/demo/ledmatrix.cdb
@@ -0,0 +1,251 @@
+M:ledmatrix
+F:G$main$0$0({2}DF,SI:S),C,0,0,0,0,0
+S:Lmain$i$1$1({2}SI:S),R,0,0,[r2,r3]
+S:G$P0$0$0({1}SC:U),I,0,0
+S:G$SP$0$0({1}SC:U),I,0,0
+S:G$DPL$0$0({1}SC:U),I,0,0
+S:G$DPH$0$0({1}SC:U),I,0,0
+S:G$PCON$0$0({1}SC:U),I,0,0
+S:G$TCON$0$0({1}SC:U),I,0,0
+S:G$TMOD$0$0({1}SC:U),I,0,0
+S:G$TL0$0$0({1}SC:U),I,0,0
+S:G$TL1$0$0({1}SC:U),I,0,0
+S:G$TH0$0$0({1}SC:U),I,0,0
+S:G$TH1$0$0({1}SC:U),I,0,0
+S:G$P1$0$0({1}SC:U),I,0,0
+S:G$SCON$0$0({1}SC:U),I,0,0
+S:G$SBUF$0$0({1}SC:U),I,0,0
+S:G$P2$0$0({1}SC:U),I,0,0
+S:G$IE$0$0({1}SC:U),I,0,0
+S:G$P3$0$0({1}SC:U),I,0,0
+S:G$IP$0$0({1}SC:U),I,0,0
+S:G$PSW$0$0({1}SC:U),I,0,0
+S:G$ACC$0$0({1}SC:U),I,0,0
+S:G$A$0$0({1}SC:U),I,0,0
+S:G$B$0$0({1}SC:U),I,0,0
+S:G$P0_0$0$0({1}SX:U),J,0,0
+S:G$P0_1$0$0({1}SX:U),J,0,0
+S:G$P0_2$0$0({1}SX:U),J,0,0
+S:G$P0_3$0$0({1}SX:U),J,0,0
+S:G$P0_4$0$0({1}SX:U),J,0,0
+S:G$P0_5$0$0({1}SX:U),J,0,0
+S:G$P0_6$0$0({1}SX:U),J,0,0
+S:G$P0_7$0$0({1}SX:U),J,0,0
+S:G$IT0$0$0({1}SX:U),J,0,0
+S:G$IE0$0$0({1}SX:U),J,0,0
+S:G$IT1$0$0({1}SX:U),J,0,0
+S:G$IE1$0$0({1}SX:U),J,0,0
+S:G$TR0$0$0({1}SX:U),J,0,0
+S:G$TF0$0$0({1}SX:U),J,0,0
+S:G$TR1$0$0({1}SX:U),J,0,0
+S:G$TF1$0$0({1}SX:U),J,0,0
+S:G$P1_0$0$0({1}SX:U),J,0,0
+S:G$P1_1$0$0({1}SX:U),J,0,0
+S:G$P1_2$0$0({1}SX:U),J,0,0
+S:G$P1_3$0$0({1}SX:U),J,0,0
+S:G$P1_4$0$0({1}SX:U),J,0,0
+S:G$P1_5$0$0({1}SX:U),J,0,0
+S:G$P1_6$0$0({1}SX:U),J,0,0
+S:G$P1_7$0$0({1}SX:U),J,0,0
+S:G$RI$0$0({1}SX:U),J,0,0
+S:G$TI$0$0({1}SX:U),J,0,0
+S:G$RB8$0$0({1}SX:U),J,0,0
+S:G$TB8$0$0({1}SX:U),J,0,0
+S:G$REN$0$0({1}SX:U),J,0,0
+S:G$SM2$0$0({1}SX:U),J,0,0
+S:G$SM1$0$0({1}SX:U),J,0,0
+S:G$SM0$0$0({1}SX:U),J,0,0
+S:G$P2_0$0$0({1}SX:U),J,0,0
+S:G$P2_1$0$0({1}SX:U),J,0,0
+S:G$P2_2$0$0({1}SX:U),J,0,0
+S:G$P2_3$0$0({1}SX:U),J,0,0
+S:G$P2_4$0$0({1}SX:U),J,0,0
+S:G$P2_5$0$0({1}SX:U),J,0,0
+S:G$P2_6$0$0({1}SX:U),J,0,0
+S:G$P2_7$0$0({1}SX:U),J,0,0
+S:G$EX0$0$0({1}SX:U),J,0,0
+S:G$ET0$0$0({1}SX:U),J,0,0
+S:G$EX1$0$0({1}SX:U),J,0,0
+S:G$ET1$0$0({1}SX:U),J,0,0
+S:G$ES$0$0({1}SX:U),J,0,0
+S:G$EA$0$0({1}SX:U),J,0,0
+S:G$P3_0$0$0({1}SX:U),J,0,0
+S:G$P3_1$0$0({1}SX:U),J,0,0
+S:G$P3_2$0$0({1}SX:U),J,0,0
+S:G$P3_3$0$0({1}SX:U),J,0,0
+S:G$P3_4$0$0({1}SX:U),J,0,0
+S:G$P3_5$0$0({1}SX:U),J,0,0
+S:G$P3_6$0$0({1}SX:U),J,0,0
+S:G$P3_7$0$0({1}SX:U),J,0,0
+S:G$RXD$0$0({1}SX:U),J,0,0
+S:G$TXD$0$0({1}SX:U),J,0,0
+S:G$INT0$0$0({1}SX:U),J,0,0
+S:G$INT1$0$0({1}SX:U),J,0,0
+S:G$T0$0$0({1}SX:U),J,0,0
+S:G$T1$0$0({1}SX:U),J,0,0
+S:G$WR$0$0({1}SX:U),J,0,0
+S:G$RD$0$0({1}SX:U),J,0,0
+S:G$PX0$0$0({1}SX:U),J,0,0
+S:G$PT0$0$0({1}SX:U),J,0,0
+S:G$PX1$0$0({1}SX:U),J,0,0
+S:G$PT1$0$0({1}SX:U),J,0,0
+S:G$PS$0$0({1}SX:U),J,0,0
+S:G$P$0$0({1}SX:U),J,0,0
+S:G$FL$0$0({1}SX:U),J,0,0
+S:G$OV$0$0({1}SX:U),J,0,0
+S:G$RS0$0$0({1}SX:U),J,0,0
+S:G$RS1$0$0({1}SX:U),J,0,0
+S:G$F0$0$0({1}SX:U),J,0,0
+S:G$AC$0$0({1}SX:U),J,0,0
+S:G$CY$0$0({1}SX:U),J,0,0
+S:G$main$0$0({2}DF,SI:S),C,0,0
+S:Fledmatrix$image$0$0({8}DA8,SC:S),D,0,0
+L:G$P0$0$0:80
+L:G$P0_0$0$0:80
+L:G$P0_1$0$0:81
+L:G$SP$0$0:81
+L:G$DPL$0$0:82
+L:G$P0_2$0$0:82
+L:G$DPH$0$0:83
+L:G$P0_3$0$0:83
+L:G$P0_4$0$0:84
+L:G$P0_5$0$0:85
+L:G$P0_6$0$0:86
+L:G$P0_7$0$0:87
+L:G$PCON$0$0:87
+L:G$IT0$0$0:88
+L:G$TCON$0$0:88
+L:G$IE0$0$0:89
+L:G$TMOD$0$0:89
+L:G$IT1$0$0:8A
+L:G$TL0$0$0:8A
+L:G$IE1$0$0:8B
+L:G$TL1$0$0:8B
+L:G$TH0$0$0:8C
+L:G$TR0$0$0:8C
+L:G$TF0$0$0:8D
+L:G$TH1$0$0:8D
+L:G$TR1$0$0:8E
+L:G$TF1$0$0:8F
+L:G$P1$0$0:90
+L:G$P1_0$0$0:90
+L:G$P1_1$0$0:91
+L:G$P1_2$0$0:92
+L:G$P1_3$0$0:93
+L:G$P1_4$0$0:94
+L:G$P1_5$0$0:95
+L:G$P1_6$0$0:96
+L:G$P1_7$0$0:97
+L:G$RI$0$0:98
+L:G$SCON$0$0:98
+L:G$SBUF$0$0:99
+L:G$TI$0$0:99
+L:G$RB8$0$0:9A
+L:G$TB8$0$0:9B
+L:G$REN$0$0:9C
+L:G$SM2$0$0:9D
+L:G$SM1$0$0:9E
+L:G$SM0$0$0:9F
+L:G$P2$0$0:A0
+L:G$P2_0$0$0:A0
+L:G$P2_1$0$0:A1
+L:G$P2_2$0$0:A2
+L:G$P2_3$0$0:A3
+L:G$P2_4$0$0:A4
+L:G$P2_5$0$0:A5
+L:G$P2_6$0$0:A6
+L:G$P2_7$0$0:A7
+L:G$EX0$0$0:A8
+L:G$IE$0$0:A8
+L:G$ET0$0$0:A9
+L:G$EX1$0$0:AA
+L:G$ET1$0$0:AB
+L:G$ES$0$0:AC
+L:G$EA$0$0:AF
+L:G$P3$0$0:B0
+L:G$P3_0$0$0:B0
+L:G$RXD$0$0:B0
+L:G$P3_1$0$0:B1
+L:G$TXD$0$0:B1
+L:G$INT0$0$0:B2
+L:G$P3_2$0$0:B2
+L:G$INT1$0$0:B3
+L:G$P3_3$0$0:B3
+L:G$P3_4$0$0:B4
+L:G$T0$0$0:B4
+L:G$P3_5$0$0:B5
+L:G$T1$0$0:B5
+L:G$P3_6$0$0:B6
+L:G$WR$0$0:B6
+L:G$P3_7$0$0:B7
+L:G$RD$0$0:B7
+L:G$IP$0$0:B8
+L:G$PX0$0$0:B8
+L:G$PT0$0$0:B9
+L:G$PX1$0$0:BA
+L:G$PT1$0$0:BB
+L:G$PS$0$0:BC
+L:G$P$0$0:D0
+L:G$PSW$0$0:D0
+L:G$FL$0$0:D1
+L:G$OV$0$0:D2
+L:G$RS0$0$0:D3
+L:G$RS1$0$0:D4
+L:G$F0$0$0:D5
+L:G$AC$0$0:D6
+L:G$CY$0$0:D7
+L:G$A$0$0:E0
+L:G$ACC$0$0:E0
+L:G$B$0$0:F0
+L:A$ledmatrix$376:0
+L:A$ledmatrix$398:3
+L:A$ledmatrix$400:6
+L:A$ledmatrix$391:61
+L:A$ledmatrix$430:64
+L:C$ledmatrix.c$27$0$0:64
+L:C$ledmatrix.c$30$1$1:64
+L:G$main$0$0:64
+L:A$ledmatrix$431:66
+L:A$ledmatrix$433:68
+L:A$ledmatrix$434:69
+L:A$ledmatrix$435:6A
+L:A$ledmatrix$436:6C
+L:A$ledmatrix$437:6D
+L:A$ledmatrix$438:6F
+L:A$ledmatrix$439:71
+L:A$ledmatrix$442:73
+L:C$ledmatrix.c$32$3$3:73
+L:A$ledmatrix$445:76
+L:C$ledmatrix.c$33$3$3:76
+L:A$ledmatrix$446:77
+L:A$ledmatrix$447:79
+L:A$ledmatrix$448:7B
+L:A$ledmatrix$449:7C
+L:A$ledmatrix$450:7E
+L:A$ledmatrix$451:80
+L:A$ledmatrix$452:81
+L:A$ledmatrix$453:82
+L:A$ledmatrix$456:84
+L:C$ledmatrix.c$34$3$3:84
+L:A$ledmatrix$457:86
+L:A$ledmatrix$458:88
+L:A$ledmatrix$459:8A
+L:A$ledmatrix$460:8C
+L:A$ledmatrix$462:8E
+L:A$ledmatrix$463:8F
+L:A$ledmatrix$464:90
+L:A$ledmatrix$465:91
+L:A$ledmatrix$466:92
+L:A$ledmatrix$467:93
+L:A$ledmatrix$469:94
+L:A$ledmatrix$470:97
+L:A$ledmatrix$471:99
+L:A$ledmatrix$472:9A
+L:A$ledmatrix$475:9C
+L:C$ledmatrix.c$31$2$2:9C
+L:A$ledmatrix$476:9D
+L:A$ledmatrix$477:A0
+L:A$ledmatrix$480:A1
+L:C$ledmatrix.c$37$1$1:A1
+L:XG$main$0$0:A1
+L:Fledmatrix$image$0$0:A7
diff --git a/demo/ledmatrix.hashes b/demo/ledmatrix.hashes
new file mode 100644
index 0000000..895b5e6
--- /dev/null
+++ b/demo/ledmatrix.hashes
@@ -0,0 +1 @@
+517133F895352F3918C3E1250EA990A5 "ledmatrix.c"
diff --git a/demo/ledmatrix.hex b/demo/ledmatrix.hex
new file mode 100644
index 0000000..339b4c0
--- /dev/null
+++ b/demo/ledmatrix.hex
@@ -0,0 +1,26 @@
+:03000000020008F3
+:0300610002000397
+:0500030012006480FE04
+:040064007A007B00A3
+:0E006800C3EA9408EB6480948050F17590FF19
+:0A007600EA24A7F582EB3400F583BD
+:0E008000E493F5808AF005F07C017D00800697
+:06008E00EC2CFCED33FD3B
+:0E009400D5F0F774FF6CF5900ABA00C80B8027
+:0100A200C598
+:0800A700B19DBDB1B7B711FF17
+:06003700E478FFF6D8FD9D
+:080015007900E94400601B7A48
+:05001D00009000AF7827
+:030022000075A0C6
+:0A00250000E493F2A308B8000205FE
+:08002F00A0D9F4DAF275A0FF7C
+:08003D007800E84400600A7934
+:030045000075A0A3
+:0600480000E4F309D8FCFE
+:08004E007800E84400600C7921
+:0B00560000900000E4F0A3D8FCD9FAF1
+:03000800758107F8
+:0A000B001200A3E582600302000367
+:0400A3007582002240
+:00000001FF
diff --git a/demo/ledmatrix.ihx b/demo/ledmatrix.ihx
new file mode 100644
index 0000000..339b4c0
--- /dev/null
+++ b/demo/ledmatrix.ihx
@@ -0,0 +1,26 @@
+:03000000020008F3
+:0300610002000397
+:0500030012006480FE04
+:040064007A007B00A3
+:0E006800C3EA9408EB6480948050F17590FF19
+:0A007600EA24A7F582EB3400F583BD
+:0E008000E493F5808AF005F07C017D00800697
+:06008E00EC2CFCED33FD3B
+:0E009400D5F0F774FF6CF5900ABA00C80B8027
+:0100A200C598
+:0800A700B19DBDB1B7B711FF17
+:06003700E478FFF6D8FD9D
+:080015007900E94400601B7A48
+:05001D00009000AF7827
+:030022000075A0C6
+:0A00250000E493F2A308B8000205FE
+:08002F00A0D9F4DAF275A0FF7C
+:08003D007800E84400600A7934
+:030045000075A0A3
+:0600480000E4F309D8FCFE
+:08004E007800E84400600C7921
+:0B00560000900000E4F0A3D8FCD9FAF1
+:03000800758107F8
+:0A000B001200A3E582600302000367
+:0400A3007582002240
+:00000001FF
diff --git a/demo/ledmatrix.lnk b/demo/ledmatrix.lnk
new file mode 100644
index 0000000..b4c7fe4
--- /dev/null
+++ b/demo/ledmatrix.lnk
@@ -0,0 +1,19 @@
+-myuxi
+-Y
+-a 0x0100
+-v 0x0000
+-w 0x2000
+-z
+-b HOME = 0x0000
+-b ISEG = 0x0000
+-b BSEG = 0x0000
+-k /usr/libexec/sdcc/../share/sdcc/lib/small
+-k /usr/share/sdcc/lib/small
+-l mcs51
+-l libsdcc
+-l libint
+-l liblong
+-l libfloat
+ledmatrix.rel
+
+-e
diff --git a/demo/ledmatrix.lst b/demo/ledmatrix.lst
new file mode 100644
index 0000000..43d46a4
--- /dev/null
+++ b/demo/ledmatrix.lst
@@ -0,0 +1,494 @@
+ 1 ;--------------------------------------------------------
+ 2 ; File Created by SDCC : free open source ANSI-C Compiler
+ 3 ; Version 2.9.0 #5416 (Oct 6 2009) (UNIX)
+ 4 ; This file was generated Mon Oct 19 23:11:07 2009
+ 5 ;--------------------------------------------------------
+ 6 .module ledmatrix
+ 7 .optsdcc -mmcs51 --model-small
+ 8
+ 9 ;--------------------------------------------------------
+ 10 ; Public variables in this module
+ 11 ;--------------------------------------------------------
+ 12 .globl _main
+ 13 .globl _CY
+ 14 .globl _AC
+ 15 .globl _F0
+ 16 .globl _RS1
+ 17 .globl _RS0
+ 18 .globl _OV
+ 19 .globl _FL
+ 20 .globl _P
+ 21 .globl _PS
+ 22 .globl _PT1
+ 23 .globl _PX1
+ 24 .globl _PT0
+ 25 .globl _PX0
+ 26 .globl _RD
+ 27 .globl _WR
+ 28 .globl _T1
+ 29 .globl _T0
+ 30 .globl _INT1
+ 31 .globl _INT0
+ 32 .globl _TXD
+ 33 .globl _RXD
+ 34 .globl _P3_7
+ 35 .globl _P3_6
+ 36 .globl _P3_5
+ 37 .globl _P3_4
+ 38 .globl _P3_3
+ 39 .globl _P3_2
+ 40 .globl _P3_1
+ 41 .globl _P3_0
+ 42 .globl _EA
+ 43 .globl _ES
+ 44 .globl _ET1
+ 45 .globl _EX1
+ 46 .globl _ET0
+ 47 .globl _EX0
+ 48 .globl _P2_7
+ 49 .globl _P2_6
+ 50 .globl _P2_5
+ 51 .globl _P2_4
+ 52 .globl _P2_3
+ 53 .globl _P2_2
+ 54 .globl _P2_1
+ 55 .globl _P2_0
+ 56 .globl _SM0
+ 57 .globl _SM1
+ 58 .globl _SM2
+ 59 .globl _REN
+ 60 .globl _TB8
+ 61 .globl _RB8
+ 62 .globl _TI
+ 63 .globl _RI
+ 64 .globl _P1_7
+ 65 .globl _P1_6
+ 66 .globl _P1_5
+ 67 .globl _P1_4
+ 68 .globl _P1_3
+ 69 .globl _P1_2
+ 70 .globl _P1_1
+ 71 .globl _P1_0
+ 72 .globl _TF1
+ 73 .globl _TR1
+ 74 .globl _TF0
+ 75 .globl _TR0
+ 76 .globl _IE1
+ 77 .globl _IT1
+ 78 .globl _IE0
+ 79 .globl _IT0
+ 80 .globl _P0_7
+ 81 .globl _P0_6
+ 82 .globl _P0_5
+ 83 .globl _P0_4
+ 84 .globl _P0_3
+ 85 .globl _P0_2
+ 86 .globl _P0_1
+ 87 .globl _P0_0
+ 88 .globl _B
+ 89 .globl _A
+ 90 .globl _ACC
+ 91 .globl _PSW
+ 92 .globl _IP
+ 93 .globl _P3
+ 94 .globl _IE
+ 95 .globl _P2
+ 96 .globl _SBUF
+ 97 .globl _SCON
+ 98 .globl _P1
+ 99 .globl _TH1
+ 100 .globl _TH0
+ 101 .globl _TL1
+ 102 .globl _TL0
+ 103 .globl _TMOD
+ 104 .globl _TCON
+ 105 .globl _PCON
+ 106 .globl _DPH
+ 107 .globl _DPL
+ 108 .globl _SP
+ 109 .globl _P0
+ 110 ;--------------------------------------------------------
+ 111 ; special function registers
+ 112 ;--------------------------------------------------------
+ 113 .area RSEG (DATA)
+ 0080 114 G$P0$0$0 == 0x0080
+ 0080 115 _P0 = 0x0080
+ 0081 116 G$SP$0$0 == 0x0081
+ 0081 117 _SP = 0x0081
+ 0082 118 G$DPL$0$0 == 0x0082
+ 0082 119 _DPL = 0x0082
+ 0083 120 G$DPH$0$0 == 0x0083
+ 0083 121 _DPH = 0x0083
+ 0087 122 G$PCON$0$0 == 0x0087
+ 0087 123 _PCON = 0x0087
+ 0088 124 G$TCON$0$0 == 0x0088
+ 0088 125 _TCON = 0x0088
+ 0089 126 G$TMOD$0$0 == 0x0089
+ 0089 127 _TMOD = 0x0089
+ 008A 128 G$TL0$0$0 == 0x008a
+ 008A 129 _TL0 = 0x008a
+ 008B 130 G$TL1$0$0 == 0x008b
+ 008B 131 _TL1 = 0x008b
+ 008C 132 G$TH0$0$0 == 0x008c
+ 008C 133 _TH0 = 0x008c
+ 008D 134 G$TH1$0$0 == 0x008d
+ 008D 135 _TH1 = 0x008d
+ 0090 136 G$P1$0$0 == 0x0090
+ 0090 137 _P1 = 0x0090
+ 0098 138 G$SCON$0$0 == 0x0098
+ 0098 139 _SCON = 0x0098
+ 0099 140 G$SBUF$0$0 == 0x0099
+ 0099 141 _SBUF = 0x0099
+ 00A0 142 G$P2$0$0 == 0x00a0
+ 00A0 143 _P2 = 0x00a0
+ 00A8 144 G$IE$0$0 == 0x00a8
+ 00A8 145 _IE = 0x00a8
+ 00B0 146 G$P3$0$0 == 0x00b0
+ 00B0 147 _P3 = 0x00b0
+ 00B8 148 G$IP$0$0 == 0x00b8
+ 00B8 149 _IP = 0x00b8
+ 00D0 150 G$PSW$0$0 == 0x00d0
+ 00D0 151 _PSW = 0x00d0
+ 00E0 152 G$ACC$0$0 == 0x00e0
+ 00E0 153 _ACC = 0x00e0
+ 00E0 154 G$A$0$0 == 0x00e0
+ 00E0 155 _A = 0x00e0
+ 00F0 156 G$B$0$0 == 0x00f0
+ 00F0 157 _B = 0x00f0
+ 158 ;--------------------------------------------------------
+ 159 ; special function bits
+ 160 ;--------------------------------------------------------
+ 161 .area RSEG (DATA)
+ 0080 162 G$P0_0$0$0 == 0x0080
+ 0080 163 _P0_0 = 0x0080
+ 0081 164 G$P0_1$0$0 == 0x0081
+ 0081 165 _P0_1 = 0x0081
+ 0082 166 G$P0_2$0$0 == 0x0082
+ 0082 167 _P0_2 = 0x0082
+ 0083 168 G$P0_3$0$0 == 0x0083
+ 0083 169 _P0_3 = 0x0083
+ 0084 170 G$P0_4$0$0 == 0x0084
+ 0084 171 _P0_4 = 0x0084
+ 0085 172 G$P0_5$0$0 == 0x0085
+ 0085 173 _P0_5 = 0x0085
+ 0086 174 G$P0_6$0$0 == 0x0086
+ 0086 175 _P0_6 = 0x0086
+ 0087 176 G$P0_7$0$0 == 0x0087
+ 0087 177 _P0_7 = 0x0087
+ 0088 178 G$IT0$0$0 == 0x0088
+ 0088 179 _IT0 = 0x0088
+ 0089 180 G$IE0$0$0 == 0x0089
+ 0089 181 _IE0 = 0x0089
+ 008A 182 G$IT1$0$0 == 0x008a
+ 008A 183 _IT1 = 0x008a
+ 008B 184 G$IE1$0$0 == 0x008b
+ 008B 185 _IE1 = 0x008b
+ 008C 186 G$TR0$0$0 == 0x008c
+ 008C 187 _TR0 = 0x008c
+ 008D 188 G$TF0$0$0 == 0x008d
+ 008D 189 _TF0 = 0x008d
+ 008E 190 G$TR1$0$0 == 0x008e
+ 008E 191 _TR1 = 0x008e
+ 008F 192 G$TF1$0$0 == 0x008f
+ 008F 193 _TF1 = 0x008f
+ 0090 194 G$P1_0$0$0 == 0x0090
+ 0090 195 _P1_0 = 0x0090
+ 0091 196 G$P1_1$0$0 == 0x0091
+ 0091 197 _P1_1 = 0x0091
+ 0092 198 G$P1_2$0$0 == 0x0092
+ 0092 199 _P1_2 = 0x0092
+ 0093 200 G$P1_3$0$0 == 0x0093
+ 0093 201 _P1_3 = 0x0093
+ 0094 202 G$P1_4$0$0 == 0x0094
+ 0094 203 _P1_4 = 0x0094
+ 0095 204 G$P1_5$0$0 == 0x0095
+ 0095 205 _P1_5 = 0x0095
+ 0096 206 G$P1_6$0$0 == 0x0096
+ 0096 207 _P1_6 = 0x0096
+ 0097 208 G$P1_7$0$0 == 0x0097
+ 0097 209 _P1_7 = 0x0097
+ 0098 210 G$RI$0$0 == 0x0098
+ 0098 211 _RI = 0x0098
+ 0099 212 G$TI$0$0 == 0x0099
+ 0099 213 _TI = 0x0099
+ 009A 214 G$RB8$0$0 == 0x009a
+ 009A 215 _RB8 = 0x009a
+ 009B 216 G$TB8$0$0 == 0x009b
+ 009B 217 _TB8 = 0x009b
+ 009C 218 G$REN$0$0 == 0x009c
+ 009C 219 _REN = 0x009c
+ 009D 220 G$SM2$0$0 == 0x009d
+ 009D 221 _SM2 = 0x009d
+ 009E 222 G$SM1$0$0 == 0x009e
+ 009E 223 _SM1 = 0x009e
+ 009F 224 G$SM0$0$0 == 0x009f
+ 009F 225 _SM0 = 0x009f
+ 00A0 226 G$P2_0$0$0 == 0x00a0
+ 00A0 227 _P2_0 = 0x00a0
+ 00A1 228 G$P2_1$0$0 == 0x00a1
+ 00A1 229 _P2_1 = 0x00a1
+ 00A2 230 G$P2_2$0$0 == 0x00a2
+ 00A2 231 _P2_2 = 0x00a2
+ 00A3 232 G$P2_3$0$0 == 0x00a3
+ 00A3 233 _P2_3 = 0x00a3
+ 00A4 234 G$P2_4$0$0 == 0x00a4
+ 00A4 235 _P2_4 = 0x00a4
+ 00A5 236 G$P2_5$0$0 == 0x00a5
+ 00A5 237 _P2_5 = 0x00a5
+ 00A6 238 G$P2_6$0$0 == 0x00a6
+ 00A6 239 _P2_6 = 0x00a6
+ 00A7 240 G$P2_7$0$0 == 0x00a7
+ 00A7 241 _P2_7 = 0x00a7
+ 00A8 242 G$EX0$0$0 == 0x00a8
+ 00A8 243 _EX0 = 0x00a8
+ 00A9 244 G$ET0$0$0 == 0x00a9
+ 00A9 245 _ET0 = 0x00a9
+ 00AA 246 G$EX1$0$0 == 0x00aa
+ 00AA 247 _EX1 = 0x00aa
+ 00AB 248 G$ET1$0$0 == 0x00ab
+ 00AB 249 _ET1 = 0x00ab
+ 00AC 250 G$ES$0$0 == 0x00ac
+ 00AC 251 _ES = 0x00ac
+ 00AF 252 G$EA$0$0 == 0x00af
+ 00AF 253 _EA = 0x00af
+ 00B0 254 G$P3_0$0$0 == 0x00b0
+ 00B0 255 _P3_0 = 0x00b0
+ 00B1 256 G$P3_1$0$0 == 0x00b1
+ 00B1 257 _P3_1 = 0x00b1
+ 00B2 258 G$P3_2$0$0 == 0x00b2
+ 00B2 259 _P3_2 = 0x00b2
+ 00B3 260 G$P3_3$0$0 == 0x00b3
+ 00B3 261 _P3_3 = 0x00b3
+ 00B4 262 G$P3_4$0$0 == 0x00b4
+ 00B4 263 _P3_4 = 0x00b4
+ 00B5 264 G$P3_5$0$0 == 0x00b5
+ 00B5 265 _P3_5 = 0x00b5
+ 00B6 266 G$P3_6$0$0 == 0x00b6
+ 00B6 267 _P3_6 = 0x00b6
+ 00B7 268 G$P3_7$0$0 == 0x00b7
+ 00B7 269 _P3_7 = 0x00b7
+ 00B0 270 G$RXD$0$0 == 0x00b0
+ 00B0 271 _RXD = 0x00b0
+ 00B1 272 G$TXD$0$0 == 0x00b1
+ 00B1 273 _TXD = 0x00b1
+ 00B2 274 G$INT0$0$0 == 0x00b2
+ 00B2 275 _INT0 = 0x00b2
+ 00B3 276 G$INT1$0$0 == 0x00b3
+ 00B3 277 _INT1 = 0x00b3
+ 00B4 278 G$T0$0$0 == 0x00b4
+ 00B4 279 _T0 = 0x00b4
+ 00B5 280 G$T1$0$0 == 0x00b5
+ 00B5 281 _T1 = 0x00b5
+ 00B6 282 G$WR$0$0 == 0x00b6
+ 00B6 283 _WR = 0x00b6
+ 00B7 284 G$RD$0$0 == 0x00b7
+ 00B7 285 _RD = 0x00b7
+ 00B8 286 G$PX0$0$0 == 0x00b8
+ 00B8 287 _PX0 = 0x00b8
+ 00B9 288 G$PT0$0$0 == 0x00b9
+ 00B9 289 _PT0 = 0x00b9
+ 00BA 290 G$PX1$0$0 == 0x00ba
+ 00BA 291 _PX1 = 0x00ba
+ 00BB 292 G$PT1$0$0 == 0x00bb
+ 00BB 293 _PT1 = 0x00bb
+ 00BC 294 G$PS$0$0 == 0x00bc
+ 00BC 295 _PS = 0x00bc
+ 00D0 296 G$P$0$0 == 0x00d0
+ 00D0 297 _P = 0x00d0
+ 00D1 298 G$FL$0$0 == 0x00d1
+ 00D1 299 _FL = 0x00d1
+ 00D2 300 G$OV$0$0 == 0x00d2
+ 00D2 301 _OV = 0x00d2
+ 00D3 302 G$RS0$0$0 == 0x00d3
+ 00D3 303 _RS0 = 0x00d3
+ 00D4 304 G$RS1$0$0 == 0x00d4
+ 00D4 305 _RS1 = 0x00d4
+ 00D5 306 G$F0$0$0 == 0x00d5
+ 00D5 307 _F0 = 0x00d5
+ 00D6 308 G$AC$0$0 == 0x00d6
+ 00D6 309 _AC = 0x00d6
+ 00D7 310 G$CY$0$0 == 0x00d7
+ 00D7 311 _CY = 0x00d7
+ 312 ;--------------------------------------------------------
+ 313 ; overlayable register banks
+ 314 ;--------------------------------------------------------
+ 315 .area REG_BANK_0 (REL,OVR,DATA)
+ 0000 316 .ds 8
+ 317 ;--------------------------------------------------------
+ 318 ; internal ram data
+ 319 ;--------------------------------------------------------
+ 320 .area DSEG (DATA)
+ 321 ;--------------------------------------------------------
+ 322 ; overlayable items in internal ram
+ 323 ;--------------------------------------------------------
+ 324 .area OSEG (OVR,DATA)
+ 325 ;--------------------------------------------------------
+ 326 ; Stack segment in internal ram
+ 327 ;--------------------------------------------------------
+ 328 .area SSEG (DATA)
+ 0000 329 __start__stack:
+ 0000 330 .ds 1
+ 331
+ 332 ;--------------------------------------------------------
+ 333 ; indirectly addressable internal ram data
+ 334 ;--------------------------------------------------------
+ 335 .area ISEG (DATA)
+ 336 ;--------------------------------------------------------
+ 337 ; absolute internal ram data
+ 338 ;--------------------------------------------------------
+ 339 .area IABS (ABS,DATA)
+ 340 .area IABS (ABS,DATA)
+ 341 ;--------------------------------------------------------
+ 342 ; bit data
+ 343 ;--------------------------------------------------------
+ 344 .area BSEG (BIT)
+ 345 ;--------------------------------------------------------
+ 346 ; paged external ram data
+ 347 ;--------------------------------------------------------
+ 348 .area PSEG (PAG,XDATA)
+ 349 ;--------------------------------------------------------
+ 350 ; external ram data
+ 351 ;--------------------------------------------------------
+ 352 .area XSEG (XDATA)
+ 353 ;--------------------------------------------------------
+ 354 ; absolute external ram data
+ 355 ;--------------------------------------------------------
+ 356 .area XABS (ABS,XDATA)
+ 357 ;--------------------------------------------------------
+ 358 ; external initialized ram data
+ 359 ;--------------------------------------------------------
+ 360 .area XISEG (XDATA)
+ 361 .area HOME (CODE)
+ 362 .area GSINIT0 (CODE)
+ 363 .area GSINIT1 (CODE)
+ 364 .area GSINIT2 (CODE)
+ 365 .area GSINIT3 (CODE)
+ 366 .area GSINIT4 (CODE)
+ 367 .area GSINIT5 (CODE)
+ 368 .area GSINIT (CODE)
+ 369 .area GSFINAL (CODE)
+ 370 .area CSEG (CODE)
+ 371 ;--------------------------------------------------------
+ 372 ; interrupt vector
+ 373 ;--------------------------------------------------------
+ 374 .area HOME (CODE)
+ 0000 375 __interrupt_vect:
+ 0000 02s00r00 376 ljmp __sdcc_gsinit_startup
+ 377 ;--------------------------------------------------------
+ 378 ; global & static initialisations
+ 379 ;--------------------------------------------------------
+ 380 .area HOME (CODE)
+ 381 .area GSINIT (CODE)
+ 382 .area GSFINAL (CODE)
+ 383 .area GSINIT (CODE)
+ 384 .globl __sdcc_gsinit_startup
+ 385 .globl __sdcc_program_startup
+ 386 .globl __start__stack
+ 387 .globl __mcs51_genXINIT
+ 388 .globl __mcs51_genXRAMCLEAR
+ 389 .globl __mcs51_genRAMCLEAR
+ 390 .area GSFINAL (CODE)
+ 0000 02s00r03 391 ljmp __sdcc_program_startup
+ 392 ;--------------------------------------------------------
+ 393 ; Home
+ 394 ;--------------------------------------------------------
+ 395 .area HOME (CODE)
+ 396 .area HOME (CODE)
+ 0003 397 __sdcc_program_startup:
+ 0003 12s00r00 398 lcall _main
+ 399 ; return from main will lock up
+ 0006 80 FE 400 sjmp .
+ 401 ;--------------------------------------------------------
+ 402 ; code
+ 403 ;--------------------------------------------------------
+ 404 .area CSEG (CODE)
+ 405 ;------------------------------------------------------------
+ 406 ;Allocation info for local variables in function 'main'
+ 407 ;------------------------------------------------------------
+ 408 ;i Allocated to registers r2 r3
+ 409 ;------------------------------------------------------------
+ 0000 410 G$main$0$0 ==.
+ 0000 411 C$ledmatrix.c$27$0$0 ==.
+ 412 ; ledmatrix.c:27: int main()
+ 413 ; -----------------------------------------
+ 414 ; function main
+ 415 ; -----------------------------------------
+ 0000 416 _main:
+ 0002 417 ar2 = 0x02
+ 0003 418 ar3 = 0x03
+ 0004 419 ar4 = 0x04
+ 0005 420 ar5 = 0x05
+ 0006 421 ar6 = 0x06
+ 0007 422 ar7 = 0x07
+ 0000 423 ar0 = 0x00
+ 0001 424 ar1 = 0x01
+ 0000 425 C$ledmatrix.c$30$1$1 ==.
+ 426 ; ledmatrix.c:30: while(1) {
+ 0000 427 00102$:
+ 0000 428 C$ledmatrix.c$31$2$2 ==.
+ 429 ; ledmatrix.c:31: for(i=0; i<8; i++) {
+ 0000 7A 00 430 mov r2,#0x00
+ 0002 7B 00 431 mov r3,#0x00
+ 0004 432 00104$:
+ 0004 C3 433 clr c
+ 0005 EA 434 mov a,r2
+ 0006 94 08 435 subb a,#0x08
+ 0008 EB 436 mov a,r3
+ 0009 64 80 437 xrl a,#0x80
+ 000B 94 80 438 subb a,#0x80
+ 000D 50 F1 439 jnc 00102$
+ 000F 440 C$ledmatrix.c$32$3$3 ==.
+ 441 ; ledmatrix.c:32: P1 = 0xff;
+ 000F 75 90 FF 442 mov _P1,#0xFF
+ 0012 443 C$ledmatrix.c$33$3$3 ==.
+ 444 ; ledmatrix.c:33: P0 = image[i];
+ 0012 EA 445 mov a,r2
+ 0013 24r00 446 add a,#_image
+ 0015 F5 82 447 mov dpl,a
+ 0017 EB 448 mov a,r3
+ 0018 34s00 449 addc a,#(_image >> 8)
+ 001A F5 83 450 mov dph,a
+ 001C E4 451 clr a
+ 001D 93 452 movc a,@a+dptr
+ 001E F5 80 453 mov _P0,a
+ 0020 454 C$ledmatrix.c$34$3$3 ==.
+ 455 ; ledmatrix.c:34: P1 = (1 << i) ^ 255;
+ 0020 8A F0 456 mov b,r2
+ 0022 05 F0 457 inc b
+ 0024 7C 01 458 mov r4,#0x01
+ 0026 7D 00 459 mov r5,#0x00
+ 0028 80 06 460 sjmp 00115$
+ 002A 461 00114$:
+ 002A EC 462 mov a,r4
+ 002B 2C 463 add a,r4
+ 002C FC 464 mov r4,a
+ 002D ED 465 mov a,r5
+ 002E 33 466 rlc a
+ 002F FD 467 mov r5,a
+ 0030 468 00115$:
+ 0030 D5 F0 F7 469 djnz b,00114$
+ 0033 74 FF 470 mov a,#0xFF
+ 0035 6C 471 xrl a,r4
+ 0036 F5 90 472 mov _P1,a
+ 0038 473 C$ledmatrix.c$31$2$2 ==.
+ 474 ; ledmatrix.c:31: for(i=0; i<8; i++) {
+ 0038 0A 475 inc r2
+ 0039 BA 00 C8 476 cjne r2,#0x00,00104$
+ 003C 0B 477 inc r3
+ 003D 478 C$ledmatrix.c$37$1$1 ==.
+ 003D 479 XG$main$0$0 ==.
+ 003D 80 C5 480 sjmp 00104$
+ 481 .area CSEG (CODE)
+ 482 .area CONST (CODE)
+ 0000 483 Fledmatrix$image$0$0 == .
+ 0000 484 _image:
+ 0000 B1 485 .db #0xB1
+ 0001 9D 486 .db #0x9D
+ 0002 BD 487 .db #0xBD
+ 0003 B1 488 .db #0xB1
+ 0004 B7 489 .db #0xB7
+ 0005 B7 490 .db #0xB7
+ 0006 11 491 .db #0x11
+ 0007 FF 492 .db #0xFF
+ 493 .area XINIT (CODE)
+ 494 .area CABS (ABS,CODE)
diff --git a/demo/ledmatrix.m5ihib b/demo/ledmatrix.m5ihib
new file mode 100644
index 0000000..40d686b
--- /dev/null
+++ b/demo/ledmatrix.m5ihib
@@ -0,0 +1,599 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!--
+ This is MCU 8051 IDE hibernation data file.
+ It does not contain program code, only data.
+
+ PLEASE DO NOT EDIT THIS FILE MANUALY, BECAUSE
+ BAD FORMATING OF THIS FILE WILL LEAD MCU 8051 IDE TO CRASH !
+-->
+<!DOCTYPE m5ihib [
+
+ <!-- ROOT ELEMENT -->
+ <!ELEMENT m5ihib (currentstate, subprograms, stepback)>
+ <!-- Root element Parameters:
+ version - File version
+ datetime - Date and time of creation
+ source_file - Souce code compiled and loaded in simulator before hibernation
+ processor - Processor type
+ xdata - Size of External data memory
+ eeprom - Size of data EEPROM
+ md5 - MD5 hash of the source code file
+ -->
+ <!ATTLIST m5ihib
+ version CDATA #REQUIRED
+ datetime CDATA #REQUIRED
+ source_file CDATA #REQUIRED
+ processor CDATA #REQUIRED
+ xdata CDATA #REQUIRED
+ eeprom CDATA #REQUIRED
+ md5 CDATA #REQUIRED
+ >
+
+
+ <!-- Current state of MCU -->
+ <!ELEMENT currentstate (iram, eram, xram, eeprom, sfr, special)>
+
+ <!-- Internal data memory in decimal -->
+ <!ELEMENT iram (#PCDATA)>
+
+ <!-- Expanded data memory in decimal -->
+ <!ELEMENT eram (#PCDATA)>
+
+ <!-- External data memory in decimal -->
+ <!ELEMENT xram (#PCDATA)>
+
+ <!-- Data EEPROM in decimal -->
+ <!ELEMENT eeprom (#PCDATA)>
+
+ <!-- Special function registers -->
+ <!ELEMENT sfr (addresses, values)>
+
+ <!-- SFR decimal addresses in the same order as in tag values -->
+ <!ELEMENT addresses (#PCDATA)>
+
+ <!-- SFR decimal values in the same order as in tag values -->
+ <!ELEMENT values (#PCDATA)>
+
+ <!-- Special engine variables -->
+ <!ELEMENT special (#PCDATA)>
+
+
+ <!-- Content of list of active interrupts -->
+ <!ELEMENT subprograms (sub)*>
+ <!-- Parameters of tag "subprograms":
+ count - Number of recorded subprograms
+ -->
+ <!ATTLIST subprograms
+ count CDATA #REQUIRED
+ >
+
+ <!-- Active interrupt -->
+ <!ELEMENT sub EMPTY>
+ <!-- Parameters of tag "sub":
+ source - Source address
+ target - Target address
+ type - Type
+ -->
+ <!ATTLIST sub
+ source CDATA #REQUIRED
+ target CDATA #REQUIRED
+ type CDATA #REQUIRED
+ >
+
+
+ <!-- Stack for stepback function (backward stepping) -->
+ <!ELEMENT stepback (step)*>
+ <!-- Parameters of tag "stepback":
+ stacklength - Number of recorded program steps
+ -->
+ <!ATTLIST stepback
+ stacklength CDATA #REQUIRED
+ >
+
+ <!-- One program step -->
+ <!ELEMENT step (spec, normal)>
+
+ <!-- Special engine variables -->
+ <!ELEMENT spec (#PCDATA)>
+
+ <!-- Ordinary registers -->
+ <!ELEMENT normal (reg)*>
+
+ <!-- One register -->
+ <!ELEMENT reg EMPTY>
+ <!-- Parameters of tag "reg":
+ type - Memory type (E == ERAM; I == IDATA; X == XDATA; S == SFR)
+ addr - Register address
+ val - Previous register value
+ -->
+ <!ATTLIST reg
+ type CDATA #REQUIRED
+ addr CDATA #REQUIRED
+ val CDATA #REQUIRED
+ >
+
+]>
+<m5ihib
+ version="1.0"
+ datetime="02/27/09 04:45:11"
+ source_file="ledmatrix.c"
+ processor="AT89C51"
+ xdata="2809"
+ eeprom="0"
+ md5="517133F895352F3918C3E1250EA990A5">
+ <currentstate>
+ <iram>
+ 0 0 0 0 0 0 0 0
+ 6 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ </iram>
+ <eram>
+
+ </eram>
+ <xram>
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0
+ </xram>
+ <eeprom>
+
+ </eeprom>
+ <sfr>
+ <addresses>
+ 152 135 153 136 137 138 139
+ 140 176 141 240 160 224 144
+ 208 128 129 130 409 131 184
+ 168
+ </addresses>
+ <values>
+ 0 0 247 0 0 0 0
+ 0 255 0 0 255 0 255
+ 0 255 9 0 120 0 0
+ 0
+ </values>
+ </sfr>
+ <special>
+ 0 {255 255 255 255 0} 100 0 {} 0 0 0 0 415 415 {} 0 0 0 0 0 0 0 0 2
+ </special>
+ </currentstate>
+ <subprograms count="1">
+ <sub source="6" target="100" type="0"/>
+ </subprograms>
+ <stepback stacklength="10">
+ <step>
+ <spec>
+ 0 {255 255 255 255 0} 61 0 {} 0 0 0 0 401 401 {} 0 0 0 0 0 0 0 0 1
+ </spec><normal>
+ <reg type="I" addr="0" val="0"/>
+ </normal>
+ </step>
+ <step>
+ <spec>
+ 0 {255 255 255 255 0} 63 0 {} 0 0 0 0 402 402 {} 0 0 0 0 0 0 0 0 1
+ </spec><normal>
+ <reg type="S" addr="224" val="0"/>
+ <reg type="S" addr="208" val="0"/>
+ </normal>
+ </step>
+ <step>
+ <spec>
+ 0 {255 255 255 255 0} 64 0 {} 0 0 0 0 403 403 {} 0 0 0 0 0 0 0 0 1
+ </spec><normal>
+ <reg type="S" addr="224" val="0"/>
+ <reg type="S" addr="208" val="0"/>
+ </normal>
+ </step>
+ <step>
+ <spec>
+ 0 {255 255 255 255 0} 66 0 {} 0 0 0 0 404 404 {} 0 0 0 0 0 0 0 0 2
+ </spec><normal>
+ </normal>
+ </step>
+ <step>
+ <spec>
+ 0 {255 255 255 255 0} 78 0 {} 0 0 0 0 406 406 {} 0 0 0 0 0 0 0 0 1
+ </spec><normal>
+ <reg type="I" addr="0" val="0"/>
+ </normal>
+ </step>
+ <step>
+ <spec>
+ 0 {255 255 255 255 0} 80 0 {} 0 0 0 0 407 407 {} 0 0 0 0 0 0 0 0 1
+ </spec><normal>
+ <reg type="S" addr="224" val="0"/>
+ <reg type="S" addr="208" val="0"/>
+ </normal>
+ </step>
+ <step>
+ <spec>
+ 0 {255 255 255 255 0} 81 0 {} 0 0 0 0 408 408 {} 0 0 0 0 0 0 0 0 1
+ </spec><normal>
+ <reg type="S" addr="224" val="0"/>
+ <reg type="S" addr="208" val="0"/>
+ </normal>
+ </step>
+ <step>
+ <spec>
+ 0 {255 255 255 255 0} 83 0 {} 0 0 0 0 409 409 {} 0 0 0 0 0 0 0 0 2
+ </spec><normal>
+ </normal>
+ </step>
+ <step>
+ <spec>
+ 0 {255 255 255 255 0} 97 0 {} 0 0 0 0 411 411 {} 0 0 0 0 0 0 0 0 2
+ </spec><normal>
+ </normal>
+ </step>
+ <step>
+ <spec>
+ 2 {255 255 255 255 0} 3 0 {} 0 0 0 0 413 413 {} 0 0 0 0 0 0 0 0 2
+ </spec><normal>
+ <reg type="S" addr="129" val="7"/>
+ <reg type="I" addr="8" val="0"/>
+ <reg type="I" addr="9" val="0"/>
+ </normal>
+ </step>
+ </stepback>
+</m5ihib>
diff --git a/demo/ledmatrix.map b/demo/ledmatrix.map
new file mode 100644
index 0000000..0fdab15
--- /dev/null
+++ b/demo/ledmatrix.map
@@ -0,0 +1,454 @@
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+CABS 0000 0000 = 0. bytes (ABS,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:FFFFFF00 s_BSEG
+ 0C:0000 l_BIT_BANK
+ 0C:0000 l_BSEG
+ 0C:0000 l_BSEG_BYTES
+ 0C:0000 l_CABS
+ 0C:0000 l_GSINIT
+ 0C:0000 l_GSINIT1
+ 0C:0000 l_GSINIT5
+ 0C:0000 l_IABS
+ 0C:0000 l_ISEG
+ 0C:0000 l_OSEG
+ 0C:0000 l_PSEG
+ 0C:0000 l_REG_BANK_1
+ 0C:0000 l_REG_BANK_2
+ 0C:0000 l_REG_BANK_3
+ 0C:0000 l_RSEG
+ 0C:0000 l_XABS
+ 0C:0000 l_XINIT
+ 0C:0000 l_XISEG
+ 0C:0000 l_XSEG
+ 0C:0000 l__CODE
+ 0C:0000 s_BSEG_BYTES
+ 0C:0000 s_CABS
+ 0C:0000 s_DSEG
+ 0C:0000 s_HOME
+ 0C:0000 s_IABS
+ 0C:0000 s_ISEG
+ 0C:0000 s_PSEG
+ 0C:0000 s_REG_BANK_0
+ 0C:0000 s_XABS
+ 0C:0000 s_XISEG
+ 0C:0000 s_XSEG
+ 0C:0003 l_GSFINAL
+ 0C:0003 l_GSINIT0
+ 0C:0008 l_CONST
+ 0C:0008 l_HOME
+ 0C:0008 l_REG_BANK_0
+ 0C:0008 s_GSINIT0
+ 0C:0008 s_REG_BANK_1
+ 0C:0008 s_RSEG
+ 0C:0008 s_SSEG
+ 0C:000A l_GSINIT2
+ 0C:000B s_GSINIT1
+ 0C:000B s_GSINIT2
+ 0C:0010 s_REG_BANK_2
+ 0C:0015 s_GSINIT3
+ 0C:0018 s_BIT_BANK
+ 0C:0018 s_OSEG
+ 0C:0018 s_REG_BANK_3
+ 0C:0020 s__CODE
+ 0C:0022 l_GSINIT3
+ 0C:002A l_GSINIT4
+ 0C:0037 s_GSINIT4
+ 0C:0043 l_CSEG
+ 0C:0061 s_GSFINAL
+ 0C:0061 s_GSINIT
+ 0C:0061 s_GSINIT5
+ 0C:0064 s_CSEG
+ 0C:0080 l_DSEG
+ 0C:00A7 s_CONST
+ 0C:00AF s_XINIT
+ 0C:00F8 l_SSEG
+ 0C:0100 l_IRAM
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+. .ABS. 0000 0000 = 0. bytes (ABS,CON)
+
+ Value Global
+ -------- --------------------------------
+ 0080 G$P0$0$0
+ 0080 G$P0_0$0$0
+ 0080 _P0
+ 0080 _P0_0
+ 0081 G$P0_1$0$0
+ 0081 G$SP$0$0
+ 0081 _P0_1
+ 0081 _SP
+ 0082 G$DPL$0$0
+ 0082 G$P0_2$0$0
+ 0082 _DPL
+ 0082 _P0_2
+ 0083 G$DPH$0$0
+ 0083 G$P0_3$0$0
+ 0083 _DPH
+ 0083 _P0_3
+ 0084 G$P0_4$0$0
+ 0084 _P0_4
+ 0085 G$P0_5$0$0
+ 0085 _P0_5
+ 0086 G$P0_6$0$0
+ 0086 _P0_6
+ 0087 G$P0_7$0$0
+ 0087 G$PCON$0$0
+ 0087 _P0_7
+ 0087 _PCON
+ 0088 G$IT0$0$0
+ 0088 G$TCON$0$0
+ 0088 _IT0
+ 0088 _TCON
+ 0089 G$IE0$0$0
+ 0089 G$TMOD$0$0
+ 0089 _IE0
+ 0089 _TMOD
+ 008A G$IT1$0$0
+ 008A G$TL0$0$0
+ 008A _IT1
+ 008A _TL0
+ 008B G$IE1$0$0
+ 008B G$TL1$0$0
+ 008B _IE1
+ 008B _TL1
+ 008C G$TH0$0$0
+ 008C G$TR0$0$0
+ 008C _TH0
+ 008C _TR0
+ 008D G$TF0$0$0
+ 008D G$TH1$0$0
+ 008D _TF0
+ 008D _TH1
+ 008E G$TR1$0$0
+ 008E _TR1
+ 008F G$TF1$0$0
+ 008F _TF1
+ 0090 G$P1$0$0
+ 0090 G$P1_0$0$0
+ 0090 _P1
+ 0090 _P1_0
+ 0091 G$P1_1$0$0
+ 0091 _P1_1
+ 0092 G$P1_2$0$0
+ 0092 _P1_2
+ 0093 G$P1_3$0$0
+ 0093 _P1_3
+ 0094 G$P1_4$0$0
+ 0094 _P1_4
+ 0095 G$P1_5$0$0
+ 0095 _P1_5
+ 0096 G$P1_6$0$0
+ 0096 _P1_6
+ 0097 G$P1_7$0$0
+ 0097 _P1_7
+ 0098 G$RI$0$0
+ 0098 G$SCON$0$0
+ 0098 _RI
+ 0098 _SCON
+ 0099 G$SBUF$0$0
+ 0099 G$TI$0$0
+ 0099 _SBUF
+ 0099 _TI
+ 009A G$RB8$0$0
+ 009A _RB8
+ 009B G$TB8$0$0
+ 009B _TB8
+ 009C G$REN$0$0
+ 009C _REN
+ 009D G$SM2$0$0
+ 009D _SM2
+ 009E G$SM1$0$0
+ 009E _SM1
+ 009F G$SM0$0$0
+ 009F _SM0
+ 00A0 G$P2$0$0
+ 00A0 G$P2_0$0$0
+ 00A0 _P2
+ 00A0 _P2_0
+ 00A0 __XPAGE
+ 00A1 G$P2_1$0$0
+ 00A1 _P2_1
+ 00A2 G$P2_2$0$0
+ 00A2 _P2_2
+ 00A3 G$P2_3$0$0
+ 00A3 _P2_3
+ 00A4 G$P2_4$0$0
+ 00A4 _P2_4
+ 00A5 G$P2_5$0$0
+ 00A5 _P2_5
+ 00A6 G$P2_6$0$0
+ 00A6 _P2_6
+ 00A7 G$P2_7$0$0
+ 00A7 _P2_7
+ 00A8 G$EX0$0$0
+ 00A8 G$IE$0$0
+ 00A8 _EX0
+ 00A8 _IE
+ 00A9 G$ET0$0$0
+ 00A9 _ET0
+ 00AA G$EX1$0$0
+ 00AA _EX1
+ 00AB G$ET1$0$0
+ 00AB _ET1
+ 00AC G$ES$0$0
+ 00AC _ES
+ 00AF G$EA$0$0
+ 00AF _EA
+ 00B0 G$P3$0$0
+ 00B0 G$P3_0$0$0
+ 00B0 G$RXD$0$0
+ 00B0 _P3
+ 00B0 _P3_0
+ 00B0 _RXD
+ 00B1 G$P3_1$0$0
+ 00B1 G$TXD$0$0
+ 00B1 _P3_1
+ 00B1 _TXD
+ 00B2 G$INT0$0$0
+ 00B2 G$P3_2$0$0
+ 00B2 _INT0
+ 00B2 _P3_2
+ 00B3 G$INT1$0$0
+ 00B3 G$P3_3$0$0
+ 00B3 _INT1
+ 00B3 _P3_3
+ 00B4 G$P3_4$0$0
+ 00B4 G$T0$0$0
+ 00B4 _P3_4
+ 00B4 _T0
+ 00B5 G$P3_5$0$0
+ 00B5 G$T1$0$0
+ 00B5 _P3_5
+ 00B5 _T1
+ 00B6 G$P3_6$0$0
+ 00B6 G$WR$0$0
+ 00B6 _P3_6
+ 00B6 _WR
+ 00B7 G$P3_7$0$0
+ 00B7 G$RD$0$0
+ 00B7 _P3_7
+ 00B7 _RD
+ 00B8 G$IP$0$0
+ 00B8 G$PX0$0$0
+ 00B8 _IP
+ 00B8 _PX0
+ 00B9 G$PT0$0$0
+ 00B9 _PT0
+ 00BA G$PX1$0$0
+ 00BA _PX1
+ 00BB G$PT1$0$0
+ 00BB _PT1
+ 00BC G$PS$0$0
+ 00BC _PS
+ 00D0 G$P$0$0
+ 00D0 G$PSW$0$0
+ 00D0 _P
+ 00D0 _PSW
+ 00D1 G$FL$0$0
+ 00D1 _FL
+ 00D2 G$OV$0$0
+ 00D2 _OV
+ 00D3 G$RS0$0$0
+ 00D3 _RS0
+ 00D4 G$RS1$0$0
+ 00D4 _RS1
+ 00D5 G$F0$0$0
+ 00D5 _F0
+ 00D6 G$AC$0$0
+ 00D6 _AC
+ 00D7 G$CY$0$0
+ 00D7 _CY
+ 00E0 G$A$0$0
+ 00E0 G$ACC$0$0
+ 00E0 _A
+ 00E0 _ACC
+ 00F0 G$B$0$0
+ 00F0 _B
+
+
+
+
+
+
+
+
+
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+SSEG 0008 00F8 = 248. bytes (REL,OVR)
+
+ Value Global
+ -------- --------------------------------
+ 0008 __start__stack
+
+
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+HOME 0000 0008 = 8. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0000 A$ledmatrix$376
+ 0C:0003 A$ledmatrix$398
+ 0C:0003 __sdcc_program_startup
+ 0C:0006 A$ledmatrix$400
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT0 0008 0003 = 3. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0008 __sdcc_gsinit_startup
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT3 0015 0022 = 34. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0015 __mcs51_genXINIT
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSINIT4 0037 002A = 42. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0037 __mcs51_genRAMCLEAR
+ 0C:003D __mcs51_genXRAMCLEAR
+
+
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+GSFINAL 0061 0003 = 3. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0061 A$ledmatrix$391
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+CSEG 0064 0043 = 67. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:0064 A$ledmatrix$430
+ 0C:0064 C$ledmatrix.c$27$0$0
+ 0C:0064 C$ledmatrix.c$30$1$1
+ 0C:0064 G$main$0$0
+ 0C:0064 _main
+ 0C:0066 A$ledmatrix$431
+ 0C:0068 A$ledmatrix$433
+ 0C:0069 A$ledmatrix$434
+ 0C:006A A$ledmatrix$435
+ 0C:006C A$ledmatrix$436
+ 0C:006D A$ledmatrix$437
+ 0C:006F A$ledmatrix$438
+ 0C:0071 A$ledmatrix$439
+ 0C:0073 A$ledmatrix$442
+ 0C:0073 C$ledmatrix.c$32$3$3
+ 0C:0076 A$ledmatrix$445
+ 0C:0076 C$ledmatrix.c$33$3$3
+ 0C:0077 A$ledmatrix$446
+ 0C:0079 A$ledmatrix$447
+ 0C:007B A$ledmatrix$448
+ 0C:007C A$ledmatrix$449
+ 0C:007E A$ledmatrix$450
+ 0C:0080 A$ledmatrix$451
+ 0C:0081 A$ledmatrix$452
+ 0C:0082 A$ledmatrix$453
+ 0C:0084 A$ledmatrix$456
+ 0C:0084 C$ledmatrix.c$34$3$3
+ 0C:0086 A$ledmatrix$457
+ 0C:0088 A$ledmatrix$458
+ 0C:008A A$ledmatrix$459
+ 0C:008C A$ledmatrix$460
+ 0C:008E A$ledmatrix$462
+ 0C:008F A$ledmatrix$463
+ 0C:0090 A$ledmatrix$464
+ 0C:0091 A$ledmatrix$465
+ 0C:0092 A$ledmatrix$466
+ 0C:0093 A$ledmatrix$467
+ 0C:0094 A$ledmatrix$469
+ 0C:0097 A$ledmatrix$470
+ 0C:0099 A$ledmatrix$471
+ 0C:009A A$ledmatrix$472
+ 0C:009C A$ledmatrix$475
+ 0C:009C C$ledmatrix.c$31$2$2
+ 0C:009D A$ledmatrix$476
+ 0C:00A0 A$ledmatrix$477
+ 0C:00A1 A$ledmatrix$480
+ 0C:00A1 C$ledmatrix.c$37$1$1
+ 0C:00A1 XG$main$0$0
+ 0C:00A3 __sdcc_external_startup
+
+Hexadecimal
+
+Area Addr Size Decimal Bytes (Attributes)
+-------------------------------- ---- ---- ------- ----- ------------
+CONST 00A7 0008 = 8. bytes (REL,CON,CODE)
+
+ Value Global
+ -------- --------------------------------
+ 0C:00A7 Fledmatrix$image$0$0
+
+ ASxxxx Linker V01.75 + NoICE + SDCC Feb 1999, page 1.
+
+Files Linked [ module(s) ]
+
+ledmatrix.rel
+
+Libraries Linked [ object file ]
+
+/usr/share/sdcc/lib/small/mcs51.lib [ crtclear.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtxinit.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtxclear.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtpagesfr.rel ]
+/usr/share/sdcc/lib/small/mcs51.lib [ crtstart.rel ]
+/usr/share/sdcc/lib/small/libsdcc.lib [ _startup.rel ]
+
+ ASxxxx Linker V01.75 + NoICE + SDCC Feb 1999, page 2.
+
+User Base Address Definitions
+
+HOME = 0x0000
+ISEG = 0x0000
+BSEG = 0x0000
+
+ \ No newline at end of file
diff --git a/demo/ledmatrix.mem b/demo/ledmatrix.mem
new file mode 100644
index 0000000..0275aa5
--- /dev/null
+++ b/demo/ledmatrix.mem
@@ -0,0 +1,28 @@
+Internal RAM layout:
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+0x00:|0|0|0|0|0|0|0|0|S|S|S|S|S|S|S|S|
+0x10:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x20:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x30:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x40:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x50:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x60:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x70:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x80:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0x90:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xa0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xb0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xc0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xd0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xe0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0xf0:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
+0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute
+
+Stack starts at: 0x08 (sp set to 0x07) with 248 bytes available.
+
+Other memory:
+ Name Start End Size Max
+ ---------------- -------- -------- -------- --------
+ PAGED EXT. RAM 0 0
+ EXTERNAL RAM 0 0
+ ROM/EPROM/FLASH 0x0000 0x00ae 175 8192
diff --git a/demo/ledmatrix.rel b/demo/ledmatrix.rel
new file mode 100644
index 0000000..e4cdd26
--- /dev/null
+++ b/demo/ledmatrix.rel
@@ -0,0 +1,328 @@
+;!FILE ledmatrix.asm
+XH
+H 1A areas FD global symbols
+M ledmatrix
+O -mmcs51 --model-small
+S G$EX0$0$0 Def00A8
+S G$IT0$0$0 Def0088
+S G$TH1$0$0 Def008D
+S _P1 Def0090
+S _A Def00E0
+S G$RXD$0$0 Def00B0
+S G$EX1$0$0 Def00AA
+S G$TB8$0$0 Def009B
+S G$IT1$0$0 Def008A
+S G$IE$0$0 Def00A8
+S _P2 Def00A0
+S _B Def00F0
+S _SP Def0081
+S _P3 Def00B0
+S _PS Def00BC
+S G$TXD$0$0 Def00B1
+S G$SM0$0$0 Def009F
+S G$TL0$0$0 Def008A
+S _T0 Def00B4
+S G$SM1$0$0 Def009E
+S G$TL1$0$0 Def008B
+S _T1 Def00B5
+S _OV Def00D2
+S G$FL$0$0 Def00D1
+S G$SM2$0$0 Def009D
+S _ACC Def00E0
+S __mcs51_genRAMCLEAR Ref0000
+S G$PT0$0$0 Def00B9
+S G$RS0$0$0 Def00D3
+S G$PT1$0$0 Def00BB
+S _WR Def00B6
+S G$F0$0$0 Def00D5
+S G$RS1$0$0 Def00D4
+S G$RD$0$0 Def00B7
+S G$TR0$0$0 Def008C
+S G$TR1$0$0 Def008E
+S G$PX0$0$0 Def00B8
+S G$ES$0$0 Def00AC
+S G$PX1$0$0 Def00BA
+S G$IP$0$0 Def00B8
+S G$PSW$0$0 Def00D0
+S G$RI$0$0 Def0098
+S _P0_0 Def0080
+S G$CY$0$0 Def00D7
+S _PCON Def0087
+S _SBUF Def0099
+S _P0_1 Def0081
+S _P1_0 Def0090
+S _P Def00D0
+S G$TI$0$0 Def0099
+S _P0_2 Def0082
+S _P1_1 Def0091
+S _P2_0 Def00A0
+S _P0_3 Def0083
+S _P1_2 Def0092
+S _P2_1 Def00A1
+S _P3_0 Def00B0
+S _SCON Def0098
+S _P0_4 Def0084
+S _P1_3 Def0093
+S _P2_2 Def00A2
+S _P3_1 Def00B1
+S G$P0$0$0 Def0080
+S _TCON Def0088
+S _TMOD Def0089
+S _P0_5 Def0085
+S _P1_4 Def0094
+S _P2_3 Def00A3
+S _P3_2 Def00B2
+S G$A$0$0 Def00E0
+S G$P1$0$0 Def0090
+S _P0_6 Def0086
+S _P1_5 Def0095
+S _P2_4 Def00A4
+S _P3_3 Def00B3
+S G$B$0$0 Def00F0
+S G$P2$0$0 Def00A0
+S _P0_7 Def0087
+S _P1_6 Def0096
+S _P2_5 Def00A5
+S _P3_4 Def00B4
+S G$PS$0$0 Def00BC
+S G$P3$0$0 Def00B0
+S G$SP$0$0 Def0081
+S _P1_7 Def0097
+S _P2_6 Def00A6
+S _P3_5 Def00B5
+S G$T0$0$0 Def00B4
+S _P2_7 Def00A7
+S _P3_6 Def00B6
+S G$OV$0$0 Def00D2
+S G$T1$0$0 Def00B5
+S _P3_7 Def00B7
+S G$ACC$0$0 Def00E0
+S _INT0 Def00B2
+S _DPH Def0083
+S _INT1 Def00B3
+S G$WR$0$0 Def00B6
+S _IE0 Def0089
+S _IE1 Def008B
+S _DPL Def0082
+S G$P0_0$0$0 Def0080
+S G$P$0$0 Def00D0
+S G$P1_0$0$0 Def0090
+S G$P0_1$0$0 Def0081
+S G$SBUF$0$0 Def0099
+S G$PCON$0$0 Def0087
+S _AC Def00D6
+S G$P2_0$0$0 Def00A0
+S G$P1_1$0$0 Def0091
+S G$P0_2$0$0 Def0082
+S _REN Def009C
+S G$P3_0$0$0 Def00B0
+S G$P2_1$0$0 Def00A1
+S G$P1_2$0$0 Def0092
+S G$P0_3$0$0 Def0083
+S _EA Def00AF
+S G$P3_1$0$0 Def00B1
+S G$P2_2$0$0 Def00A2
+S G$P1_3$0$0 Def0093
+S G$P0_4$0$0 Def0084
+S G$SCON$0$0 Def0098
+S G$P3_2$0$0 Def00B2
+S G$P2_3$0$0 Def00A3
+S G$P1_4$0$0 Def0094
+S G$P0_5$0$0 Def0085
+S G$TMOD$0$0 Def0089
+S G$TCON$0$0 Def0088
+S G$P3_3$0$0 Def00B3
+S G$P2_4$0$0 Def00A4
+S G$P1_5$0$0 Def0095
+S G$P0_6$0$0 Def0086
+S _ET0 Def00A9
+S G$P3_4$0$0 Def00B4
+S G$P2_5$0$0 Def00A5
+S G$P1_6$0$0 Def0096
+S G$P0_7$0$0 Def0087
+S _TF0 Def008D
+S _ET1 Def00AB
+S G$P3_5$0$0 Def00B5
+S G$P2_6$0$0 Def00A6
+S G$P1_7$0$0 Def0097
+S _TF1 Def008F
+S G$P3_6$0$0 Def00B6
+S G$P2_7$0$0 Def00A7
+S _TH0 Def008C
+S _RB8 Def009A
+S __mcs51_genXINIT Ref0000
+S G$P3_7$0$0 Def00B7
+S _TH1 Def008D
+S _IT0 Def0088
+S _EX0 Def00A8
+S _IE Def00A8
+S _IT1 Def008A
+S _TB8 Def009B
+S _EX1 Def00AA
+S _RXD Def00B0
+S G$INT0$0$0 Def00B2
+S G$INT1$0$0 Def00B3
+S G$DPH$0$0 Def0083
+S _TL0 Def008A
+S _SM0 Def009F
+S _TXD Def00B1
+S _TL1 Def008B
+S _SM1 Def009E
+S G$IE0$0$0 Def0089
+S _SM2 Def009D
+S _FL Def00D1
+S G$IE1$0$0 Def008B
+S G$DPL$0$0 Def0082
+S _PT0 Def00B9
+S _PT1 Def00BB
+S _RS0 Def00D3
+S _TR0 Def008C
+S _RD Def00B7
+S _RS1 Def00D4
+S _F0 Def00D5
+S _TR1 Def008E
+S G$AC$0$0 Def00D6
+S _ES Def00AC
+S _PX0 Def00B8
+S G$REN$0$0 Def009C
+S _IP Def00B8
+S _PX1 Def00BA
+S G$EA$0$0 Def00AF
+S _PSW Def00D0
+S __sdcc_gsinit_startup Ref0000
+S _RI Def0098
+S _CY Def00D7
+S G$ET0$0$0 Def00A9
+S _TI Def0099
+S G$ET1$0$0 Def00AB
+S G$TF0$0$0 Def008D
+S G$TF1$0$0 Def008F
+S __mcs51_genXRAMCLEAR Ref0000
+S G$RB8$0$0 Def009A
+S G$TH0$0$0 Def008C
+S _P0 Def0080
+A _CODE size 0 flags 0 addr 0
+A RSEG size 0 flags 0 addr 0
+A REG_BANK_0 size 8 flags 4 addr 0
+A DSEG size 0 flags 0 addr 0
+A OSEG size 0 flags 4 addr 0
+A SSEG size 1 flags 0 addr 0
+S __start__stack Def0000
+A ISEG size 0 flags 0 addr 0
+A IABS size 0 flags 8 addr 0
+A BSEG size 0 flags 80 addr 0
+A PSEG size 0 flags 50 addr 0
+A XSEG size 0 flags 40 addr 0
+A XABS size 0 flags 48 addr 0
+A XISEG size 0 flags 40 addr 0
+A HOME size 8 flags 20 addr 0
+S A$ledmatrix$400 Def0006
+S A$ledmatrix$376 Def0000
+S A$ledmatrix$398 Def0003
+S __sdcc_program_startup Def0003
+A GSINIT0 size 0 flags 20 addr 0
+A GSINIT1 size 0 flags 20 addr 0
+A GSINIT2 size 0 flags 20 addr 0
+A GSINIT3 size 0 flags 20 addr 0
+A GSINIT4 size 0 flags 20 addr 0
+A GSINIT5 size 0 flags 20 addr 0
+A GSINIT size 0 flags 20 addr 0
+A GSFINAL size 3 flags 20 addr 0
+S A$ledmatrix$391 Def0000
+A CSEG size 3F flags 20 addr 0
+S _main Def0000
+S A$ledmatrix$430 Def0000
+S A$ledmatrix$431 Def0002
+S A$ledmatrix$450 Def001A
+S A$ledmatrix$460 Def0028
+S A$ledmatrix$451 Def001C
+S A$ledmatrix$442 Def000F
+S A$ledmatrix$433 Def0004
+S A$ledmatrix$470 Def0033
+S A$ledmatrix$452 Def001D
+S A$ledmatrix$434 Def0005
+S A$ledmatrix$480 Def003D
+S A$ledmatrix$471 Def0035
+S A$ledmatrix$462 Def002A
+S A$ledmatrix$453 Def001E
+S A$ledmatrix$435 Def0006
+S A$ledmatrix$472 Def0036
+S A$ledmatrix$463 Def002B
+S A$ledmatrix$445 Def0012
+S A$ledmatrix$436 Def0008
+S XG$main$0$0 Def003D
+S A$ledmatrix$464 Def002C
+S A$ledmatrix$446 Def0013
+S A$ledmatrix$437 Def0009
+S A$ledmatrix$465 Def002D
+S A$ledmatrix$456 Def0020
+S A$ledmatrix$447 Def0015
+S A$ledmatrix$438 Def000B
+S A$ledmatrix$475 Def0038
+S A$ledmatrix$466 Def002E
+S A$ledmatrix$457 Def0022
+S A$ledmatrix$448 Def0017
+S A$ledmatrix$439 Def000D
+S C$ledmatrix.c$30$1$1 Def0000
+S A$ledmatrix$476 Def0039
+S A$ledmatrix$467 Def002F
+S A$ledmatrix$458 Def0024
+S A$ledmatrix$449 Def0018
+S A$ledmatrix$477 Def003C
+S A$ledmatrix$459 Def0026
+S A$ledmatrix$469 Def0030
+S C$ledmatrix.c$31$2$2 Def0038
+S C$ledmatrix.c$27$0$0 Def0000
+S G$main$0$0 Def0000
+S C$ledmatrix.c$32$3$3 Def000F
+S C$ledmatrix.c$37$1$1 Def003D
+S C$ledmatrix.c$33$3$3 Def0012
+S C$ledmatrix.c$34$3$3 Def0020
+A CONST size 8 flags 20 addr 0
+S Fledmatrix$image$0$0 Def0000
+A XINIT size 0 flags 20 addr 0
+A CABS size 0 flags 28 addr 0
+T 00 00
+R 00 00 00 02
+T 00 00
+R 00 00 00 05
+T 00 00
+R 00 00 00 05
+T 00 00
+R 00 00 00 0D
+T 00 00 02 00 00
+R 00 00 00 0D 02 03 00 BA
+T 00 00 02 00 03
+R 00 00 00 15 00 03 00 0D
+T 00 03
+R 00 00 00 0D
+T 00 03 12 00 00 80 FE
+R 00 00 00 0D 00 03 00 16
+T 00 00
+R 00 00 00 16
+T 00 00
+R 00 00 00 16
+T 00 00 7A 00 7B 00
+R 00 00 00 16
+T 00 04
+R 00 00 00 16
+T 00 04 C3 EA 94 08 EB 64 80 94 80 50 F1 75 90 FF
+R 00 00 00 16
+T 00 12 EA 24 00 00 00 F5 82 EB 34 00 00 00 F5 83
+R 00 00 00 16 F1 01 04 00 17 F1 81 0B 00 17
+T 00 1C E4 93 F5 80 8A F0 05 F0 7C 01 7D 00 80 06
+R 00 00 00 16
+T 00 2A
+R 00 00 00 16
+T 00 2A EC 2C FC ED 33 FD
+R 00 00 00 16
+T 00 30
+R 00 00 00 16
+T 00 30 D5 F0 F7 74 FF 6C F5 90 0A BA 00 C8 0B 80
+R 00 00 00 16
+T 00 3E C5
+R 00 00 00 16
+T 00 00
+R 00 00 00 17
+T 00 00 B1 9D BD B1 B7 B7 11 FF
+R 00 00 00 17
diff --git a/demo/ledmatrix.rst b/demo/ledmatrix.rst
new file mode 100644
index 0000000..9a26795
--- /dev/null
+++ b/demo/ledmatrix.rst
@@ -0,0 +1,494 @@
+ 1 ;--------------------------------------------------------
+ 2 ; File Created by SDCC : free open source ANSI-C Compiler
+ 3 ; Version 2.9.0 #5416 (Oct 6 2009) (UNIX)
+ 4 ; This file was generated Mon Oct 19 23:11:07 2009
+ 5 ;--------------------------------------------------------
+ 6 .module ledmatrix
+ 7 .optsdcc -mmcs51 --model-small
+ 8
+ 9 ;--------------------------------------------------------
+ 10 ; Public variables in this module
+ 11 ;--------------------------------------------------------
+ 12 .globl _main
+ 13 .globl _CY
+ 14 .globl _AC
+ 15 .globl _F0
+ 16 .globl _RS1
+ 17 .globl _RS0
+ 18 .globl _OV
+ 19 .globl _FL
+ 20 .globl _P
+ 21 .globl _PS
+ 22 .globl _PT1
+ 23 .globl _PX1
+ 24 .globl _PT0
+ 25 .globl _PX0
+ 26 .globl _RD
+ 27 .globl _WR
+ 28 .globl _T1
+ 29 .globl _T0
+ 30 .globl _INT1
+ 31 .globl _INT0
+ 32 .globl _TXD
+ 33 .globl _RXD
+ 34 .globl _P3_7
+ 35 .globl _P3_6
+ 36 .globl _P3_5
+ 37 .globl _P3_4
+ 38 .globl _P3_3
+ 39 .globl _P3_2
+ 40 .globl _P3_1
+ 41 .globl _P3_0
+ 42 .globl _EA
+ 43 .globl _ES
+ 44 .globl _ET1
+ 45 .globl _EX1
+ 46 .globl _ET0
+ 47 .globl _EX0
+ 48 .globl _P2_7
+ 49 .globl _P2_6
+ 50 .globl _P2_5
+ 51 .globl _P2_4
+ 52 .globl _P2_3
+ 53 .globl _P2_2
+ 54 .globl _P2_1
+ 55 .globl _P2_0
+ 56 .globl _SM0
+ 57 .globl _SM1
+ 58 .globl _SM2
+ 59 .globl _REN
+ 60 .globl _TB8
+ 61 .globl _RB8
+ 62 .globl _TI
+ 63 .globl _RI
+ 64 .globl _P1_7
+ 65 .globl _P1_6
+ 66 .globl _P1_5
+ 67 .globl _P1_4
+ 68 .globl _P1_3
+ 69 .globl _P1_2
+ 70 .globl _P1_1
+ 71 .globl _P1_0
+ 72 .globl _TF1
+ 73 .globl _TR1
+ 74 .globl _TF0
+ 75 .globl _TR0
+ 76 .globl _IE1
+ 77 .globl _IT1
+ 78 .globl _IE0
+ 79 .globl _IT0
+ 80 .globl _P0_7
+ 81 .globl _P0_6
+ 82 .globl _P0_5
+ 83 .globl _P0_4
+ 84 .globl _P0_3
+ 85 .globl _P0_2
+ 86 .globl _P0_1
+ 87 .globl _P0_0
+ 88 .globl _B
+ 89 .globl _A
+ 90 .globl _ACC
+ 91 .globl _PSW
+ 92 .globl _IP
+ 93 .globl _P3
+ 94 .globl _IE
+ 95 .globl _P2
+ 96 .globl _SBUF
+ 97 .globl _SCON
+ 98 .globl _P1
+ 99 .globl _TH1
+ 100 .globl _TH0
+ 101 .globl _TL1
+ 102 .globl _TL0
+ 103 .globl _TMOD
+ 104 .globl _TCON
+ 105 .globl _PCON
+ 106 .globl _DPH
+ 107 .globl _DPL
+ 108 .globl _SP
+ 109 .globl _P0
+ 110 ;--------------------------------------------------------
+ 111 ; special function registers
+ 112 ;--------------------------------------------------------
+ 113 .area RSEG (DATA)
+ 0080 114 G$P0$0$0 == 0x0080
+ 0080 115 _P0 = 0x0080
+ 0081 116 G$SP$0$0 == 0x0081
+ 0081 117 _SP = 0x0081
+ 0082 118 G$DPL$0$0 == 0x0082
+ 0082 119 _DPL = 0x0082
+ 0083 120 G$DPH$0$0 == 0x0083
+ 0083 121 _DPH = 0x0083
+ 0087 122 G$PCON$0$0 == 0x0087
+ 0087 123 _PCON = 0x0087
+ 0088 124 G$TCON$0$0 == 0x0088
+ 0088 125 _TCON = 0x0088
+ 0089 126 G$TMOD$0$0 == 0x0089
+ 0089 127 _TMOD = 0x0089
+ 008A 128 G$TL0$0$0 == 0x008a
+ 008A 129 _TL0 = 0x008a
+ 008B 130 G$TL1$0$0 == 0x008b
+ 008B 131 _TL1 = 0x008b
+ 008C 132 G$TH0$0$0 == 0x008c
+ 008C 133 _TH0 = 0x008c
+ 008D 134 G$TH1$0$0 == 0x008d
+ 008D 135 _TH1 = 0x008d
+ 0090 136 G$P1$0$0 == 0x0090
+ 0090 137 _P1 = 0x0090
+ 0098 138 G$SCON$0$0 == 0x0098
+ 0098 139 _SCON = 0x0098
+ 0099 140 G$SBUF$0$0 == 0x0099
+ 0099 141 _SBUF = 0x0099
+ 00A0 142 G$P2$0$0 == 0x00a0
+ 00A0 143 _P2 = 0x00a0
+ 00A8 144 G$IE$0$0 == 0x00a8
+ 00A8 145 _IE = 0x00a8
+ 00B0 146 G$P3$0$0 == 0x00b0
+ 00B0 147 _P3 = 0x00b0
+ 00B8 148 G$IP$0$0 == 0x00b8
+ 00B8 149 _IP = 0x00b8
+ 00D0 150 G$PSW$0$0 == 0x00d0
+ 00D0 151 _PSW = 0x00d0
+ 00E0 152 G$ACC$0$0 == 0x00e0
+ 00E0 153 _ACC = 0x00e0
+ 00E0 154 G$A$0$0 == 0x00e0
+ 00E0 155 _A = 0x00e0
+ 00F0 156 G$B$0$0 == 0x00f0
+ 00F0 157 _B = 0x00f0
+ 158 ;--------------------------------------------------------
+ 159 ; special function bits
+ 160 ;--------------------------------------------------------
+ 161 .area RSEG (DATA)
+ 0080 162 G$P0_0$0$0 == 0x0080
+ 0080 163 _P0_0 = 0x0080
+ 0081 164 G$P0_1$0$0 == 0x0081
+ 0081 165 _P0_1 = 0x0081
+ 0082 166 G$P0_2$0$0 == 0x0082
+ 0082 167 _P0_2 = 0x0082
+ 0083 168 G$P0_3$0$0 == 0x0083
+ 0083 169 _P0_3 = 0x0083
+ 0084 170 G$P0_4$0$0 == 0x0084
+ 0084 171 _P0_4 = 0x0084
+ 0085 172 G$P0_5$0$0 == 0x0085
+ 0085 173 _P0_5 = 0x0085
+ 0086 174 G$P0_6$0$0 == 0x0086
+ 0086 175 _P0_6 = 0x0086
+ 0087 176 G$P0_7$0$0 == 0x0087
+ 0087 177 _P0_7 = 0x0087
+ 0088 178 G$IT0$0$0 == 0x0088
+ 0088 179 _IT0 = 0x0088
+ 0089 180 G$IE0$0$0 == 0x0089
+ 0089 181 _IE0 = 0x0089
+ 008A 182 G$IT1$0$0 == 0x008a
+ 008A 183 _IT1 = 0x008a
+ 008B 184 G$IE1$0$0 == 0x008b
+ 008B 185 _IE1 = 0x008b
+ 008C 186 G$TR0$0$0 == 0x008c
+ 008C 187 _TR0 = 0x008c
+ 008D 188 G$TF0$0$0 == 0x008d
+ 008D 189 _TF0 = 0x008d
+ 008E 190 G$TR1$0$0 == 0x008e
+ 008E 191 _TR1 = 0x008e
+ 008F 192 G$TF1$0$0 == 0x008f
+ 008F 193 _TF1 = 0x008f
+ 0090 194 G$P1_0$0$0 == 0x0090
+ 0090 195 _P1_0 = 0x0090
+ 0091 196 G$P1_1$0$0 == 0x0091
+ 0091 197 _P1_1 = 0x0091
+ 0092 198 G$P1_2$0$0 == 0x0092
+ 0092 199 _P1_2 = 0x0092
+ 0093 200 G$P1_3$0$0 == 0x0093
+ 0093 201 _P1_3 = 0x0093
+ 0094 202 G$P1_4$0$0 == 0x0094
+ 0094 203 _P1_4 = 0x0094
+ 0095 204 G$P1_5$0$0 == 0x0095
+ 0095 205 _P1_5 = 0x0095
+ 0096 206 G$P1_6$0$0 == 0x0096
+ 0096 207 _P1_6 = 0x0096
+ 0097 208 G$P1_7$0$0 == 0x0097
+ 0097 209 _P1_7 = 0x0097
+ 0098 210 G$RI$0$0 == 0x0098
+ 0098 211 _RI = 0x0098
+ 0099 212 G$TI$0$0 == 0x0099
+ 0099 213 _TI = 0x0099
+ 009A 214 G$RB8$0$0 == 0x009a
+ 009A 215 _RB8 = 0x009a
+ 009B 216 G$TB8$0$0 == 0x009b
+ 009B 217 _TB8 = 0x009b
+ 009C 218 G$REN$0$0 == 0x009c
+ 009C 219 _REN = 0x009c
+ 009D 220 G$SM2$0$0 == 0x009d
+ 009D 221 _SM2 = 0x009d
+ 009E 222 G$SM1$0$0 == 0x009e
+ 009E 223 _SM1 = 0x009e
+ 009F 224 G$SM0$0$0 == 0x009f
+ 009F 225 _SM0 = 0x009f
+ 00A0 226 G$P2_0$0$0 == 0x00a0
+ 00A0 227 _P2_0 = 0x00a0
+ 00A1 228 G$P2_1$0$0 == 0x00a1
+ 00A1 229 _P2_1 = 0x00a1
+ 00A2 230 G$P2_2$0$0 == 0x00a2
+ 00A2 231 _P2_2 = 0x00a2
+ 00A3 232 G$P2_3$0$0 == 0x00a3
+ 00A3 233 _P2_3 = 0x00a3
+ 00A4 234 G$P2_4$0$0 == 0x00a4
+ 00A4 235 _P2_4 = 0x00a4
+ 00A5 236 G$P2_5$0$0 == 0x00a5
+ 00A5 237 _P2_5 = 0x00a5
+ 00A6 238 G$P2_6$0$0 == 0x00a6
+ 00A6 239 _P2_6 = 0x00a6
+ 00A7 240 G$P2_7$0$0 == 0x00a7
+ 00A7 241 _P2_7 = 0x00a7
+ 00A8 242 G$EX0$0$0 == 0x00a8
+ 00A8 243 _EX0 = 0x00a8
+ 00A9 244 G$ET0$0$0 == 0x00a9
+ 00A9 245 _ET0 = 0x00a9
+ 00AA 246 G$EX1$0$0 == 0x00aa
+ 00AA 247 _EX1 = 0x00aa
+ 00AB 248 G$ET1$0$0 == 0x00ab
+ 00AB 249 _ET1 = 0x00ab
+ 00AC 250 G$ES$0$0 == 0x00ac
+ 00AC 251 _ES = 0x00ac
+ 00AF 252 G$EA$0$0 == 0x00af
+ 00AF 253 _EA = 0x00af
+ 00B0 254 G$P3_0$0$0 == 0x00b0
+ 00B0 255 _P3_0 = 0x00b0
+ 00B1 256 G$P3_1$0$0 == 0x00b1
+ 00B1 257 _P3_1 = 0x00b1
+ 00B2 258 G$P3_2$0$0 == 0x00b2
+ 00B2 259 _P3_2 = 0x00b2
+ 00B3 260 G$P3_3$0$0 == 0x00b3
+ 00B3 261 _P3_3 = 0x00b3
+ 00B4 262 G$P3_4$0$0 == 0x00b4
+ 00B4 263 _P3_4 = 0x00b4
+ 00B5 264 G$P3_5$0$0 == 0x00b5
+ 00B5 265 _P3_5 = 0x00b5
+ 00B6 266 G$P3_6$0$0 == 0x00b6
+ 00B6 267 _P3_6 = 0x00b6
+ 00B7 268 G$P3_7$0$0 == 0x00b7
+ 00B7 269 _P3_7 = 0x00b7
+ 00B0 270 G$RXD$0$0 == 0x00b0
+ 00B0 271 _RXD = 0x00b0
+ 00B1 272 G$TXD$0$0 == 0x00b1
+ 00B1 273 _TXD = 0x00b1
+ 00B2 274 G$INT0$0$0 == 0x00b2
+ 00B2 275 _INT0 = 0x00b2
+ 00B3 276 G$INT1$0$0 == 0x00b3
+ 00B3 277 _INT1 = 0x00b3
+ 00B4 278 G$T0$0$0 == 0x00b4
+ 00B4 279 _T0 = 0x00b4
+ 00B5 280 G$T1$0$0 == 0x00b5
+ 00B5 281 _T1 = 0x00b5
+ 00B6 282 G$WR$0$0 == 0x00b6
+ 00B6 283 _WR = 0x00b6
+ 00B7 284 G$RD$0$0 == 0x00b7
+ 00B7 285 _RD = 0x00b7
+ 00B8 286 G$PX0$0$0 == 0x00b8
+ 00B8 287 _PX0 = 0x00b8
+ 00B9 288 G$PT0$0$0 == 0x00b9
+ 00B9 289 _PT0 = 0x00b9
+ 00BA 290 G$PX1$0$0 == 0x00ba
+ 00BA 291 _PX1 = 0x00ba
+ 00BB 292 G$PT1$0$0 == 0x00bb
+ 00BB 293 _PT1 = 0x00bb
+ 00BC 294 G$PS$0$0 == 0x00bc
+ 00BC 295 _PS = 0x00bc
+ 00D0 296 G$P$0$0 == 0x00d0
+ 00D0 297 _P = 0x00d0
+ 00D1 298 G$FL$0$0 == 0x00d1
+ 00D1 299 _FL = 0x00d1
+ 00D2 300 G$OV$0$0 == 0x00d2
+ 00D2 301 _OV = 0x00d2
+ 00D3 302 G$RS0$0$0 == 0x00d3
+ 00D3 303 _RS0 = 0x00d3
+ 00D4 304 G$RS1$0$0 == 0x00d4
+ 00D4 305 _RS1 = 0x00d4
+ 00D5 306 G$F0$0$0 == 0x00d5
+ 00D5 307 _F0 = 0x00d5
+ 00D6 308 G$AC$0$0 == 0x00d6
+ 00D6 309 _AC = 0x00d6
+ 00D7 310 G$CY$0$0 == 0x00d7
+ 00D7 311 _CY = 0x00d7
+ 312 ;--------------------------------------------------------
+ 313 ; overlayable register banks
+ 314 ;--------------------------------------------------------
+ 315 .area REG_BANK_0 (REL,OVR,DATA)
+ 0000 316 .ds 8
+ 317 ;--------------------------------------------------------
+ 318 ; internal ram data
+ 319 ;--------------------------------------------------------
+ 320 .area DSEG (DATA)
+ 321 ;--------------------------------------------------------
+ 322 ; overlayable items in internal ram
+ 323 ;--------------------------------------------------------
+ 324 .area OSEG (OVR,DATA)
+ 325 ;--------------------------------------------------------
+ 326 ; Stack segment in internal ram
+ 327 ;--------------------------------------------------------
+ 328 .area SSEG (DATA)
+ 0008 329 __start__stack:
+ 0008 330 .ds 1
+ 331
+ 332 ;--------------------------------------------------------
+ 333 ; indirectly addressable internal ram data
+ 334 ;--------------------------------------------------------
+ 335 .area ISEG (DATA)
+ 336 ;--------------------------------------------------------
+ 337 ; absolute internal ram data
+ 338 ;--------------------------------------------------------
+ 339 .area IABS (ABS,DATA)
+ 340 .area IABS (ABS,DATA)
+ 341 ;--------------------------------------------------------
+ 342 ; bit data
+ 343 ;--------------------------------------------------------
+ 344 .area BSEG (BIT)
+ 345 ;--------------------------------------------------------
+ 346 ; paged external ram data
+ 347 ;--------------------------------------------------------
+ 348 .area PSEG (PAG,XDATA)
+ 349 ;--------------------------------------------------------
+ 350 ; external ram data
+ 351 ;--------------------------------------------------------
+ 352 .area XSEG (XDATA)
+ 353 ;--------------------------------------------------------
+ 354 ; absolute external ram data
+ 355 ;--------------------------------------------------------
+ 356 .area XABS (ABS,XDATA)
+ 357 ;--------------------------------------------------------
+ 358 ; external initialized ram data
+ 359 ;--------------------------------------------------------
+ 360 .area XISEG (XDATA)
+ 361 .area HOME (CODE)
+ 362 .area GSINIT0 (CODE)
+ 363 .area GSINIT1 (CODE)
+ 364 .area GSINIT2 (CODE)
+ 365 .area GSINIT3 (CODE)
+ 366 .area GSINIT4 (CODE)
+ 367 .area GSINIT5 (CODE)
+ 368 .area GSINIT (CODE)
+ 369 .area GSFINAL (CODE)
+ 370 .area CSEG (CODE)
+ 371 ;--------------------------------------------------------
+ 372 ; interrupt vector
+ 373 ;--------------------------------------------------------
+ 374 .area HOME (CODE)
+ 0000 375 __interrupt_vect:
+ 0000 02 00 08 376 ljmp __sdcc_gsinit_startup
+ 377 ;--------------------------------------------------------
+ 378 ; global & static initialisations
+ 379 ;--------------------------------------------------------
+ 380 .area HOME (CODE)
+ 381 .area GSINIT (CODE)
+ 382 .area GSFINAL (CODE)
+ 383 .area GSINIT (CODE)
+ 384 .globl __sdcc_gsinit_startup
+ 385 .globl __sdcc_program_startup
+ 386 .globl __start__stack
+ 387 .globl __mcs51_genXINIT
+ 388 .globl __mcs51_genXRAMCLEAR
+ 389 .globl __mcs51_genRAMCLEAR
+ 390 .area GSFINAL (CODE)
+ 0061 02 00 03 391 ljmp __sdcc_program_startup
+ 392 ;--------------------------------------------------------
+ 393 ; Home
+ 394 ;--------------------------------------------------------
+ 395 .area HOME (CODE)
+ 396 .area HOME (CODE)
+ 0003 397 __sdcc_program_startup:
+ 0003 12 00 64 398 lcall _main
+ 399 ; return from main will lock up
+ 0006 80 FE 400 sjmp .
+ 401 ;--------------------------------------------------------
+ 402 ; code
+ 403 ;--------------------------------------------------------
+ 404 .area CSEG (CODE)
+ 405 ;------------------------------------------------------------
+ 406 ;Allocation info for local variables in function 'main'
+ 407 ;------------------------------------------------------------
+ 408 ;i Allocated to registers r2 r3
+ 409 ;------------------------------------------------------------
+ 0000 410 G$main$0$0 ==.
+ 0000 411 C$ledmatrix.c$27$0$0 ==.
+ 412 ; ledmatrix.c:27: int main()
+ 413 ; -----------------------------------------
+ 414 ; function main
+ 415 ; -----------------------------------------
+ 0064 416 _main:
+ 0002 417 ar2 = 0x02
+ 0003 418 ar3 = 0x03
+ 0004 419 ar4 = 0x04
+ 0005 420 ar5 = 0x05
+ 0006 421 ar6 = 0x06
+ 0007 422 ar7 = 0x07
+ 0000 423 ar0 = 0x00
+ 0001 424 ar1 = 0x01
+ 0000 425 C$ledmatrix.c$30$1$1 ==.
+ 426 ; ledmatrix.c:30: while(1) {
+ 0064 427 00102$:
+ 0000 428 C$ledmatrix.c$31$2$2 ==.
+ 429 ; ledmatrix.c:31: for(i=0; i<8; i++) {
+ 0064 7A 00 430 mov r2,#0x00
+ 0066 7B 00 431 mov r3,#0x00
+ 0068 432 00104$:
+ 0068 C3 433 clr c
+ 0069 EA 434 mov a,r2
+ 006A 94 08 435 subb a,#0x08
+ 006C EB 436 mov a,r3
+ 006D 64 80 437 xrl a,#0x80
+ 006F 94 80 438 subb a,#0x80
+ 0071 50 F1 439 jnc 00102$
+ 000F 440 C$ledmatrix.c$32$3$3 ==.
+ 441 ; ledmatrix.c:32: P1 = 0xff;
+ 0073 75 90 FF 442 mov _P1,#0xFF
+ 0012 443 C$ledmatrix.c$33$3$3 ==.
+ 444 ; ledmatrix.c:33: P0 = image[i];
+ 0076 EA 445 mov a,r2
+ 0077 24 A7 446 add a,#_image
+ 0079 F5 82 447 mov dpl,a
+ 007B EB 448 mov a,r3
+ 007C 34 00 449 addc a,#(_image >> 8)
+ 007E F5 83 450 mov dph,a
+ 0080 E4 451 clr a
+ 0081 93 452 movc a,@a+dptr
+ 0082 F5 80 453 mov _P0,a
+ 0020 454 C$ledmatrix.c$34$3$3 ==.
+ 455 ; ledmatrix.c:34: P1 = (1 << i) ^ 255;
+ 0084 8A F0 456 mov b,r2
+ 0086 05 F0 457 inc b
+ 0088 7C 01 458 mov r4,#0x01
+ 008A 7D 00 459 mov r5,#0x00
+ 008C 80 06 460 sjmp 00115$
+ 008E 461 00114$:
+ 008E EC 462 mov a,r4
+ 008F 2C 463 add a,r4
+ 0090 FC 464 mov r4,a
+ 0091 ED 465 mov a,r5
+ 0092 33 466 rlc a
+ 0093 FD 467 mov r5,a
+ 0094 468 00115$:
+ 0094 D5 F0 F7 469 djnz b,00114$
+ 0097 74 FF 470 mov a,#0xFF
+ 0099 6C 471 xrl a,r4
+ 009A F5 90 472 mov _P1,a
+ 0038 473 C$ledmatrix.c$31$2$2 ==.
+ 474 ; ledmatrix.c:31: for(i=0; i<8; i++) {
+ 009C 0A 475 inc r2
+ 009D BA 00 C8 476 cjne r2,#0x00,00104$
+ 00A0 0B 477 inc r3
+ 003D 478 C$ledmatrix.c$37$1$1 ==.
+ 003D 479 XG$main$0$0 ==.
+ 00A1 80 C5 480 sjmp 00104$
+ 481 .area CSEG (CODE)
+ 482 .area CONST (CODE)
+ 0000 483 Fledmatrix$image$0$0 == .
+ 00A7 484 _image:
+ 00A7 B1 485 .db #0xB1
+ 00A8 9D 486 .db #0x9D
+ 00A9 BD 487 .db #0xBD
+ 00AA B1 488 .db #0xB1
+ 00AB B7 489 .db #0xB7
+ 00AC B7 490 .db #0xB7
+ 00AD 11 491 .db #0x11
+ 00AE FF 492 .db #0xFF
+ 493 .area XINIT (CODE)
+ 494 .area CABS (ABS,CODE)
diff --git a/demo/ledmatrix.sym b/demo/ledmatrix.sym
new file mode 100644
index 0000000..e61476a
--- /dev/null
+++ b/demo/ledmatrix.sym
@@ -0,0 +1,634 @@
+ ASxxxx Assembler V01.70 + NoICE + SDCC mods + Flat24 Feb-1999 (Intel 8051), page 1.
+
+Symbol Table
+
+ A 00D6
+ D A$ledmatrix$376 0000 GR
+ 15 A$ledmatrix$391 0000 GR
+ D A$ledmatrix$398 0003 GR
+ D A$ledmatrix$400 0006 GR
+ 16 A$ledmatrix$430 0000 GR
+ 16 A$ledmatrix$431 0002 GR
+ 16 A$ledmatrix$433 0004 GR
+ 16 A$ledmatrix$434 0005 GR
+ 16 A$ledmatrix$435 0006 GR
+ 16 A$ledmatrix$436 0008 GR
+ 16 A$ledmatrix$437 0009 GR
+ 16 A$ledmatrix$438 000B GR
+ 16 A$ledmatrix$439 000D GR
+ 16 A$ledmatrix$442 000F GR
+ 16 A$ledmatrix$445 0012 GR
+ 16 A$ledmatrix$446 0013 GR
+ 16 A$ledmatrix$447 0015 GR
+ 16 A$ledmatrix$448 0017 GR
+ 16 A$ledmatrix$449 0018 GR
+ 16 A$ledmatrix$450 001A GR
+ 16 A$ledmatrix$451 001C GR
+ 16 A$ledmatrix$452 001D GR
+ 16 A$ledmatrix$453 001E GR
+ 16 A$ledmatrix$456 0020 GR
+ 16 A$ledmatrix$457 0022 GR
+ 16 A$ledmatrix$458 0024 GR
+ 16 A$ledmatrix$459 0026 GR
+ 16 A$ledmatrix$460 0028 GR
+ 16 A$ledmatrix$462 002A GR
+ 16 A$ledmatrix$463 002B GR
+ 16 A$ledmatrix$464 002C GR
+ 16 A$ledmatrix$465 002D GR
+ 16 A$ledmatrix$466 002E GR
+ 16 A$ledmatrix$467 002F GR
+ 16 A$ledmatrix$469 0030 GR
+ 16 A$ledmatrix$470 0033 GR
+ 16 A$ledmatrix$471 0035 GR
+ 16 A$ledmatrix$472 0036 GR
+ 16 A$ledmatrix$475 0038 GR
+ 16 A$ledmatrix$476 0039 GR
+ 16 A$ledmatrix$477 003C GR
+ 16 A$ledmatrix$480 003D GR
+ AC 00D6
+ ACC 00E0
+ ACC.0 00E0
+ ACC.1 00E1
+ ACC.2 00E2
+ ACC.3 00E3
+ ACC.4 00E4
+ ACC.5 00E5
+ ACC.6 00E6
+ ACC.7 00E7
+ B 00F0
+ B.0 00F0
+ B.1 00F1
+ B.2 00F2
+ B.3 00F3
+ B.4 00F4
+ B.5 00F5
+ B.6 00F6
+ B.7 00F7
+ 16 C$ledmatrix.c$27$0$0 = 0000 GR
+ 16 C$ledmatrix.c$30$1$1 = 0000 GR
+ 16 C$ledmatrix.c$31$2$2 = 0038 GR
+ 16 C$ledmatrix.c$32$3$3 = 000F GR
+ 16 C$ledmatrix.c$33$3$3 = 0012 GR
+ 16 C$ledmatrix.c$34$3$3 = 0020 GR
+ 16 C$ledmatrix.c$37$1$1 = 003D GR
+ CPRL2 00C8
+ CT2 00C9
+ CY 00D7
+ DPH 0083
+ DPL 0082
+ EA 00AF
+ ES 00AC
+ ET0 00A9
+ ET1 00AB
+ ET2 00AD
+ EX0 00A8
+ EX1 00AA
+ EXEN2 00CB
+ EXF2 00CE
+ F0 00D5
+ 17 Fledmatrix$image$0$0 = 0000 GR
+ G$A$0$0 = 00E0 G
+ G$AC$0$0 = 00D6 G
+ G$ACC$0$0 = 00E0 G
+ G$B$0$0 = 00F0 G
+ G$CY$0$0 = 00D7 G
+ G$DPH$0$0 = 0083 G
+ G$DPL$0$0 = 0082 G
+ G$EA$0$0 = 00AF G
+ G$ES$0$0 = 00AC G
+ G$ET0$0$0 = 00A9 G
+ G$ET1$0$0 = 00AB G
+ G$EX0$0$0 = 00A8 G
+ G$EX1$0$0 = 00AA G
+ G$F0$0$0 = 00D5 G
+ G$FL$0$0 = 00D1 G
+ G$IE$0$0 = 00A8 G
+ G$IE0$0$0 = 0089 G
+ G$IE1$0$0 = 008B G
+ G$INT0$0$0 = 00B2 G
+ G$INT1$0$0 = 00B3 G
+ G$IP$0$0 = 00B8 G
+ G$IT0$0$0 = 0088 G
+ G$IT1$0$0 = 008A G
+ G$OV$0$0 = 00D2 G
+ G$P$0$0 = 00D0 G
+ G$P0$0$0 = 0080 G
+ G$P0_0$0$0 = 0080 G
+ G$P0_1$0$0 = 0081 G
+ G$P0_2$0$0 = 0082 G
+ G$P0_3$0$0 = 0083 G
+ G$P0_4$0$0 = 0084 G
+ G$P0_5$0$0 = 0085 G
+ G$P0_6$0$0 = 0086 G
+ G$P0_7$0$0 = 0087 G
+ G$P1$0$0 = 0090 G
+ G$P1_0$0$0 = 0090 G
+ G$P1_1$0$0 = 0091 G
+ G$P1_2$0$0 = 0092 G
+ G$P1_3$0$0 = 0093 G
+ G$P1_4$0$0 = 0094 G
+ G$P1_5$0$0 = 0095 G
+ G$P1_6$0$0 = 0096 G
+ G$P1_7$0$0 = 0097 G
+ G$P2$0$0 = 00A0 G
+ G$P2_0$0$0 = 00A0 G
+ G$P2_1$0$0 = 00A1 G
+ G$P2_2$0$0 = 00A2 G
+ G$P2_3$0$0 = 00A3 G
+ G$P2_4$0$0 = 00A4 G
+ G$P2_5$0$0 = 00A5 G
+ G$P2_6$0$0 = 00A6 G
+ G$P2_7$0$0 = 00A7 G
+ G$P3$0$0 = 00B0 G
+ G$P3_0$0$0 = 00B0 G
+ G$P3_1$0$0 = 00B1 G
+ G$P3_2$0$0 = 00B2 G
+ G$P3_3$0$0 = 00B3 G
+ G$P3_4$0$0 = 00B4 G
+ G$P3_5$0$0 = 00B5 G
+ G$P3_6$0$0 = 00B6 G
+ G$P3_7$0$0 = 00B7 G
+ G$PCON$0$0 = 0087 G
+ G$PS$0$0 = 00BC G
+ G$PSW$0$0 = 00D0 G
+ G$PT0$0$0 = 00B9 G
+ G$PT1$0$0 = 00BB G
+ G$PX0$0$0 = 00B8 G
+ G$PX1$0$0 = 00BA G
+ G$RB8$0$0 = 009A G
+ G$RD$0$0 = 00B7 G
+ G$REN$0$0 = 009C G
+ G$RI$0$0 = 0098 G
+ G$RS0$0$0 = 00D3 G
+ G$RS1$0$0 = 00D4 G
+ G$RXD$0$0 = 00B0 G
+ G$SBUF$0$0 = 0099 G
+ G$SCON$0$0 = 0098 G
+ G$SM0$0$0 = 009F G
+ G$SM1$0$0 = 009E G
+ G$SM2$0$0 = 009D G
+ G$SP$0$0 = 0081 G
+ G$T0$0$0 = 00B4 G
+ G$T1$0$0 = 00B5 G
+ G$TB8$0$0 = 009B G
+ G$TCON$0$0 = 0088 G
+ G$TF0$0$0 = 008D G
+ G$TF1$0$0 = 008F G
+ G$TH0$0$0 = 008C G
+ G$TH1$0$0 = 008D G
+ G$TI$0$0 = 0099 G
+ G$TL0$0$0 = 008A G
+ G$TL1$0$0 = 008B G
+ G$TMOD$0$0 = 0089 G
+ G$TR0$0$0 = 008C G
+ G$TR1$0$0 = 008E G
+ G$TXD$0$0 = 00B1 G
+ G$WR$0$0 = 00B6 G
+ 16 G$main$0$0 = 0000 GR
+ IE 00A8
+ IE.0 00A8
+ IE.1 00A9
+ IE.2 00AA
+ IE.3 00AB
+ IE.4 00AC
+ IE.5 00AD
+ IE.7 00AF
+ IE0 0089
+ IE1 008B
+ INT0 00B2
+ INT1 00B3
+ IP 00B8
+ IP.0 00B8
+ IP.1 00B9
+ IP.2 00BA
+ IP.3 00BB
+ IP.4 00BC
+ IP.5 00BD
+ IT0 0088
+ IT1 008A
+ OV 00D2
+ P 00D0
+ P0 0080
+ P0.0 0080
+ P0.1 0081
+ P0.2 0082
+ P0.3 0083
+ P0.4 0084
+ P0.5 0085
+ P0.6 0086
+ P0.7 0087
+ P1 0090
+ P1.0 0090
+ P1.1 0091
+ P1.2 0092
+ P1.3 0093
+ P1.4 0094
+ P1.5 0095
+ P1.6 0096
+ P1.7 0097
+ P2 00A0
+ P2.0 00A0
+ P2.1 00A1
+ P2.2 00A2
+ P2.3 00A3
+ P2.4 00A4
+ P2.5 00A5
+ P2.6 00A6
+ P2.7 00A7
+ P3 00B0
+ P3.0 00B0
+ P3.1 00B1
+ P3.2 00B2
+ P3.3 00B3
+ P3.4 00B4
+ P3.5 00B5
+ P3.6 00B6
+ P3.7 00B7
+ PCON 0087
+ PS 00BC
+ PSW 00D0
+ PSW.0 00D0
+ PSW.1 00D1
+ PSW.2 00D2
+ PSW.3 00D3
+ PSW.4 00D4
+ PSW.5 00D5
+ PSW.6 00D6
+ PSW.7 00D7
+ PT0 00B9
+ PT1 00BB
+ PT2 00BD
+ PX0 00B8
+ PX1 00BA
+ RB8 009A
+ RCAP2H 00CB
+ RCAP2L 00CA
+ RCLK 00CD
+ REN 009C
+ RI 0098
+ RS0 00D3
+ RS1 00D4
+ RXD 00B0
+ SBUF 0099
+ SCON 0098
+ SCON.0 0098
+ SCON.1 0099
+ SCON.2 009A
+ SCON.3 009B
+ SCON.4 009C
+ SCON.5 009D
+ SCON.6 009E
+ SCON.7 009F
+ SM0 009F
+ SM1 009E
+ SM2 009D
+ SP 0081
+ T2CON 00C8
+ T2CON.0 00C8
+ T2CON.1 00C9
+ T2CON.2 00CA
+ T2CON.3 00CB
+ T2CON.4 00CC
+ T2CON.5 00CD
+ T2CON.6 00CE
+ T2CON.7 00CF
+ TB8 009B
+ TCLK 00CC
+ TCON 0088
+ TCON.0 0088
+ TCON.1 0089
+ TCON.2 008A
+ TCON.3 008B
+ TCON.4 008C
+ TCON.5 008D
+ TCON.6 008E
+ TCON.7 008F
+ TF0 008D
+ TF1 008F
+ TF2 00CF
+ TH0 008C
+ TH1 008D
+ TH2 00CD
+ TI 0099
+ TL0 008A
+ TL1 008B
+ TL2 00CC
+ TMOD 0089
+ TR0 008C
+ TR1 008E
+ TR2 00CA
+ TXD 00B1
+ 16 XG$main$0$0 = 003D GR
+ _A = 00E0 G
+ _AC = 00D6 G
+ _ACC = 00E0 G
+ _B = 00F0 G
+ _CY = 00D7 G
+ _DPH = 0083 G
+ _DPL = 0082 G
+ _EA = 00AF G
+ _ES = 00AC G
+ _ET0 = 00A9 G
+ _ET1 = 00AB G
+ _EX0 = 00A8 G
+ _EX1 = 00AA G
+ _F0 = 00D5 G
+ _FL = 00D1 G
+ _IE = 00A8 G
+ _IE0 = 0089 G
+ _IE1 = 008B G
+ _INT0 = 00B2 G
+ _INT1 = 00B3 G
+ _IP = 00B8 G
+ _IT0 = 0088 G
+ _IT1 = 008A G
+ _OV = 00D2 G
+ _P = 00D0 G
+ _P0 = 0080 G
+ _P0_0 = 0080 G
+ _P0_1 = 0081 G
+ _P0_2 = 0082 G
+ _P0_3 = 0083 G
+ _P0_4 = 0084 G
+ _P0_5 = 0085 G
+ _P0_6 = 0086 G
+ _P0_7 = 0087 G
+ _P1 = 0090 G
+ _P1_0 = 0090 G
+ _P1_1 = 0091 G
+ _P1_2 = 0092 G
+ _P1_3 = 0093 G
+ _P1_4 = 0094 G
+ _P1_5 = 0095 G
+ _P1_6 = 0096 G
+ _P1_7 = 0097 G
+ _P2 = 00A0 G
+ _P2_0 = 00A0 G
+ _P2_1 = 00A1 G
+ _P2_2 = 00A2 G
+ _P2_3 = 00A3 G
+ _P2_4 = 00A4 G
+ _P2_5 = 00A5 G
+ _P2_6 = 00A6 G
+ _P2_7 = 00A7 G
+ _P3 = 00B0 G
+ _P3_0 = 00B0 G
+ _P3_1 = 00B1 G
+ _P3_2 = 00B2 G
+ _P3_3 = 00B3 G
+ _P3_4 = 00B4 G
+ _P3_5 = 00B5 G
+ _P3_6 = 00B6 G
+ _P3_7 = 00B7 G
+ _PCON = 0087 G
+ _PS = 00BC G
+ _PSW = 00D0 G
+ _PT0 = 00B9 G
+ _PT1 = 00BB G
+ _PX0 = 00B8 G
+ _PX1 = 00BA G
+ _RB8 = 009A G
+ _RD = 00B7 G
+ _REN = 009C G
+ _RI = 0098 G
+ _RS0 = 00D3 G
+ _RS1 = 00D4 G
+ _RXD = 00B0 G
+ _SBUF = 0099 G
+ _SCON = 0098 G
+ _SM0 = 009F G
+ _SM1 = 009E G
+ _SM2 = 009D G
+ _SP = 0081 G
+ _T0 = 00B4 G
+ _T1 = 00B5 G
+ _TB8 = 009B G
+ _TCON = 0088 G
+ _TF0 = 008D G
+ _TF1 = 008F G
+ _TH0 = 008C G
+ _TH1 = 008D G
+ _TI = 0099 G
+ _TL0 = 008A G
+ _TL1 = 008B G
+ _TMOD = 0089 G
+ _TR0 = 008C G
+ _TR1 = 008E G
+ _TXD = 00B1 G
+ _WR = 00B6 G
+ D __interrupt_vect 0000 R
+ __mcs51_genRAMCLEAR **** GX
+ __mcs51_genXINIT **** GX
+ __mcs51_genXRAMCLEAR **** GX
+ __sdcc_gsinit_startup **** GX
+ D __sdcc_program_startup 0003 GR
+ 5 __start__stack 0000 GR
+ 17 _image 0000 R
+ 16 _main 0000 GR
+ a 00D6
+ ac 00D6
+ acc 00E0
+ acc.0 00E0
+ acc.1 00E1
+ acc.2 00E2
+ acc.3 00E3
+ acc.4 00E4
+ acc.5 00E5
+ acc.6 00E6
+ acc.7 00E7
+ ar0 = 0000
+ ar1 = 0001
+ ar2 = 0002
+ ar3 = 0003
+ ar4 = 0004
+ ar5 = 0005
+ ar6 = 0006
+ ar7 = 0007
+ b 00F0
+ b.0 00F0
+ b.1 00F1
+ b.2 00F2
+ b.3 00F3
+ b.4 00F4
+ b.5 00F5
+ b.6 00F6
+ b.7 00F7
+ cprl2 00C8
+ ct2 00C9
+ cy 00D7
+ dph 0083
+ dpl 0082
+ ea 00AF
+ es 00AC
+ et0 00A9
+ et1 00AB
+ et2 00AD
+ ex0 00A8
+ ex1 00AA
+ exen2 00CB
+ exf2 00CE
+ f0 00D5
+ ie 00A8
+ ie.0 00A8
+ ie.1 00A9
+ ie.2 00AA
+ ie.3 00AB
+ ie.4 00AC
+ ie.5 00AD
+ ie.7 00AF
+ ie0 0089
+ ie1 008B
+ int0 00B2
+ int1 00B3
+ ip 00B8
+ ip.0 00B8
+ ip.1 00B9
+ ip.2 00BA
+ ip.3 00BB
+ ip.4 00BC
+ ip.5 00BD
+ it0 0088
+ it1 008A
+ ov 00D2
+ p 00D0
+ p0 0080
+ p0.0 0080
+ p0.1 0081
+ p0.2 0082
+ p0.3 0083
+ p0.4 0084
+ p0.5 0085
+ p0.6 0086
+ p0.7 0087
+ p1 0090
+ p1.0 0090
+ p1.1 0091
+ p1.2 0092
+ p1.3 0093
+ p1.4 0094
+ p1.5 0095
+ p1.6 0096
+ p1.7 0097
+ p2 00A0
+ p2.0 00A0
+ p2.1 00A1
+ p2.2 00A2
+ p2.3 00A3
+ p2.4 00A4
+ p2.5 00A5
+ p2.6 00A6
+ p2.7 00A7
+ p3 00B0
+ p3.0 00B0
+ p3.1 00B1
+ p3.2 00B2
+ p3.3 00B3
+ p3.4 00B4
+ p3.5 00B5
+ p3.6 00B6
+ p3.7 00B7
+ pcon 0087
+ ps 00BC
+ psw 00D0
+ psw.0 00D0
+ psw.1 00D1
+ psw.2 00D2
+ psw.3 00D3
+ psw.4 00D4
+ psw.5 00D5
+ psw.6 00D6
+ psw.7 00D7
+ pt0 00B9
+ pt1 00BB
+ pt2 00BD
+ px0 00B8
+ px1 00BA
+ rb8 009A
+ rcap2h 00CB
+ rcap2l 00CA
+ rclk 00CD
+ ren 009C
+ ri 0098
+ rs0 00D3
+ rs1 00D4
+ rxd 00B0
+ sbuf 0099
+ scon 0098
+ scon.0 0098
+ scon.1 0099
+ scon.2 009A
+ scon.3 009B
+ scon.4 009C
+ scon.5 009D
+ scon.6 009E
+ scon.7 009F
+ sm0 009F
+ sm1 009E
+ sm2 009D
+ sp 0081
+ t2con 00C8
+ t2con.0 00C8
+ t2con.1 00C9
+ t2con.2 00CA
+ t2con.3 00CB
+ t2con.4 00CC
+ t2con.5 00CD
+ t2con.6 00CE
+ t2con.7 00CF
+ tb8 009B
+ tclk 00CC
+ tcon 0088
+ tcon.0 0088
+ tcon.1 0089
+ tcon.2 008A
+ tcon.3 008B
+ tcon.4 008C
+ tcon.5 008D
+ tcon.6 008E
+ tcon.7 008F
+ tf0 008D
+ tf1 008F
+ tf2 00CF
+ th0 008C
+ th1 008D
+ th2 00CD
+ ti 0099
+ tl0 008A
+ tl1 008B
+ tl2 00CC
+ tmod 0089
+ tr0 008C
+ tr1 008E
+ tr2 00CA
+ txd 00B1
+
+ ASxxxx Assembler V01.70 + NoICE + SDCC mods + Flat24 Feb-1999 (Intel 8051), page 2.
+
+Area Table
+
+ 0 _CODE size 0 flags 0
+ 1 RSEG size 0 flags 0
+ 2 REG_BANK_0 size 8 flags 4
+ 3 DSEG size 0 flags 0
+ 4 OSEG size 0 flags 4
+ 5 SSEG size 1 flags 0
+ 6 ISEG size 0 flags 0
+ 7 IABS size 0 flags 8
+ 8 BSEG size 0 flags 80
+ 9 PSEG size 0 flags 50
+ A XSEG size 0 flags 40
+ B XABS size 0 flags 48
+ C XISEG size 0 flags 40
+ D HOME size 8 flags 20
+ E GSINIT0 size 0 flags 20
+ F GSINIT1 size 0 flags 20
+ 10 GSINIT2 size 0 flags 20
+ 11 GSINIT3 size 0 flags 20
+ 12 GSINIT4 size 0 flags 20
+ 13 GSINIT5 size 0 flags 20
+ 14 GSINIT size 0 flags 20
+ 15 GSFINAL size 3 flags 20
+ 16 CSEG size 3F flags 20
+ 17 CONST size 8 flags 20
+ 18 XINIT size 0 flags 20
+ 19 CABS size 0 flags 28
diff --git a/demo/ledmatrix.vhc b/demo/ledmatrix.vhc
new file mode 100644
index 0000000..4c8f25e
--- /dev/null
+++ b/demo/ledmatrix.vhc
@@ -0,0 +1,6 @@
+# MCU 8051 IDE: Virtual HW component configuration file
+# Date: 02/27/09
+# Project: Demo-project
+# Component: LED matrix
+
+LedMatrix {{C5 0 C6 0 C7 0 R0 1 R1 1 R2 1 R3 1 R4 1 R5 1 R6 1 R7 1 C0 0 C1 0 C2 0 C3 0 C4 0} {C5 2 C6 1 C7 0 R0 7 R1 6 R2 5 R3 4 R4 3 R5 2 R6 1 R7 0 C0 7 C1 6 C2 5 C3 4 C4 3} {} {Some user note ...} blue 500 {0 0}}
diff --git a/demo/mleddisplay.adf b/demo/mleddisplay.adf
new file mode 100644
index 0000000..f3c5764
--- /dev/null
+++ b/demo/mleddisplay.adf
@@ -0,0 +1,45 @@
+# Assembler debug file for MCU 8051 IDE v1.1
+# Used assembler: MCU 8051 IDE
+# Date: 03/02/09
+BFC1B21D558BFAE2B1E43162DAEFE347 "mleddisplay.asm"
+0 37 0 2 0 37
+0 51 3 6
+0 52 4 182 10 9
+0 54 7 118 0
+0 55 9 8
+0 56 10 184 36 1
+0 57 13 34
+0 58 14 17 3
+0 60 16 34
+0 72 17 24
+0 73 18 229 240
+0 74 20 3
+0 75 21 245 240
+0 79 23 230
+0 80 24 147
+0 83 25 117 176 255
+0 84 28 245 144
+0 85 30 133 240 176
+0 88 33 184 32 237
+0 89 36 34
+0 96 37 117 32 0
+0 97 40 117 33 0
+0 98 43 117 34 0
+0 99 46 117 35 0
+0 102 49 117 240 238
+0 104 52 144 0 65
+0 112 55 120 36
+0 113 57 17 17
+0 116 59 120 32
+0 117 61 17 3
+0 120 63 1 55
+0 21 65 192
+0 22 66 249
+0 23 67 164
+0 24 68 176
+0 25 69 153
+0 26 70 146
+0 27 71 130
+0 28 72 248
+0 29 73 128
+0 30 74 144 \ No newline at end of file
diff --git a/demo/mleddisplay.asm b/demo/mleddisplay.asm
new file mode 100644
index 0000000..8e2add9
--- /dev/null
+++ b/demo/mleddisplay.asm
@@ -0,0 +1,125 @@
+; Demonstration code for MCU 8051 IDE
+;
+; Load virtual HW from "mleddisplay.vhc"
+; and press F2 and F6
+;
+; It should increment 4 digit number displayed
+; on multiplexed LED display
+
+
+; -----------------------------------------------
+; CONSTANTS
+; -----------------------------------------------
+
+data_ptr data 20h ; Number to display
+data_len equ 4h ; Number of digits
+
+;; Codes for 8-segment LED display
+ ; They can be easily determinated with
+ ; 8-segment editor ( [Main menu] - >
+ ; [Utilities] -> [8-segment editor] )
+numbers:db 11000000b ; 0
+ db 11111001b ; 1
+ db 10100100b ; 2
+ db 10110000b ; 3
+ db 10011001b ; 4
+ db 10010010b ; 5
+ db 10000010b ; 6
+ db 11111000b ; 7
+ db 10000000b ; 8
+ db 10010000b ; 9
+
+; -----------------------------------------------
+; VECTORS
+; -----------------------------------------------
+ ; Reset vector
+ org 0
+ jmp start
+
+; -----------------------------------------------
+; SUBPROGRAMS
+; -----------------------------------------------
+
+;; Increment the number
+ ;
+ ; R0 must be set to data_ptr before call
+ ;
+ ; Affected registers: R0
+ ; Interrupts: None
+ ; Notes: Recursive subprogram
+inrement_number:
+ inc @R0
+ cjne @R0, #0Ah, inc_num_end
+
+ mov @R0, #0
+ inc R0
+ cjne R0, #data_ptr+data_len, $+4
+ ret
+ call inrement_number
+inc_num_end:
+ ret
+
+;; Display the number on the LED display
+ ;
+ ; DPTR must point to table numbers
+ ; R0 must contain (data_ptr+data_len)
+ ;
+ ; Affected registers: A, B, R0, P1, P3
+ ; Interrupts: None
+ ; Notes: Uses DPTR
+display_number:
+ ; Select digit to display
+ dec R0 ; In uC
+ mov A, B
+ rr A
+ mov B, A
+
+ ; Translate the digit to binary
+ ; representation for the LED display
+ mov A, @R0
+ movc A, @A+DPTR
+
+ ; Display the digit on the display
+ mov P3, #0ffh
+ mov P1, A
+ mov P3, B
+
+ ; Display next digit
+ cjne R0, #data_ptr, display_number
+ ret
+
+; -----------------------------------------------
+; PROGRAM START
+; -----------------------------------------------
+start:
+ ; Data to zeroes
+ mov data_ptr+0, #0h ; left-most
+ mov data_ptr+1, #0h
+ mov data_ptr+2, #0h
+ mov data_ptr+3, #0h ; right-most
+
+ ; Address 1st number on the display
+ mov B, #0EEh
+ ; Initialize DPTR (Data PoinTeR)
+ mov DPTR, #numbers
+
+; -----------------------------------------------
+; MAIN LOOP
+; -----------------------------------------------
+
+main:
+ ; Show the number on the LED display
+ mov R0, #data_ptr+data_len
+ call display_number
+
+ ; Increment the number
+ mov R0, #data_ptr
+ call inrement_number
+
+ ; Close main loop
+ jmp main
+
+; -----------------------------------------------
+; PROGRAM END
+; -----------------------------------------------
+ end
diff --git a/demo/mleddisplay.bin b/demo/mleddisplay.bin
new file mode 100644
index 0000000..18d8eb4
--- /dev/null
+++ b/demo/mleddisplay.bin
Binary files differ
diff --git a/demo/mleddisplay.hex b/demo/mleddisplay.hex
new file mode 100644
index 0000000..abf8563
--- /dev/null
+++ b/demo/mleddisplay.hex
@@ -0,0 +1,2 @@
+:4B00000002002506B60A09760008B824012211032218E5F003F5F0E69375B0FFF59085F0B0B820ED2275200075210075220075230075F0EE90004178241111782011030137C0F9A4B0999282F8809027
+:00000001FF \ No newline at end of file
diff --git a/demo/mleddisplay.lst b/demo/mleddisplay.lst
new file mode 100644
index 0000000..f87d046
--- /dev/null
+++ b/demo/mleddisplay.lst
@@ -0,0 +1,316 @@
+mleddisplay PAGE 1
+ 1 ; Demonstration code for MCU 8051 IDE
+ 2 ;
+ 3 ; Load virtual HW from "mleddisplay.vhc"
+ 4 ; and press F2 and F6
+ 5 ;
+ 6 ; It should increment 4 digit number displayed
+ 7 ; on multiplexed LED display
+ 8
+ 9
+ 10 ; -----------------------------------------------
+ 11 ; CONSTANTS
+ 12 ; -----------------------------------------------
+ 13
+ 0020 14 data_ptr data 20h ; Number to display
+ 0004 15 data_len equ 4h ; Number of digits
+ 16
+ 17 ;; Codes for 8-segment LED display
+ 18 ; They can be easily determinated with
+ 19 ; 8-segment editor ( [Main menu] - >
+ 20 ; [Utilities] -> [8-segment editor] )
+0041 C0 21 numbers:db 11000000b ; 0
+0042 F9 22 db 11111001b ; 1
+0043 A4 23 db 10100100b ; 2
+0044 B0 24 db 10110000b ; 3
+0045 99 25 db 10011001b ; 4
+0046 92 26 db 10010010b ; 5
+0047 82 27 db 10000010b ; 6
+0048 F8 28 db 11111000b ; 7
+0049 80 29 db 10000000b ; 8
+004A 90 30 db 10010000b ; 9
+ 31
+ 32 ; -----------------------------------------------
+ 33 ; VECTORS
+ 34 ; -----------------------------------------------
+ 35 ; Reset vector
+ 36 org 0
+0000 06 37 jmp start
+ 38
+ 39 ; -----------------------------------------------
+ 40 ; SUBPROGRAMS
+ 41 ; -----------------------------------------------
+ 42
+ 43 ;; Increment the number
+ 44 ;
+ 45 ; R0 must be set to data_ptr before call
+ 46 ;
+ 47 ; Affected registers: R0
+ 48 ; Interrupts: None
+ 49 ; Notes: Recursive subprogram
+ 50 inrement_number:
+0003 B60A09 51 inc @R0
+0004 7600 52 cjne @R0, #0Ah, inc_num_end
+ 53
+0007 08 54 mov @R0, #0
+0009 B82401 55 inc R0
+000A 22 56 cjne R0, #data_ptr+data_len, $+4
+ 57 ret
+000E 0137 58 call inrement_number
+ 59 inc_num_end:
+0010 7820 60 ret
+ 61
+ 62 ;; Display the number on the LED display
+ 63 ;
+ 64 ; DPTR must point to table numbers
+ 65 ; R0 must contain (data_ptr+data_len)
+ 66 ;
+ 67 ; Affected registers: A, B, R0, P1, P3
+ 68 ; Interrupts: None
+ 69 ; Notes: Uses DPTR
+ 70 display_number:
+ 71 ; Select digit to display
+0011 18 72 dec R0 ; In uC
+0012 E5F0 73 mov A, B
+0014 03 74 rr A
+0015 F5F0 75 mov B, A
+ 76
+ 77 ; Translate the digit to binary
+ 78 ; representation for the LED display
+0017 E6 79 mov A, @R0
+0018 93 80 movc A, @A+DPTR
+ 81
+ 82 ; Display the digit on the display
+0019 75B0FF 83 mov P3, #0ffh
+001C F590 84 mov P1, A
+001E 85F0B0 85 mov P3, B
+ 86
+ 87 ; Display next digit
+0021 B820ED 88 cjne R0, #data_ptr, display_number
+0024 22 89 ret
+ 90
+ 91 ; -----------------------------------------------
+ 92 ; PROGRAM START
+ 93 ; -----------------------------------------------
+ 94 start:
+ 95 ; Data to zeroes
+0025 752000 96 mov data_ptr+0, #0h ; left-most
+0028 752100 97 mov data_ptr+1, #0h
+002B 752200 98 mov data_ptr+2, #0h
+002E 752300 99 mov data_ptr+3, #0h ; right-most
+ 100
+ 101 ; Address 1st number on the display
+0031 75F0EE 102 mov B, #0EEh
+ 103 ; Initialize DPTR (Data PoinTeR)
+0034 900041 104 mov DPTR, #numbers
+ 105
+ 106 ; -----------------------------------------------
+ 107 ; MAIN LOOP
+ 108 ; -----------------------------------------------
+ 109
+ 110 main:
+ 111 ; Show the number on the LED display
+0037 7824 112 mov R0, #data_ptr+data_len
+ 113 call display_number
+ 114
+ 115 ; Increment the number
+ 116 mov R0, #data_ptr
+ 117 call inrement_number
+ 118
+ 119 ; Close main loop
+ 120 jmp main
+ 121
+ 122 ; -----------------------------------------------
+ 123 ; PROGRAM END
+ 124 ; -----------------------------------------------
+ 125 end
+ASSEMBLY COMPLETE, NO ERRORS FOUND, NO WARNINGS
+
+
+SYMBOL TABLE:
+AC . . . . . . . . . . . . . . . . . B ADDR 00D6H NOT USED
+ACC. . . . . . . . . . . . . . . . . D ADDR 00E0H NOT USED
+ACSR . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+ADCF . . . . . . . . . . . . . . . . D ADDR 00F6H NOT USED
+ADCLK. . . . . . . . . . . . . . . . D ADDR 00F2H NOT USED
+ADCON. . . . . . . . . . . . . . . . D ADDR 00F3H NOT USED
+ADDH . . . . . . . . . . . . . . . . D ADDR 00F5H NOT USED
+ADDL . . . . . . . . . . . . . . . . D ADDR 00F4H NOT USED
+AUXR . . . . . . . . . . . . . . . . D ADDR 008EH NOT USED
+AUXR1. . . . . . . . . . . . . . . . D ADDR 00A2H NOT USED
+B. . . . . . . . . . . . . . . . . . D ADDR 00F0H
+BDRCON . . . . . . . . . . . . . . . D ADDR 009BH NOT USED
+BDRCON_1 . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+BRL. . . . . . . . . . . . . . . . . D ADDR 009AH NOT USED
+CCAP0H . . . . . . . . . . . . . . . D ADDR 00FAH NOT USED
+CCAP0L . . . . . . . . . . . . . . . D ADDR 00EAH NOT USED
+CCAP1H . . . . . . . . . . . . . . . D ADDR 00FBH NOT USED
+CCAP1L . . . . . . . . . . . . . . . D ADDR 00EBH NOT USED
+CCAP2H . . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAP3H . . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAP4H . . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL2H. . . . . . . . . . . . . . . D ADDR 00FCH NOT USED
+CCAPL2L. . . . . . . . . . . . . . . D ADDR 00ECH NOT USED
+CCAPL3H. . . . . . . . . . . . . . . D ADDR 00FDH NOT USED
+CCAPL3L. . . . . . . . . . . . . . . D ADDR 00EDH NOT USED
+CCAPL4H. . . . . . . . . . . . . . . D ADDR 00FEH NOT USED
+CCAPL4L. . . . . . . . . . . . . . . D ADDR 00EEH NOT USED
+CCAPM0 . . . . . . . . . . . . . . . D ADDR 00DAH NOT USED
+CCAPM1 . . . . . . . . . . . . . . . D ADDR 00DBH NOT USED
+CCAPM2 . . . . . . . . . . . . . . . D ADDR 00DCH NOT USED
+CCAPM3 . . . . . . . . . . . . . . . D ADDR 00DDH NOT USED
+CCAPM4 . . . . . . . . . . . . . . . D ADDR 00DEH NOT USED
+CCF0 . . . . . . . . . . . . . . . . B ADDR 00D8H NOT USED
+CCF1 . . . . . . . . . . . . . . . . B ADDR 00D9H NOT USED
+CCF2 . . . . . . . . . . . . . . . . B ADDR 00DAH NOT USED
+CCF3 . . . . . . . . . . . . . . . . B ADDR 00DBH NOT USED
+CCF4 . . . . . . . . . . . . . . . . B ADDR 00DCH NOT USED
+CCON . . . . . . . . . . . . . . . . D ADDR 00D8H NOT USED
+CFINT. . . . . . . . . . . . . . . . C ADDR 0033H NOT USED
+CH . . . . . . . . . . . . . . . . . D ADDR 00F9H NOT USED
+CKCON. . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKCON0 . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CKRL . . . . . . . . . . . . . . . . D ADDR 0097H NOT USED
+CKSEL. . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+CL . . . . . . . . . . . . . . . . . D ADDR 00E9H NOT USED
+CLKREG . . . . . . . . . . . . . . . D ADDR 008FH NOT USED
+CMOD . . . . . . . . . . . . . . . . D ADDR 00D9H NOT USED
+CPRL2. . . . . . . . . . . . . . . . B ADDR 00C8H NOT USED
+CR . . . . . . . . . . . . . . . . . B ADDR 00DEH NOT USED
+CT2. . . . . . . . . . . . . . . . . B ADDR 00C9H NOT USED
+CY . . . . . . . . . . . . . . . . . B ADDR 00D7H NOT USED
+DATA_LEN . . . . . . . . . . . . . . N NUMB 0004H NOT USED
+DATA_PTR . . . . . . . . . . . . . . D ADDR 0020H
+DISPLAY_NUMBER . . . . . . . . . . . C ADDR 0011H
+DP0H . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DP0L . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+DP1H . . . . . . . . . . . . . . . . D ADDR 0085H NOT USED
+DP1L . . . . . . . . . . . . . . . . D ADDR 0084H NOT USED
+DPH. . . . . . . . . . . . . . . . . D ADDR 0083H NOT USED
+DPL. . . . . . . . . . . . . . . . . D ADDR 0082H NOT USED
+EA . . . . . . . . . . . . . . . . . B ADDR 00AFH NOT USED
+EC . . . . . . . . . . . . . . . . . B ADDR 00AEH NOT USED
+EECON. . . . . . . . . . . . . . . . D ADDR 0096H NOT USED
+ES . . . . . . . . . . . . . . . . . B ADDR 00ACH NOT USED
+ET0. . . . . . . . . . . . . . . . . B ADDR 00A9H NOT USED
+ET1. . . . . . . . . . . . . . . . . B ADDR 00ABH NOT USED
+ET2. . . . . . . . . . . . . . . . . B ADDR 00ADH NOT USED
+EX0. . . . . . . . . . . . . . . . . B ADDR 00A8H NOT USED
+EX1. . . . . . . . . . . . . . . . . B ADDR 00AAH NOT USED
+EXEN2. . . . . . . . . . . . . . . . B ADDR 00CBH NOT USED
+EXF2 . . . . . . . . . . . . . . . . B ADDR 00CEH NOT USED
+EXTI0. . . . . . . . . . . . . . . . C ADDR 0003H NOT USED
+EXTI1. . . . . . . . . . . . . . . . C ADDR 0013H NOT USED
+F0 . . . . . . . . . . . . . . . . . B ADDR 00D5H NOT USED
+FE . . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+IE . . . . . . . . . . . . . . . . . D ADDR 00A8H NOT USED
+IE0. . . . . . . . . . . . . . . . . B ADDR 0089H NOT USED
+IE1. . . . . . . . . . . . . . . . . B ADDR 008BH NOT USED
+INC_NUM_END. . . . . . . . . . . . . C ADDR 0010H
+INREMENT_NUMBER. . . . . . . . . . . C ADDR 0003H
+INT0 . . . . . . . . . . . . . . . . B ADDR 00B2H NOT USED
+INT1 . . . . . . . . . . . . . . . . B ADDR 00B3H NOT USED
+IP . . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPH. . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH0 . . . . . . . . . . . . . . . . D ADDR 00B7H NOT USED
+IPH1 . . . . . . . . . . . . . . . . D ADDR 00B3H NOT USED
+IPL0 . . . . . . . . . . . . . . . . D ADDR 00B8H NOT USED
+IPL1 . . . . . . . . . . . . . . . . D ADDR 00B2H NOT USED
+IT0. . . . . . . . . . . . . . . . . B ADDR 0088H NOT USED
+IT1. . . . . . . . . . . . . . . . . B ADDR 008AH NOT USED
+KBE. . . . . . . . . . . . . . . . . D ADDR 009DH NOT USED
+KBF. . . . . . . . . . . . . . . . . D ADDR 009EH NOT USED
+KBLS . . . . . . . . . . . . . . . . D ADDR 009CH NOT USED
+MAIN . . . . . . . . . . . . . . . . C ADDR 0037H
+NUMBERS. . . . . . . . . . . . . . . C ADDR 0041H
+OSCCON . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+OV . . . . . . . . . . . . . . . . . B ADDR 00D2H NOT USED
+P. . . . . . . . . . . . . . . . . . B ADDR 00D0H NOT USED
+P0 . . . . . . . . . . . . . . . . . D ADDR 0080H NOT USED
+P1 . . . . . . . . . . . . . . . . . D ADDR 0090H
+P1M1 . . . . . . . . . . . . . . . . D ADDR 00D4H NOT USED
+P1M2 . . . . . . . . . . . . . . . . D ADDR 00E2H NOT USED
+P2 . . . . . . . . . . . . . . . . . D ADDR 00A0H NOT USED
+P3 . . . . . . . . . . . . . . . . . D ADDR 00B0H
+P3M1 . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+P3M2 . . . . . . . . . . . . . . . . D ADDR 00E3H NOT USED
+P4 . . . . . . . . . . . . . . . . . D ADDR 00C0H NOT USED
+P4M1 . . . . . . . . . . . . . . . . D ADDR 00D6H NOT USED
+P4M2 . . . . . . . . . . . . . . . . D ADDR 00E4H NOT USED
+P5 . . . . . . . . . . . . . . . . . D ADDR 00E8H NOT USED
+PC . . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PCON . . . . . . . . . . . . . . . . D ADDR 0087H NOT USED
+PPCL . . . . . . . . . . . . . . . . B ADDR 00BEH NOT USED
+PS . . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSL. . . . . . . . . . . . . . . . . B ADDR 00BCH NOT USED
+PSW. . . . . . . . . . . . . . . . . D ADDR 00D0H NOT USED
+PT0. . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT0L . . . . . . . . . . . . . . . . B ADDR 00B9H NOT USED
+PT1. . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT1L . . . . . . . . . . . . . . . . B ADDR 00BBH NOT USED
+PT2. . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PT2L . . . . . . . . . . . . . . . . B ADDR 00BDH NOT USED
+PX0. . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX0L . . . . . . . . . . . . . . . . B ADDR 00B8H NOT USED
+PX1. . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+PX1L . . . . . . . . . . . . . . . . B ADDR 00BAH NOT USED
+RB8. . . . . . . . . . . . . . . . . B ADDR 009AH NOT USED
+RCAP2H . . . . . . . . . . . . . . . D ADDR 00CBH NOT USED
+RCAP2L . . . . . . . . . . . . . . . D ADDR 00CAH NOT USED
+RCLK . . . . . . . . . . . . . . . . B ADDR 00CDH NOT USED
+RD . . . . . . . . . . . . . . . . . B ADDR 00B7H NOT USED
+REN. . . . . . . . . . . . . . . . . B ADDR 009CH NOT USED
+RESET. . . . . . . . . . . . . . . . C ADDR 0000H NOT USED
+RI . . . . . . . . . . . . . . . . . B ADDR 0098H NOT USED
+RS0. . . . . . . . . . . . . . . . . B ADDR 00D3H NOT USED
+RS1. . . . . . . . . . . . . . . . . B ADDR 00D4H NOT USED
+RXD. . . . . . . . . . . . . . . . . B ADDR 00B0H NOT USED
+SADDR. . . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_0. . . . . . . . . . . . . . . D ADDR 00A9H NOT USED
+SADDR_1. . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SADEN. . . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_0. . . . . . . . . . . . . . . D ADDR 00B9H NOT USED
+SADEN_1. . . . . . . . . . . . . . . D ADDR 00BAH NOT USED
+SBUF . . . . . . . . . . . . . . . . D ADDR 0099H NOT USED
+SCON . . . . . . . . . . . . . . . . D ADDR 0098H NOT USED
+SINT . . . . . . . . . . . . . . . . C ADDR 0023H NOT USED
+SM0. . . . . . . . . . . . . . . . . B ADDR 009FH NOT USED
+SM1. . . . . . . . . . . . . . . . . B ADDR 009EH NOT USED
+SM2. . . . . . . . . . . . . . . . . B ADDR 009DH NOT USED
+SP . . . . . . . . . . . . . . . . . D ADDR 0081H NOT USED
+SPCON. . . . . . . . . . . . . . . . D ADDR 00C3H NOT USED
+SPCR . . . . . . . . . . . . . . . . D ADDR 00D5H NOT USED
+SPDAT. . . . . . . . . . . . . . . . D ADDR 00C5H NOT USED
+SPDR . . . . . . . . . . . . . . . . D ADDR 0086H NOT USED
+SPSR . . . . . . . . . . . . . . . . D ADDR 00AAH NOT USED
+SPSTA. . . . . . . . . . . . . . . . D ADDR 00C4H NOT USED
+START. . . . . . . . . . . . . . . . C ADDR 0025H
+T0 . . . . . . . . . . . . . . . . . B ADDR 00B4H NOT USED
+T1 . . . . . . . . . . . . . . . . . B ADDR 00B5H NOT USED
+T2CON. . . . . . . . . . . . . . . . D ADDR 00C8H NOT USED
+T2MOD. . . . . . . . . . . . . . . . D ADDR 00C9H NOT USED
+TB8. . . . . . . . . . . . . . . . . B ADDR 009BH NOT USED
+TCLK . . . . . . . . . . . . . . . . B ADDR 00CCH NOT USED
+TCON . . . . . . . . . . . . . . . . D ADDR 0088H NOT USED
+TF0. . . . . . . . . . . . . . . . . B ADDR 008DH NOT USED
+TF1. . . . . . . . . . . . . . . . . B ADDR 008FH NOT USED
+TF2. . . . . . . . . . . . . . . . . B ADDR 00CFH NOT USED
+TH0. . . . . . . . . . . . . . . . . D ADDR 008CH NOT USED
+TH1. . . . . . . . . . . . . . . . . D ADDR 008DH NOT USED
+TH2. . . . . . . . . . . . . . . . . D ADDR 00CDH NOT USED
+TI . . . . . . . . . . . . . . . . . B ADDR 0099H NOT USED
+TIMER0 . . . . . . . . . . . . . . . C ADDR 000BH NOT USED
+TIMER1 . . . . . . . . . . . . . . . C ADDR 001BH NOT USED
+TIMER2 . . . . . . . . . . . . . . . C ADDR 002BH NOT USED
+TL0. . . . . . . . . . . . . . . . . D ADDR 008AH NOT USED
+TL1. . . . . . . . . . . . . . . . . D ADDR 008BH NOT USED
+TL2. . . . . . . . . . . . . . . . . D ADDR 00CCH NOT USED
+TMOD . . . . . . . . . . . . . . . . D ADDR 0089H NOT USED
+TR0. . . . . . . . . . . . . . . . . B ADDR 008CH NOT USED
+TR1. . . . . . . . . . . . . . . . . B ADDR 008EH NOT USED
+TR2. . . . . . . . . . . . . . . . . B ADDR 00CAH NOT USED
+TXD. . . . . . . . . . . . . . . . . B ADDR 00B1H NOT USED
+WDTCON . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTPRG . . . . . . . . . . . . . . . D ADDR 00A7H NOT USED
+WDTRST . . . . . . . . . . . . . . . D ADDR 00A6H NOT USED
+WR . . . . . . . . . . . . . . . . . B ADDR 00B6H NOT USED \ No newline at end of file
diff --git a/demo/mleddisplay.vhw b/demo/mleddisplay.vhw
new file mode 100644
index 0000000..ecdf182
--- /dev/null
+++ b/demo/mleddisplay.vhw
@@ -0,0 +1,5 @@
+# MCU 8051 IDE: Virtual HW configuration file
+# Date: 05/10/2010
+# Project: Demo-project
+
+MultiplexedLedDisplay {{0 1 1 1 2 1 3 1 4 1 T0 3 5 1 T1 3 6 1 T2 3 7 1 T3 3} {0 7 1 6 2 5 3 4 4 3 T0 7 5 2 T1 6 6 1 T2 5 7 0 T3 4} 425x225+850+345 {Demo for "leddisplay.asm"} red 50 1}
diff --git a/doc/man/mcu8051ide.1.gz b/doc/man/mcu8051ide.1.gz
new file mode 100644
index 0000000..0e507fc
--- /dev/null
+++ b/doc/man/mcu8051ide.1.gz
Binary files differ
diff --git a/icons/16x16/1downarrow.png b/icons/16x16/1downarrow.png
new file mode 100644
index 0000000..5829fe4
--- /dev/null
+++ b/icons/16x16/1downarrow.png
Binary files differ
diff --git a/icons/16x16/1leftarrow.png b/icons/16x16/1leftarrow.png
new file mode 100644
index 0000000..dd35e73
--- /dev/null
+++ b/icons/16x16/1leftarrow.png
Binary files differ
diff --git a/icons/16x16/1rightarrow.png b/icons/16x16/1rightarrow.png
new file mode 100644
index 0000000..c2673b1
--- /dev/null
+++ b/icons/16x16/1rightarrow.png
Binary files differ
diff --git a/icons/16x16/1uparrow.png b/icons/16x16/1uparrow.png
new file mode 100644
index 0000000..3b7c03d
--- /dev/null
+++ b/icons/16x16/1uparrow.png
Binary files differ
diff --git a/icons/16x16/2_rightarrow.png b/icons/16x16/2_rightarrow.png
new file mode 100644
index 0000000..c41265b
--- /dev/null
+++ b/icons/16x16/2_rightarrow.png
Binary files differ
diff --git a/icons/16x16/2downarrow.png b/icons/16x16/2downarrow.png
new file mode 100644
index 0000000..ab2a8c0
--- /dev/null
+++ b/icons/16x16/2downarrow.png
Binary files differ
diff --git a/icons/16x16/2leftarrow.png b/icons/16x16/2leftarrow.png
new file mode 100644
index 0000000..78eae05
--- /dev/null
+++ b/icons/16x16/2leftarrow.png
Binary files differ
diff --git a/icons/16x16/2rightarrow.png b/icons/16x16/2rightarrow.png
new file mode 100644
index 0000000..9d40536
--- /dev/null
+++ b/icons/16x16/2rightarrow.png
Binary files differ
diff --git a/icons/16x16/2uparrow.png b/icons/16x16/2uparrow.png
new file mode 100644
index 0000000..253b1de
--- /dev/null
+++ b/icons/16x16/2uparrow.png
Binary files differ
diff --git a/icons/16x16/8seg.png b/icons/16x16/8seg.png
new file mode 100644
index 0000000..4281704
--- /dev/null
+++ b/icons/16x16/8seg.png
Binary files differ
diff --git a/icons/16x16/_1downarrow.png b/icons/16x16/_1downarrow.png
new file mode 100644
index 0000000..3da291d
--- /dev/null
+++ b/icons/16x16/_1downarrow.png
Binary files differ
diff --git a/icons/16x16/_1uparrow.png b/icons/16x16/_1uparrow.png
new file mode 100644
index 0000000..ad1047d
--- /dev/null
+++ b/icons/16x16/_1uparrow.png
Binary files differ
diff --git a/icons/16x16/_blockdevice.png b/icons/16x16/_blockdevice.png
new file mode 100644
index 0000000..a4acb09
--- /dev/null
+++ b/icons/16x16/_blockdevice.png
Binary files differ
diff --git a/icons/16x16/add.png b/icons/16x16/add.png
new file mode 100644
index 0000000..ee0ba46
--- /dev/null
+++ b/icons/16x16/add.png
Binary files differ
diff --git a/icons/16x16/amber_dot.png b/icons/16x16/amber_dot.png
new file mode 100644
index 0000000..c7d1383
--- /dev/null
+++ b/icons/16x16/amber_dot.png
Binary files differ
diff --git a/icons/16x16/arr.png b/icons/16x16/arr.png
new file mode 100644
index 0000000..47603fb
--- /dev/null
+++ b/icons/16x16/arr.png
Binary files differ
diff --git a/icons/16x16/ascii.png b/icons/16x16/ascii.png
new file mode 100644
index 0000000..d662de4
--- /dev/null
+++ b/icons/16x16/ascii.png
Binary files differ
diff --git a/icons/16x16/asm.png b/icons/16x16/asm.png
new file mode 100644
index 0000000..96b386f
--- /dev/null
+++ b/icons/16x16/asm.png
Binary files differ
diff --git a/icons/16x16/back.png b/icons/16x16/back.png
new file mode 100644
index 0000000..1404236
--- /dev/null
+++ b/icons/16x16/back.png
Binary files differ
diff --git a/icons/16x16/bar5.png b/icons/16x16/bar5.png
new file mode 100644
index 0000000..8ea3b27
--- /dev/null
+++ b/icons/16x16/bar5.png
Binary files differ
diff --git a/icons/16x16/bh.png b/icons/16x16/bh.png
new file mode 100644
index 0000000..a8807dc
--- /dev/null
+++ b/icons/16x16/bh.png
Binary files differ
diff --git a/icons/16x16/blockdevice.png b/icons/16x16/blockdevice.png
new file mode 100644
index 0000000..0567c72
--- /dev/null
+++ b/icons/16x16/blockdevice.png
Binary files differ
diff --git a/icons/16x16/bm_ex.png b/icons/16x16/bm_ex.png
new file mode 100644
index 0000000..792b479
--- /dev/null
+++ b/icons/16x16/bm_ex.png
Binary files differ
diff --git a/icons/16x16/bookmark.png b/icons/16x16/bookmark.png
new file mode 100644
index 0000000..5e76158
--- /dev/null
+++ b/icons/16x16/bookmark.png
Binary files differ
diff --git a/icons/16x16/bookmark_add.png b/icons/16x16/bookmark_add.png
new file mode 100644
index 0000000..e1d093a
--- /dev/null
+++ b/icons/16x16/bookmark_add.png
Binary files differ
diff --git a/icons/16x16/bookmark_toolbar.png b/icons/16x16/bookmark_toolbar.png
new file mode 100644
index 0000000..fdf17ca
--- /dev/null
+++ b/icons/16x16/bookmark_toolbar.png
Binary files differ
diff --git a/icons/16x16/bottom.png b/icons/16x16/bottom.png
new file mode 100644
index 0000000..8f21884
--- /dev/null
+++ b/icons/16x16/bottom.png
Binary files differ
diff --git a/icons/16x16/bottom1.png b/icons/16x16/bottom1.png
new file mode 100644
index 0000000..1089f50
--- /dev/null
+++ b/icons/16x16/bottom1.png
Binary files differ
diff --git a/icons/16x16/bug.png b/icons/16x16/bug.png
new file mode 100644
index 0000000..827d5f8
--- /dev/null
+++ b/icons/16x16/bug.png
Binary files differ
diff --git a/icons/16x16/button_cancel.png b/icons/16x16/button_cancel.png
new file mode 100644
index 0000000..f9e820e
--- /dev/null
+++ b/icons/16x16/button_cancel.png
Binary files differ
diff --git a/icons/16x16/camera_test.png b/icons/16x16/camera_test.png
new file mode 100644
index 0000000..22ce9df
--- /dev/null
+++ b/icons/16x16/camera_test.png
Binary files differ
diff --git a/icons/16x16/cancel.png b/icons/16x16/cancel.png
new file mode 100644
index 0000000..6b990a2
--- /dev/null
+++ b/icons/16x16/cancel.png
Binary files differ
diff --git a/icons/16x16/change_case.png b/icons/16x16/change_case.png
new file mode 100644
index 0000000..df16e8b
--- /dev/null
+++ b/icons/16x16/change_case.png
Binary files differ
diff --git a/icons/16x16/chardevice.png b/icons/16x16/chardevice.png
new file mode 100644
index 0000000..3b82c19
--- /dev/null
+++ b/icons/16x16/chardevice.png
Binary files differ
diff --git a/icons/16x16/clear_left.png b/icons/16x16/clear_left.png
new file mode 100644
index 0000000..ea11a3e
--- /dev/null
+++ b/icons/16x16/clear_left.png
Binary files differ
diff --git a/icons/16x16/clear_left_r.png b/icons/16x16/clear_left_r.png
new file mode 100644
index 0000000..60e1cf0
--- /dev/null
+++ b/icons/16x16/clear_left_r.png
Binary files differ
diff --git a/icons/16x16/colorize.png b/icons/16x16/colorize.png
new file mode 100644
index 0000000..9612cd5
--- /dev/null
+++ b/icons/16x16/colorize.png
Binary files differ
diff --git a/icons/16x16/compfile.png b/icons/16x16/compfile.png
new file mode 100644
index 0000000..ee27f35
--- /dev/null
+++ b/icons/16x16/compfile.png
Binary files differ
diff --git a/icons/16x16/compfile_this.png b/icons/16x16/compfile_this.png
new file mode 100644
index 0000000..de0efc6
--- /dev/null
+++ b/icons/16x16/compfile_this.png
Binary files differ
diff --git a/icons/16x16/configure.png b/icons/16x16/configure.png
new file mode 100644
index 0000000..95bd319
--- /dev/null
+++ b/icons/16x16/configure.png
Binary files differ
diff --git a/icons/16x16/configure_shortcuts.png b/icons/16x16/configure_shortcuts.png
new file mode 100644
index 0000000..47d469e
--- /dev/null
+++ b/icons/16x16/configure_shortcuts.png
Binary files differ
diff --git a/icons/16x16/configure_toolbars.png b/icons/16x16/configure_toolbars.png
new file mode 100644
index 0000000..653479b
--- /dev/null
+++ b/icons/16x16/configure_toolbars.png
Binary files differ
diff --git a/icons/16x16/contents.png b/icons/16x16/contents.png
new file mode 100644
index 0000000..e2a44ec
--- /dev/null
+++ b/icons/16x16/contents.png
Binary files differ
diff --git a/icons/16x16/corner.png b/icons/16x16/corner.png
new file mode 100644
index 0000000..c9255fd
--- /dev/null
+++ b/icons/16x16/corner.png
Binary files differ
diff --git a/icons/16x16/diode.png b/icons/16x16/diode.png
new file mode 100644
index 0000000..058f0c0
--- /dev/null
+++ b/icons/16x16/diode.png
Binary files differ
diff --git a/icons/16x16/disasm.png b/icons/16x16/disasm.png
new file mode 100644
index 0000000..7e23538
--- /dev/null
+++ b/icons/16x16/disasm.png
Binary files differ
diff --git a/icons/16x16/dot.png b/icons/16x16/dot.png
new file mode 100644
index 0000000..3d7e6eb
--- /dev/null
+++ b/icons/16x16/dot.png
Binary files differ
diff --git a/icons/16x16/dot_g.png b/icons/16x16/dot_g.png
new file mode 100644
index 0000000..d85393c
--- /dev/null
+++ b/icons/16x16/dot_g.png
Binary files differ
diff --git a/icons/16x16/dot_r.png b/icons/16x16/dot_r.png
new file mode 100644
index 0000000..1f14e6d
--- /dev/null
+++ b/icons/16x16/dot_r.png
Binary files differ
diff --git a/icons/16x16/down.png b/icons/16x16/down.png
new file mode 100644
index 0000000..697fc98
--- /dev/null
+++ b/icons/16x16/down.png
Binary files differ
diff --git a/icons/16x16/down0.png b/icons/16x16/down0.png
new file mode 100644
index 0000000..a526541
--- /dev/null
+++ b/icons/16x16/down0.png
Binary files differ
diff --git a/icons/16x16/edit.png b/icons/16x16/edit.png
new file mode 100644
index 0000000..fc9884b
--- /dev/null
+++ b/icons/16x16/edit.png
Binary files differ
diff --git a/icons/16x16/editclear.png b/icons/16x16/editclear.png
new file mode 100644
index 0000000..4624840
--- /dev/null
+++ b/icons/16x16/editclear.png
Binary files differ
diff --git a/icons/16x16/editcopy.png b/icons/16x16/editcopy.png
new file mode 100644
index 0000000..c3ff243
--- /dev/null
+++ b/icons/16x16/editcopy.png
Binary files differ
diff --git a/icons/16x16/editcut.png b/icons/16x16/editcut.png
new file mode 100644
index 0000000..7ec355a
--- /dev/null
+++ b/icons/16x16/editcut.png
Binary files differ
diff --git a/icons/16x16/editdelete.png b/icons/16x16/editdelete.png
new file mode 100644
index 0000000..6d0d29d
--- /dev/null
+++ b/icons/16x16/editdelete.png
Binary files differ
diff --git a/icons/16x16/editpaste.png b/icons/16x16/editpaste.png
new file mode 100644
index 0000000..f6a1db8
--- /dev/null
+++ b/icons/16x16/editpaste.png
Binary files differ
diff --git a/icons/16x16/emacs.png b/icons/16x16/emacs.png
new file mode 100644
index 0000000..77c1a66
--- /dev/null
+++ b/icons/16x16/emacs.png
Binary files differ
diff --git a/icons/16x16/emptytrash.png b/icons/16x16/emptytrash.png
new file mode 100644
index 0000000..f5cb2b8
--- /dev/null
+++ b/icons/16x16/emptytrash.png
Binary files differ
diff --git a/icons/16x16/eraser.png b/icons/16x16/eraser.png
new file mode 100644
index 0000000..459d28a
--- /dev/null
+++ b/icons/16x16/eraser.png
Binary files differ
diff --git a/icons/16x16/exclamation.png b/icons/16x16/exclamation.png
new file mode 100644
index 0000000..d9929ab
--- /dev/null
+++ b/icons/16x16/exclamation.png
Binary files differ
diff --git a/icons/16x16/exec.png b/icons/16x16/exec.png
new file mode 100644
index 0000000..fc14700
--- /dev/null
+++ b/icons/16x16/exec.png
Binary files differ
diff --git a/icons/16x16/exit.png b/icons/16x16/exit.png
new file mode 100644
index 0000000..a77152b
--- /dev/null
+++ b/icons/16x16/exit.png
Binary files differ
diff --git a/icons/16x16/fileclose.png b/icons/16x16/fileclose.png
new file mode 100644
index 0000000..edf5f76
--- /dev/null
+++ b/icons/16x16/fileclose.png
Binary files differ
diff --git a/icons/16x16/filefind.png b/icons/16x16/filefind.png
new file mode 100644
index 0000000..42aae04
--- /dev/null
+++ b/icons/16x16/filefind.png
Binary files differ
diff --git a/icons/16x16/fileimport.png b/icons/16x16/fileimport.png
new file mode 100644
index 0000000..32baf9c
--- /dev/null
+++ b/icons/16x16/fileimport.png
Binary files differ
diff --git a/icons/16x16/filenew.png b/icons/16x16/filenew.png
new file mode 100644
index 0000000..84c4071
--- /dev/null
+++ b/icons/16x16/filenew.png
Binary files differ
diff --git a/icons/16x16/fileopen.png b/icons/16x16/fileopen.png
new file mode 100644
index 0000000..037c2da
--- /dev/null
+++ b/icons/16x16/fileopen.png
Binary files differ
diff --git a/icons/16x16/filesave.png b/icons/16x16/filesave.png
new file mode 100644
index 0000000..41b3f43
--- /dev/null
+++ b/icons/16x16/filesave.png
Binary files differ
diff --git a/icons/16x16/filesaveas.png b/icons/16x16/filesaveas.png
new file mode 100644
index 0000000..3e28d5d
--- /dev/null
+++ b/icons/16x16/filesaveas.png
Binary files differ
diff --git a/icons/16x16/filter.png b/icons/16x16/filter.png
new file mode 100644
index 0000000..83890a8
--- /dev/null
+++ b/icons/16x16/filter.png
Binary files differ
diff --git a/icons/16x16/find.png b/icons/16x16/find.png
new file mode 100644
index 0000000..f9451cc
--- /dev/null
+++ b/icons/16x16/find.png
Binary files differ
diff --git a/icons/16x16/flag.png b/icons/16x16/flag.png
new file mode 100644
index 0000000..be5f074
--- /dev/null
+++ b/icons/16x16/flag.png
Binary files differ
diff --git a/icons/16x16/folder_new.png b/icons/16x16/folder_new.png
new file mode 100644
index 0000000..130e35e
--- /dev/null
+++ b/icons/16x16/folder_new.png
Binary files differ
diff --git a/icons/16x16/forward.png b/icons/16x16/forward.png
new file mode 100644
index 0000000..aa24953
--- /dev/null
+++ b/icons/16x16/forward.png
Binary files differ
diff --git a/icons/16x16/fsview.png b/icons/16x16/fsview.png
new file mode 100644
index 0000000..71ccf0a
--- /dev/null
+++ b/icons/16x16/fsview.png
Binary files differ
diff --git a/icons/16x16/gear.png b/icons/16x16/gear.png
new file mode 100644
index 0000000..a88018c
--- /dev/null
+++ b/icons/16x16/gear.png
Binary files differ
diff --git a/icons/16x16/gear0.png b/icons/16x16/gear0.png
new file mode 100644
index 0000000..d919a13
--- /dev/null
+++ b/icons/16x16/gear0.png
Binary files differ
diff --git a/icons/16x16/gear1.png b/icons/16x16/gear1.png
new file mode 100644
index 0000000..24102ec
--- /dev/null
+++ b/icons/16x16/gear1.png
Binary files differ
diff --git a/icons/16x16/gear2.png b/icons/16x16/gear2.png
new file mode 100644
index 0000000..eb61084
--- /dev/null
+++ b/icons/16x16/gear2.png
Binary files differ
diff --git a/icons/16x16/gedit.png b/icons/16x16/gedit.png
new file mode 100644
index 0000000..9e2218d
--- /dev/null
+++ b/icons/16x16/gedit.png
Binary files differ
diff --git a/icons/16x16/gohome.png b/icons/16x16/gohome.png
new file mode 100644
index 0000000..090a36d
--- /dev/null
+++ b/icons/16x16/gohome.png
Binary files differ
diff --git a/icons/16x16/goto.png b/icons/16x16/goto.png
new file mode 100644
index 0000000..4553e30
--- /dev/null
+++ b/icons/16x16/goto.png
Binary files differ
diff --git a/icons/16x16/goto2.png b/icons/16x16/goto2.png
new file mode 100644
index 0000000..a8e61fa
--- /dev/null
+++ b/icons/16x16/goto2.png
Binary files differ
diff --git a/icons/16x16/graph.png b/icons/16x16/graph.png
new file mode 100644
index 0000000..291b342
--- /dev/null
+++ b/icons/16x16/graph.png
Binary files differ
diff --git a/icons/16x16/green_dot.png b/icons/16x16/green_dot.png
new file mode 100644
index 0000000..04dac15
--- /dev/null
+++ b/icons/16x16/green_dot.png
Binary files differ
diff --git a/icons/16x16/grid0.png b/icons/16x16/grid0.png
new file mode 100644
index 0000000..914538f
--- /dev/null
+++ b/icons/16x16/grid0.png
Binary files differ
diff --git a/icons/16x16/grid1.png b/icons/16x16/grid1.png
new file mode 100644
index 0000000..3f75503
--- /dev/null
+++ b/icons/16x16/grid1.png
Binary files differ
diff --git a/icons/16x16/grid2.png b/icons/16x16/grid2.png
new file mode 100644
index 0000000..ae65f4b
--- /dev/null
+++ b/icons/16x16/grid2.png
Binary files differ
diff --git a/icons/16x16/grid3.png b/icons/16x16/grid3.png
new file mode 100644
index 0000000..365e6c1
--- /dev/null
+++ b/icons/16x16/grid3.png
Binary files differ
diff --git a/icons/16x16/gvim.png b/icons/16x16/gvim.png
new file mode 100644
index 0000000..fd26de5
--- /dev/null
+++ b/icons/16x16/gvim.png
Binary files differ
diff --git a/icons/16x16/hb.png b/icons/16x16/hb.png
new file mode 100644
index 0000000..db8c800
--- /dev/null
+++ b/icons/16x16/hb.png
Binary files differ
diff --git a/icons/16x16/help.png b/icons/16x16/help.png
new file mode 100644
index 0000000..4ed65a9
--- /dev/null
+++ b/icons/16x16/help.png
Binary files differ
diff --git a/icons/16x16/hh.png b/icons/16x16/hh.png
new file mode 100644
index 0000000..84fcf65
--- /dev/null
+++ b/icons/16x16/hh.png
Binary files differ
diff --git a/icons/16x16/html.png b/icons/16x16/html.png
new file mode 100644
index 0000000..9e5bc52
--- /dev/null
+++ b/icons/16x16/html.png
Binary files differ
diff --git a/icons/16x16/indent.png b/icons/16x16/indent.png
new file mode 100644
index 0000000..ab7ee75
--- /dev/null
+++ b/icons/16x16/indent.png
Binary files differ
diff --git a/icons/16x16/info.png b/icons/16x16/info.png
new file mode 100644
index 0000000..0d826bb
--- /dev/null
+++ b/icons/16x16/info.png
Binary files differ
diff --git a/icons/16x16/kaboodleloop.png b/icons/16x16/kaboodleloop.png
new file mode 100644
index 0000000..4b9ceaa
--- /dev/null
+++ b/icons/16x16/kaboodleloop.png
Binary files differ
diff --git a/icons/16x16/kcmdevices.png b/icons/16x16/kcmdevices.png
new file mode 100644
index 0000000..64428e1
--- /dev/null
+++ b/icons/16x16/kcmdevices.png
Binary files differ
diff --git a/icons/16x16/kcmdf.png b/icons/16x16/kcmdf.png
new file mode 100644
index 0000000..7b966b6
--- /dev/null
+++ b/icons/16x16/kcmdf.png
Binary files differ
diff --git a/icons/16x16/kcmmemory.png b/icons/16x16/kcmmemory.png
new file mode 100644
index 0000000..6ddeddb
--- /dev/null
+++ b/icons/16x16/kcmmemory.png
Binary files differ
diff --git a/icons/16x16/kcmmemory_B.png b/icons/16x16/kcmmemory_B.png
new file mode 100644
index 0000000..775543a
--- /dev/null
+++ b/icons/16x16/kcmmemory_B.png
Binary files differ
diff --git a/icons/16x16/kcmmemory_BA.png b/icons/16x16/kcmmemory_BA.png
new file mode 100644
index 0000000..f3266de
--- /dev/null
+++ b/icons/16x16/kcmmemory_BA.png
Binary files differ
diff --git a/icons/16x16/kcmmemory_C.png b/icons/16x16/kcmmemory_C.png
new file mode 100644
index 0000000..0c2ad30
--- /dev/null
+++ b/icons/16x16/kcmmemory_C.png
Binary files differ
diff --git a/icons/16x16/kcmmemory_E.png b/icons/16x16/kcmmemory_E.png
new file mode 100644
index 0000000..f56f0e6
--- /dev/null
+++ b/icons/16x16/kcmmemory_E.png
Binary files differ
diff --git a/icons/16x16/kcmmemory_P.png b/icons/16x16/kcmmemory_P.png
new file mode 100644
index 0000000..1673c43
--- /dev/null
+++ b/icons/16x16/kcmmemory_P.png
Binary files differ
diff --git a/icons/16x16/kcmmemory_S.png b/icons/16x16/kcmmemory_S.png
new file mode 100644
index 0000000..ae3bd42
--- /dev/null
+++ b/icons/16x16/kcmmemory_S.png
Binary files differ
diff --git a/icons/16x16/kcmmemory_ST.png b/icons/16x16/kcmmemory_ST.png
new file mode 100644
index 0000000..979c293
--- /dev/null
+++ b/icons/16x16/kcmmemory_ST.png
Binary files differ
diff --git a/icons/16x16/kcmmemory_X.png b/icons/16x16/kcmmemory_X.png
new file mode 100644
index 0000000..e3a4730
--- /dev/null
+++ b/icons/16x16/kcmmemory_X.png
Binary files differ
diff --git a/icons/16x16/kcmpci.png b/icons/16x16/kcmpci.png
new file mode 100644
index 0000000..0ac401c
--- /dev/null
+++ b/icons/16x16/kcmpci.png
Binary files differ
diff --git a/icons/16x16/kcmsystem.png b/icons/16x16/kcmsystem.png
new file mode 100644
index 0000000..b97bfb4
--- /dev/null
+++ b/icons/16x16/kcmsystem.png
Binary files differ
diff --git a/icons/16x16/key_enter.png b/icons/16x16/key_enter.png
new file mode 100644
index 0000000..19041fb
--- /dev/null
+++ b/icons/16x16/key_enter.png
Binary files differ
diff --git a/icons/16x16/kservices.png b/icons/16x16/kservices.png
new file mode 100644
index 0000000..b0611ff
--- /dev/null
+++ b/icons/16x16/kservices.png
Binary files differ
diff --git a/icons/16x16/kwrite.png b/icons/16x16/kwrite.png
new file mode 100644
index 0000000..02464c2
--- /dev/null
+++ b/icons/16x16/kwrite.png
Binary files differ
diff --git a/icons/16x16/launch.png b/icons/16x16/launch.png
new file mode 100644
index 0000000..838c38b
--- /dev/null
+++ b/icons/16x16/launch.png
Binary files differ
diff --git a/icons/16x16/launch_this.png b/icons/16x16/launch_this.png
new file mode 100644
index 0000000..fad5d5f
--- /dev/null
+++ b/icons/16x16/launch_this.png
Binary files differ
diff --git a/icons/16x16/ledblue.png b/icons/16x16/ledblue.png
new file mode 100644
index 0000000..7aa0df9
--- /dev/null
+++ b/icons/16x16/ledblue.png
Binary files differ
diff --git a/icons/16x16/ledblue2.png b/icons/16x16/ledblue2.png
new file mode 100644
index 0000000..498705b
--- /dev/null
+++ b/icons/16x16/ledblue2.png
Binary files differ
diff --git a/icons/16x16/leddisplay.png b/icons/16x16/leddisplay.png
new file mode 100644
index 0000000..92e0fa0
--- /dev/null
+++ b/icons/16x16/leddisplay.png
Binary files differ
diff --git a/icons/16x16/ledgray.png b/icons/16x16/ledgray.png
new file mode 100644
index 0000000..8c87f9f
--- /dev/null
+++ b/icons/16x16/ledgray.png
Binary files differ
diff --git a/icons/16x16/ledgrayblue.png b/icons/16x16/ledgrayblue.png
new file mode 100644
index 0000000..4326059
--- /dev/null
+++ b/icons/16x16/ledgrayblue.png
Binary files differ
diff --git a/icons/16x16/ledgraygreen.png b/icons/16x16/ledgraygreen.png
new file mode 100644
index 0000000..c7d8b2a
--- /dev/null
+++ b/icons/16x16/ledgraygreen.png
Binary files differ
diff --git a/icons/16x16/ledgrayorange.png b/icons/16x16/ledgrayorange.png
new file mode 100644
index 0000000..ba54b8d
--- /dev/null
+++ b/icons/16x16/ledgrayorange.png
Binary files differ
diff --git a/icons/16x16/ledgraypurple.png b/icons/16x16/ledgraypurple.png
new file mode 100644
index 0000000..e506ab3
--- /dev/null
+++ b/icons/16x16/ledgraypurple.png
Binary files differ
diff --git a/icons/16x16/ledgrayred.png b/icons/16x16/ledgrayred.png
new file mode 100644
index 0000000..8dc2e68
--- /dev/null
+++ b/icons/16x16/ledgrayred.png
Binary files differ
diff --git a/icons/16x16/ledgrayyellow.png b/icons/16x16/ledgrayyellow.png
new file mode 100644
index 0000000..80805ff
--- /dev/null
+++ b/icons/16x16/ledgrayyellow.png
Binary files differ
diff --git a/icons/16x16/ledgreen.png b/icons/16x16/ledgreen.png
new file mode 100644
index 0000000..1e6896b
--- /dev/null
+++ b/icons/16x16/ledgreen.png
Binary files differ
diff --git a/icons/16x16/ledgreen2.png b/icons/16x16/ledgreen2.png
new file mode 100644
index 0000000..71e2171
--- /dev/null
+++ b/icons/16x16/ledgreen2.png
Binary files differ
diff --git a/icons/16x16/ledmatrix.png b/icons/16x16/ledmatrix.png
new file mode 100644
index 0000000..6d0260c
--- /dev/null
+++ b/icons/16x16/ledmatrix.png
Binary files differ
diff --git a/icons/16x16/ledorange.png b/icons/16x16/ledorange.png
new file mode 100644
index 0000000..321e837
--- /dev/null
+++ b/icons/16x16/ledorange.png
Binary files differ
diff --git a/icons/16x16/ledorange2.png b/icons/16x16/ledorange2.png
new file mode 100644
index 0000000..0d6ee64
--- /dev/null
+++ b/icons/16x16/ledorange2.png
Binary files differ
diff --git a/icons/16x16/ledpanel.png b/icons/16x16/ledpanel.png
new file mode 100644
index 0000000..53ca911
--- /dev/null
+++ b/icons/16x16/ledpanel.png
Binary files differ
diff --git a/icons/16x16/ledpurple.png b/icons/16x16/ledpurple.png
new file mode 100644
index 0000000..01fc32e
--- /dev/null
+++ b/icons/16x16/ledpurple.png
Binary files differ
diff --git a/icons/16x16/ledpurple2.png b/icons/16x16/ledpurple2.png
new file mode 100644
index 0000000..f7aa7f4
--- /dev/null
+++ b/icons/16x16/ledpurple2.png
Binary files differ
diff --git a/icons/16x16/ledred.png b/icons/16x16/ledred.png
new file mode 100644
index 0000000..448fc9f
--- /dev/null
+++ b/icons/16x16/ledred.png
Binary files differ
diff --git a/icons/16x16/ledred2.png b/icons/16x16/ledred2.png
new file mode 100644
index 0000000..45d68c1
--- /dev/null
+++ b/icons/16x16/ledred2.png
Binary files differ
diff --git a/icons/16x16/ledyellow.png b/icons/16x16/ledyellow.png
new file mode 100644
index 0000000..d5d2ef7
--- /dev/null
+++ b/icons/16x16/ledyellow.png
Binary files differ
diff --git a/icons/16x16/ledyellow2.png b/icons/16x16/ledyellow2.png
new file mode 100644
index 0000000..ef58c40
--- /dev/null
+++ b/icons/16x16/ledyellow2.png
Binary files differ
diff --git a/icons/16x16/left.png b/icons/16x16/left.png
new file mode 100644
index 0000000..d1b3f82
--- /dev/null
+++ b/icons/16x16/left.png
Binary files differ
diff --git a/icons/16x16/line.png b/icons/16x16/line.png
new file mode 100644
index 0000000..ecc8360
--- /dev/null
+++ b/icons/16x16/line.png
Binary files differ
diff --git a/icons/16x16/locationbar_erase.png b/icons/16x16/locationbar_erase.png
new file mode 100644
index 0000000..0fb00f9
--- /dev/null
+++ b/icons/16x16/locationbar_erase.png
Binary files differ
diff --git a/icons/16x16/lock.png b/icons/16x16/lock.png
new file mode 100644
index 0000000..945a6eb
--- /dev/null
+++ b/icons/16x16/lock.png
Binary files differ
diff --git a/icons/16x16/math_matrix.png b/icons/16x16/math_matrix.png
new file mode 100644
index 0000000..a0f17f6
--- /dev/null
+++ b/icons/16x16/math_matrix.png
Binary files differ
diff --git a/icons/16x16/matrix2.png b/icons/16x16/matrix2.png
new file mode 100644
index 0000000..9c1fa15
--- /dev/null
+++ b/icons/16x16/matrix2.png
Binary files differ
diff --git a/icons/16x16/matrixkeypad.png b/icons/16x16/matrixkeypad.png
new file mode 100644
index 0000000..5362afb
--- /dev/null
+++ b/icons/16x16/matrixkeypad.png
Binary files differ
diff --git a/icons/16x16/mcu8051ide.png b/icons/16x16/mcu8051ide.png
new file mode 100644
index 0000000..189e607
--- /dev/null
+++ b/icons/16x16/mcu8051ide.png
Binary files differ
diff --git a/icons/16x16/mleddisplay.png b/icons/16x16/mleddisplay.png
new file mode 100644
index 0000000..ffc3674
--- /dev/null
+++ b/icons/16x16/mleddisplay.png
Binary files differ
diff --git a/icons/16x16/mouse.png b/icons/16x16/mouse.png
new file mode 100644
index 0000000..84c7990
--- /dev/null
+++ b/icons/16x16/mouse.png
Binary files differ
diff --git a/icons/16x16/next.png b/icons/16x16/next.png
new file mode 100644
index 0000000..499ab70
--- /dev/null
+++ b/icons/16x16/next.png
Binary files differ
diff --git a/icons/16x16/no.png b/icons/16x16/no.png
new file mode 100644
index 0000000..4ffdef7
--- /dev/null
+++ b/icons/16x16/no.png
Binary files differ
diff --git a/icons/16x16/ok.png b/icons/16x16/ok.png
new file mode 100644
index 0000000..543710f
--- /dev/null
+++ b/icons/16x16/ok.png
Binary files differ
diff --git a/icons/16x16/oval.png b/icons/16x16/oval.png
new file mode 100644
index 0000000..b8a91d5
--- /dev/null
+++ b/icons/16x16/oval.png
Binary files differ
diff --git a/icons/16x16/pencil.png b/icons/16x16/pencil.png
new file mode 100644
index 0000000..acf8aae
--- /dev/null
+++ b/icons/16x16/pencil.png
Binary files differ
diff --git a/icons/16x16/player_pause.png b/icons/16x16/player_pause.png
new file mode 100644
index 0000000..4c894ce
--- /dev/null
+++ b/icons/16x16/player_pause.png
Binary files differ
diff --git a/icons/16x16/player_playlist.png b/icons/16x16/player_playlist.png
new file mode 100644
index 0000000..7330bc5
--- /dev/null
+++ b/icons/16x16/player_playlist.png
Binary files differ
diff --git a/icons/16x16/player_time.png b/icons/16x16/player_time.png
new file mode 100644
index 0000000..1de43d5
--- /dev/null
+++ b/icons/16x16/player_time.png
Binary files differ
diff --git a/icons/16x16/player_time2.png b/icons/16x16/player_time2.png
new file mode 100644
index 0000000..cec1a99
--- /dev/null
+++ b/icons/16x16/player_time2.png
Binary files differ
diff --git a/icons/16x16/project_open.png b/icons/16x16/project_open.png
new file mode 100644
index 0000000..bebc235
--- /dev/null
+++ b/icons/16x16/project_open.png
Binary files differ
diff --git a/icons/16x16/queue.png b/icons/16x16/queue.png
new file mode 100644
index 0000000..8c5e4be
--- /dev/null
+++ b/icons/16x16/queue.png
Binary files differ
diff --git a/icons/16x16/rebuild.png b/icons/16x16/rebuild.png
new file mode 100644
index 0000000..9e3f403
--- /dev/null
+++ b/icons/16x16/rebuild.png
Binary files differ
diff --git a/icons/16x16/red_dot.png b/icons/16x16/red_dot.png
new file mode 100644
index 0000000..34ca31d
--- /dev/null
+++ b/icons/16x16/red_dot.png
Binary files differ
diff --git a/icons/16x16/redo.png b/icons/16x16/redo.png
new file mode 100644
index 0000000..ec2ed78
--- /dev/null
+++ b/icons/16x16/redo.png
Binary files differ
diff --git a/icons/16x16/reload.png b/icons/16x16/reload.png
new file mode 100644
index 0000000..e002141
--- /dev/null
+++ b/icons/16x16/reload.png
Binary files differ
diff --git a/icons/16x16/reload_red.png b/icons/16x16/reload_red.png
new file mode 100644
index 0000000..7121f68
--- /dev/null
+++ b/icons/16x16/reload_red.png
Binary files differ
diff --git a/icons/16x16/resume.png b/icons/16x16/resume.png
new file mode 100644
index 0000000..fa8766b
--- /dev/null
+++ b/icons/16x16/resume.png
Binary files differ
diff --git a/icons/16x16/right.png b/icons/16x16/right.png
new file mode 100644
index 0000000..ce9e41a
--- /dev/null
+++ b/icons/16x16/right.png
Binary files differ
diff --git a/icons/16x16/save_all.png b/icons/16x16/save_all.png
new file mode 100644
index 0000000..b565abf
--- /dev/null
+++ b/icons/16x16/save_all.png
Binary files differ
diff --git a/icons/16x16/sb.png b/icons/16x16/sb.png
new file mode 100644
index 0000000..dcc952e
--- /dev/null
+++ b/icons/16x16/sb.png
Binary files differ
diff --git a/icons/16x16/sh.png b/icons/16x16/sh.png
new file mode 100644
index 0000000..4da7d1f
--- /dev/null
+++ b/icons/16x16/sh.png
Binary files differ
diff --git a/icons/16x16/simplekeypad.png b/icons/16x16/simplekeypad.png
new file mode 100644
index 0000000..73b5b50
--- /dev/null
+++ b/icons/16x16/simplekeypad.png
Binary files differ
diff --git a/icons/16x16/source_c.png b/icons/16x16/source_c.png
new file mode 100644
index 0000000..8312c6b
--- /dev/null
+++ b/icons/16x16/source_c.png
Binary files differ
diff --git a/icons/16x16/source_cpp.png b/icons/16x16/source_cpp.png
new file mode 100644
index 0000000..40c6169
--- /dev/null
+++ b/icons/16x16/source_cpp.png
Binary files differ
diff --git a/icons/16x16/source_h.png b/icons/16x16/source_h.png
new file mode 100644
index 0000000..203ad57
--- /dev/null
+++ b/icons/16x16/source_h.png
Binary files differ
diff --git a/icons/16x16/spellcheck.png b/icons/16x16/spellcheck.png
new file mode 100644
index 0000000..6303389
--- /dev/null
+++ b/icons/16x16/spellcheck.png
Binary files differ
diff --git a/icons/16x16/status_unknown.png b/icons/16x16/status_unknown.png
new file mode 100644
index 0000000..fd49f31
--- /dev/null
+++ b/icons/16x16/status_unknown.png
Binary files differ
diff --git a/icons/16x16/sub.png b/icons/16x16/sub.png
new file mode 100644
index 0000000..c7fb16d
--- /dev/null
+++ b/icons/16x16/sub.png
Binary files differ
diff --git a/icons/16x16/symbol.png b/icons/16x16/symbol.png
new file mode 100644
index 0000000..b892722
--- /dev/null
+++ b/icons/16x16/symbol.png
Binary files differ
diff --git a/icons/16x16/terminal.png b/icons/16x16/terminal.png
new file mode 100644
index 0000000..75fa314
--- /dev/null
+++ b/icons/16x16/terminal.png
Binary files differ
diff --git a/icons/16x16/tex.png b/icons/16x16/tex.png
new file mode 100644
index 0000000..2989200
--- /dev/null
+++ b/icons/16x16/tex.png
Binary files differ
diff --git a/icons/16x16/text_bold.png b/icons/16x16/text_bold.png
new file mode 100644
index 0000000..f64f38b
--- /dev/null
+++ b/icons/16x16/text_bold.png
Binary files differ
diff --git a/icons/16x16/text_italic.png b/icons/16x16/text_italic.png
new file mode 100644
index 0000000..8f825f9
--- /dev/null
+++ b/icons/16x16/text_italic.png
Binary files differ
diff --git a/icons/16x16/text_strike.png b/icons/16x16/text_strike.png
new file mode 100644
index 0000000..0d5a964
--- /dev/null
+++ b/icons/16x16/text_strike.png
Binary files differ
diff --git a/icons/16x16/text_under.png b/icons/16x16/text_under.png
new file mode 100644
index 0000000..5094434
--- /dev/null
+++ b/icons/16x16/text_under.png
Binary files differ
diff --git a/icons/16x16/today.png b/icons/16x16/today.png
new file mode 100644
index 0000000..6c16724
--- /dev/null
+++ b/icons/16x16/today.png
Binary files differ
diff --git a/icons/16x16/top.png b/icons/16x16/top.png
new file mode 100644
index 0000000..01cec63
--- /dev/null
+++ b/icons/16x16/top.png
Binary files differ
diff --git a/icons/16x16/undo.png b/icons/16x16/undo.png
new file mode 100644
index 0000000..d2ed14f
--- /dev/null
+++ b/icons/16x16/undo.png
Binary files differ
diff --git a/icons/16x16/unindent.png b/icons/16x16/unindent.png
new file mode 100644
index 0000000..119e763
--- /dev/null
+++ b/icons/16x16/unindent.png
Binary files differ
diff --git a/icons/16x16/unlock.png b/icons/16x16/unlock.png
new file mode 100644
index 0000000..3a1a0d3
--- /dev/null
+++ b/icons/16x16/unlock.png
Binary files differ
diff --git a/icons/16x16/up.png b/icons/16x16/up.png
new file mode 100644
index 0000000..9d9856c
--- /dev/null
+++ b/icons/16x16/up.png
Binary files differ
diff --git a/icons/16x16/up0.png b/icons/16x16/up0.png
new file mode 100644
index 0000000..47c9c0c
--- /dev/null
+++ b/icons/16x16/up0.png
Binary files differ
diff --git a/icons/16x16/usb.png b/icons/16x16/usb.png
new file mode 100644
index 0000000..b772ba5
--- /dev/null
+++ b/icons/16x16/usb.png
Binary files differ
diff --git a/icons/16x16/vcs_commit.png b/icons/16x16/vcs_commit.png
new file mode 100644
index 0000000..71f6b3d
--- /dev/null
+++ b/icons/16x16/vcs_commit.png
Binary files differ
diff --git a/icons/16x16/vcs_update.png b/icons/16x16/vcs_update.png
new file mode 100644
index 0000000..c3ba632
--- /dev/null
+++ b/icons/16x16/vcs_update.png
Binary files differ
diff --git a/icons/16x16/view_choose.png b/icons/16x16/view_choose.png
new file mode 100644
index 0000000..58c80e3
--- /dev/null
+++ b/icons/16x16/view_choose.png
Binary files differ
diff --git a/icons/16x16/view_detailed.png b/icons/16x16/view_detailed.png
new file mode 100644
index 0000000..4fea77a
--- /dev/null
+++ b/icons/16x16/view_detailed.png
Binary files differ
diff --git a/icons/16x16/view_icon.png b/icons/16x16/view_icon.png
new file mode 100644
index 0000000..ac15e30
--- /dev/null
+++ b/icons/16x16/view_icon.png
Binary files differ
diff --git a/icons/16x16/view_left_right.png b/icons/16x16/view_left_right.png
new file mode 100644
index 0000000..d2223fa
--- /dev/null
+++ b/icons/16x16/view_left_right.png
Binary files differ
diff --git a/icons/16x16/view_remove.png b/icons/16x16/view_remove.png
new file mode 100644
index 0000000..b4eb6c7
--- /dev/null
+++ b/icons/16x16/view_remove.png
Binary files differ
diff --git a/icons/16x16/view_text.png b/icons/16x16/view_text.png
new file mode 100644
index 0000000..e03744b
--- /dev/null
+++ b/icons/16x16/view_text.png
Binary files differ
diff --git a/icons/16x16/view_top_bottom.png b/icons/16x16/view_top_bottom.png
new file mode 100644
index 0000000..fe61322
--- /dev/null
+++ b/icons/16x16/view_top_bottom.png
Binary files differ
diff --git a/icons/16x16/viewmag_in.png b/icons/16x16/viewmag_in.png
new file mode 100644
index 0000000..d2b139c
--- /dev/null
+++ b/icons/16x16/viewmag_in.png
Binary files differ
diff --git a/icons/16x16/viewmag_out.png b/icons/16x16/viewmag_out.png
new file mode 100644
index 0000000..2ae727f
--- /dev/null
+++ b/icons/16x16/viewmag_out.png
Binary files differ
diff --git a/icons/16x16/window_fullscreen.png b/icons/16x16/window_fullscreen.png
new file mode 100644
index 0000000..a8c35c4
--- /dev/null
+++ b/icons/16x16/window_fullscreen.png
Binary files differ
diff --git a/icons/16x16/xcalc.png b/icons/16x16/xcalc.png
new file mode 100644
index 0000000..5b08260
--- /dev/null
+++ b/icons/16x16/xcalc.png
Binary files differ
diff --git a/icons/22x22/1downarrow.png b/icons/22x22/1downarrow.png
new file mode 100644
index 0000000..ea9c00c
--- /dev/null
+++ b/icons/22x22/1downarrow.png
Binary files differ
diff --git a/icons/22x22/1leftarrow.png b/icons/22x22/1leftarrow.png
new file mode 100644
index 0000000..a6c4668
--- /dev/null
+++ b/icons/22x22/1leftarrow.png
Binary files differ
diff --git a/icons/22x22/1rightarrow.png b/icons/22x22/1rightarrow.png
new file mode 100644
index 0000000..8356b71
--- /dev/null
+++ b/icons/22x22/1rightarrow.png
Binary files differ
diff --git a/icons/22x22/1uparrow.png b/icons/22x22/1uparrow.png
new file mode 100644
index 0000000..d6c2b99
--- /dev/null
+++ b/icons/22x22/1uparrow.png
Binary files differ
diff --git a/icons/22x22/2rightarrow.png b/icons/22x22/2rightarrow.png
new file mode 100644
index 0000000..f57b483
--- /dev/null
+++ b/icons/22x22/2rightarrow.png
Binary files differ
diff --git a/icons/22x22/8seg.png b/icons/22x22/8seg.png
new file mode 100644
index 0000000..de32eae
--- /dev/null
+++ b/icons/22x22/8seg.png
Binary files differ
diff --git a/icons/22x22/_chardevice.png b/icons/22x22/_chardevice.png
new file mode 100644
index 0000000..82cfceb
--- /dev/null
+++ b/icons/22x22/_chardevice.png
Binary files differ
diff --git a/icons/22x22/_kcmdf.png b/icons/22x22/_kcmdf.png
new file mode 100644
index 0000000..beb57d3
--- /dev/null
+++ b/icons/22x22/_kcmdf.png
Binary files differ
diff --git a/icons/22x22/back.png b/icons/22x22/back.png
new file mode 100644
index 0000000..3e8f12f
--- /dev/null
+++ b/icons/22x22/back.png
Binary files differ
diff --git a/icons/22x22/bar0.png b/icons/22x22/bar0.png
new file mode 100644
index 0000000..e64c50c
--- /dev/null
+++ b/icons/22x22/bar0.png
Binary files differ
diff --git a/icons/22x22/bar1.png b/icons/22x22/bar1.png
new file mode 100644
index 0000000..b91b6af
--- /dev/null
+++ b/icons/22x22/bar1.png
Binary files differ
diff --git a/icons/22x22/bar5.png b/icons/22x22/bar5.png
new file mode 100644
index 0000000..e3649c1
--- /dev/null
+++ b/icons/22x22/bar5.png
Binary files differ
diff --git a/icons/22x22/binary.png b/icons/22x22/binary.png
new file mode 100644
index 0000000..28d3bea
--- /dev/null
+++ b/icons/22x22/binary.png
Binary files differ
diff --git a/icons/22x22/bookmark.png b/icons/22x22/bookmark.png
new file mode 100644
index 0000000..ced954c
--- /dev/null
+++ b/icons/22x22/bookmark.png
Binary files differ
diff --git a/icons/22x22/bookmark_folder.png b/icons/22x22/bookmark_folder.png
new file mode 100644
index 0000000..61305b7
--- /dev/null
+++ b/icons/22x22/bookmark_folder.png
Binary files differ
diff --git a/icons/22x22/change_case.png b/icons/22x22/change_case.png
new file mode 100644
index 0000000..8161d85
--- /dev/null
+++ b/icons/22x22/change_case.png
Binary files differ
diff --git a/icons/22x22/chardevice.png b/icons/22x22/chardevice.png
new file mode 100644
index 0000000..43d467b
--- /dev/null
+++ b/icons/22x22/chardevice.png
Binary files differ
diff --git a/icons/22x22/compfile.png b/icons/22x22/compfile.png
new file mode 100644
index 0000000..eb05673
--- /dev/null
+++ b/icons/22x22/compfile.png
Binary files differ
diff --git a/icons/22x22/compfile_this.png b/icons/22x22/compfile_this.png
new file mode 100644
index 0000000..5136b65
--- /dev/null
+++ b/icons/22x22/compfile_this.png
Binary files differ
diff --git a/icons/22x22/configure.png b/icons/22x22/configure.png
new file mode 100644
index 0000000..96ba433
--- /dev/null
+++ b/icons/22x22/configure.png
Binary files differ
diff --git a/icons/22x22/contents.png b/icons/22x22/contents.png
new file mode 100644
index 0000000..7596e67
--- /dev/null
+++ b/icons/22x22/contents.png
Binary files differ
diff --git a/icons/22x22/desktop.png b/icons/22x22/desktop.png
new file mode 100644
index 0000000..ad48d81
--- /dev/null
+++ b/icons/22x22/desktop.png
Binary files differ
diff --git a/icons/22x22/disasm.png b/icons/22x22/disasm.png
new file mode 100644
index 0000000..625bd4a
--- /dev/null
+++ b/icons/22x22/disasm.png
Binary files differ
diff --git a/icons/22x22/editclear.png b/icons/22x22/editclear.png
new file mode 100644
index 0000000..1ae690d
--- /dev/null
+++ b/icons/22x22/editclear.png
Binary files differ
diff --git a/icons/22x22/editcopy.png b/icons/22x22/editcopy.png
new file mode 100644
index 0000000..ae1cd9f
--- /dev/null
+++ b/icons/22x22/editcopy.png
Binary files differ
diff --git a/icons/22x22/editcut.png b/icons/22x22/editcut.png
new file mode 100644
index 0000000..192b575
--- /dev/null
+++ b/icons/22x22/editcut.png
Binary files differ
diff --git a/icons/22x22/editdelete.png b/icons/22x22/editdelete.png
new file mode 100644
index 0000000..6fb193f
--- /dev/null
+++ b/icons/22x22/editdelete.png
Binary files differ
diff --git a/icons/22x22/editpaste.png b/icons/22x22/editpaste.png
new file mode 100644
index 0000000..b8454f9
--- /dev/null
+++ b/icons/22x22/editpaste.png
Binary files differ
diff --git a/icons/22x22/emptytrash.png b/icons/22x22/emptytrash.png
new file mode 100644
index 0000000..eea039d
--- /dev/null
+++ b/icons/22x22/emptytrash.png
Binary files differ
diff --git a/icons/22x22/exit.png b/icons/22x22/exit.png
new file mode 100644
index 0000000..b266020
--- /dev/null
+++ b/icons/22x22/exit.png
Binary files differ
diff --git a/icons/22x22/fileclose.png b/icons/22x22/fileclose.png
new file mode 100644
index 0000000..7cb9859
--- /dev/null
+++ b/icons/22x22/fileclose.png
Binary files differ
diff --git a/icons/22x22/filenew.png b/icons/22x22/filenew.png
new file mode 100644
index 0000000..004ca03
--- /dev/null
+++ b/icons/22x22/filenew.png
Binary files differ
diff --git a/icons/22x22/fileopen.png b/icons/22x22/fileopen.png
new file mode 100644
index 0000000..a79982e
--- /dev/null
+++ b/icons/22x22/fileopen.png
Binary files differ
diff --git a/icons/22x22/filesave.png b/icons/22x22/filesave.png
new file mode 100644
index 0000000..3bc2a37
--- /dev/null
+++ b/icons/22x22/filesave.png
Binary files differ
diff --git a/icons/22x22/filesaveas.png b/icons/22x22/filesaveas.png
new file mode 100644
index 0000000..c8d4816
--- /dev/null
+++ b/icons/22x22/filesaveas.png
Binary files differ
diff --git a/icons/22x22/filter.png b/icons/22x22/filter.png
new file mode 100644
index 0000000..bff8da3
--- /dev/null
+++ b/icons/22x22/filter.png
Binary files differ
diff --git a/icons/22x22/find.png b/icons/22x22/find.png
new file mode 100644
index 0000000..20d3668
--- /dev/null
+++ b/icons/22x22/find.png
Binary files differ
diff --git a/icons/22x22/flag.png b/icons/22x22/flag.png
new file mode 100644
index 0000000..9eb60f9
--- /dev/null
+++ b/icons/22x22/flag.png
Binary files differ
diff --git a/icons/22x22/folder_home.png b/icons/22x22/folder_home.png
new file mode 100644
index 0000000..e9612a3
--- /dev/null
+++ b/icons/22x22/folder_home.png
Binary files differ
diff --git a/icons/22x22/folder_new.png b/icons/22x22/folder_new.png
new file mode 100644
index 0000000..1277281
--- /dev/null
+++ b/icons/22x22/folder_new.png
Binary files differ
diff --git a/icons/22x22/fork.png b/icons/22x22/fork.png
new file mode 100644
index 0000000..da97aef
--- /dev/null
+++ b/icons/22x22/fork.png
Binary files differ
diff --git a/icons/22x22/fork_this.png b/icons/22x22/fork_this.png
new file mode 100644
index 0000000..9bfa254
--- /dev/null
+++ b/icons/22x22/fork_this.png
Binary files differ
diff --git a/icons/22x22/forward.png b/icons/22x22/forward.png
new file mode 100644
index 0000000..cfab7cf
--- /dev/null
+++ b/icons/22x22/forward.png
Binary files differ
diff --git a/icons/22x22/fsview.png b/icons/22x22/fsview.png
new file mode 100644
index 0000000..2e4eb5c
--- /dev/null
+++ b/icons/22x22/fsview.png
Binary files differ
diff --git a/icons/22x22/gear.png b/icons/22x22/gear.png
new file mode 100644
index 0000000..14dc745
--- /dev/null
+++ b/icons/22x22/gear.png
Binary files differ
diff --git a/icons/22x22/gear0.png b/icons/22x22/gear0.png
new file mode 100644
index 0000000..a42ae9f
--- /dev/null
+++ b/icons/22x22/gear0.png
Binary files differ
diff --git a/icons/22x22/gear0_play.png b/icons/22x22/gear0_play.png
new file mode 100644
index 0000000..cb571c8
--- /dev/null
+++ b/icons/22x22/gear0_play.png
Binary files differ
diff --git a/icons/22x22/gear1.png b/icons/22x22/gear1.png
new file mode 100644
index 0000000..305f891
--- /dev/null
+++ b/icons/22x22/gear1.png
Binary files differ
diff --git a/icons/22x22/gear1_play.png b/icons/22x22/gear1_play.png
new file mode 100644
index 0000000..428e724
--- /dev/null
+++ b/icons/22x22/gear1_play.png
Binary files differ
diff --git a/icons/22x22/gear2.png b/icons/22x22/gear2.png
new file mode 100644
index 0000000..eed998b
--- /dev/null
+++ b/icons/22x22/gear2.png
Binary files differ
diff --git a/icons/22x22/gear2_play.png b/icons/22x22/gear2_play.png
new file mode 100644
index 0000000..7ef04ba
--- /dev/null
+++ b/icons/22x22/gear2_play.png
Binary files differ
diff --git a/icons/22x22/goto.png b/icons/22x22/goto.png
new file mode 100644
index 0000000..1088baf
--- /dev/null
+++ b/icons/22x22/goto.png
Binary files differ
diff --git a/icons/22x22/goto2.png b/icons/22x22/goto2.png
new file mode 100644
index 0000000..639bdcf
--- /dev/null
+++ b/icons/22x22/goto2.png
Binary files differ
diff --git a/icons/22x22/hdd_unmount.png b/icons/22x22/hdd_unmount.png
new file mode 100644
index 0000000..d5398d9
--- /dev/null
+++ b/icons/22x22/hdd_unmount.png
Binary files differ
diff --git a/icons/22x22/help.png b/icons/22x22/help.png
new file mode 100644
index 0000000..644347b
--- /dev/null
+++ b/icons/22x22/help.png
Binary files differ
diff --git a/icons/22x22/history.png b/icons/22x22/history.png
new file mode 100644
index 0000000..ea64540
--- /dev/null
+++ b/icons/22x22/history.png
Binary files differ
diff --git a/icons/22x22/history2.png b/icons/22x22/history2.png
new file mode 100644
index 0000000..cd4a61b
--- /dev/null
+++ b/icons/22x22/history2.png
Binary files differ
diff --git a/icons/22x22/html.png b/icons/22x22/html.png
new file mode 100644
index 0000000..d0df8e9
--- /dev/null
+++ b/icons/22x22/html.png
Binary files differ
diff --git a/icons/22x22/kaboodleloop.png b/icons/22x22/kaboodleloop.png
new file mode 100644
index 0000000..f4b6069
--- /dev/null
+++ b/icons/22x22/kaboodleloop.png
Binary files differ
diff --git a/icons/22x22/kcmdf.png b/icons/22x22/kcmdf.png
new file mode 100644
index 0000000..aa92e25
--- /dev/null
+++ b/icons/22x22/kcmdf.png
Binary files differ
diff --git a/icons/22x22/kcmsystem.png b/icons/22x22/kcmsystem.png
new file mode 100644
index 0000000..0caf8a1
--- /dev/null
+++ b/icons/22x22/kcmsystem.png
Binary files differ
diff --git a/icons/22x22/leddisplay.png b/icons/22x22/leddisplay.png
new file mode 100644
index 0000000..c35347e
--- /dev/null
+++ b/icons/22x22/leddisplay.png
Binary files differ
diff --git a/icons/22x22/ledmatrix.png b/icons/22x22/ledmatrix.png
new file mode 100644
index 0000000..025e612
--- /dev/null
+++ b/icons/22x22/ledmatrix.png
Binary files differ
diff --git a/icons/22x22/ledpanel.png b/icons/22x22/ledpanel.png
new file mode 100644
index 0000000..31f6163
--- /dev/null
+++ b/icons/22x22/ledpanel.png
Binary files differ
diff --git a/icons/22x22/math_matrix.png b/icons/22x22/math_matrix.png
new file mode 100644
index 0000000..396e728
--- /dev/null
+++ b/icons/22x22/math_matrix.png
Binary files differ
diff --git a/icons/22x22/matrixkeypad.png b/icons/22x22/matrixkeypad.png
new file mode 100644
index 0000000..8e9a03d
--- /dev/null
+++ b/icons/22x22/matrixkeypad.png
Binary files differ
diff --git a/icons/22x22/mcu8051ide.png b/icons/22x22/mcu8051ide.png
new file mode 100644
index 0000000..f068e90
--- /dev/null
+++ b/icons/22x22/mcu8051ide.png
Binary files differ
diff --git a/icons/22x22/memory.png b/icons/22x22/memory.png
new file mode 100644
index 0000000..90652bc
--- /dev/null
+++ b/icons/22x22/memory.png
Binary files differ
diff --git a/icons/22x22/memory_B.png b/icons/22x22/memory_B.png
new file mode 100644
index 0000000..830bfaf
--- /dev/null
+++ b/icons/22x22/memory_B.png
Binary files differ
diff --git a/icons/22x22/memory_BA.png b/icons/22x22/memory_BA.png
new file mode 100644
index 0000000..890832b
--- /dev/null
+++ b/icons/22x22/memory_BA.png
Binary files differ
diff --git a/icons/22x22/memory_C.png b/icons/22x22/memory_C.png
new file mode 100644
index 0000000..d520736
--- /dev/null
+++ b/icons/22x22/memory_C.png
Binary files differ
diff --git a/icons/22x22/memory_E.png b/icons/22x22/memory_E.png
new file mode 100644
index 0000000..1a886db
--- /dev/null
+++ b/icons/22x22/memory_E.png
Binary files differ
diff --git a/icons/22x22/memory_P.png b/icons/22x22/memory_P.png
new file mode 100644
index 0000000..69993d0
--- /dev/null
+++ b/icons/22x22/memory_P.png
Binary files differ
diff --git a/icons/22x22/memory_S.png b/icons/22x22/memory_S.png
new file mode 100644
index 0000000..e5dbecf
--- /dev/null
+++ b/icons/22x22/memory_S.png
Binary files differ
diff --git a/icons/22x22/memory_ST.png b/icons/22x22/memory_ST.png
new file mode 100644
index 0000000..ba6674d
--- /dev/null
+++ b/icons/22x22/memory_ST.png
Binary files differ
diff --git a/icons/22x22/memory_X.png b/icons/22x22/memory_X.png
new file mode 100644
index 0000000..9710469
--- /dev/null
+++ b/icons/22x22/memory_X.png
Binary files differ
diff --git a/icons/22x22/mleddisplay.png b/icons/22x22/mleddisplay.png
new file mode 100644
index 0000000..611d105
--- /dev/null
+++ b/icons/22x22/mleddisplay.png
Binary files differ
diff --git a/icons/22x22/pencil.png b/icons/22x22/pencil.png
new file mode 100644
index 0000000..818322a
--- /dev/null
+++ b/icons/22x22/pencil.png
Binary files differ
diff --git a/icons/22x22/player_pause.png b/icons/22x22/player_pause.png
new file mode 100644
index 0000000..b14e507
--- /dev/null
+++ b/icons/22x22/player_pause.png
Binary files differ
diff --git a/icons/22x22/player_play.png b/icons/22x22/player_play.png
new file mode 100644
index 0000000..bc7336c
--- /dev/null
+++ b/icons/22x22/player_play.png
Binary files differ
diff --git a/icons/22x22/project_open.png b/icons/22x22/project_open.png
new file mode 100644
index 0000000..77910b2
--- /dev/null
+++ b/icons/22x22/project_open.png
Binary files differ
diff --git a/icons/22x22/rebuild.png b/icons/22x22/rebuild.png
new file mode 100644
index 0000000..9f182b3
--- /dev/null
+++ b/icons/22x22/rebuild.png
Binary files differ
diff --git a/icons/22x22/redo.png b/icons/22x22/redo.png
new file mode 100644
index 0000000..6aacd4f
--- /dev/null
+++ b/icons/22x22/redo.png
Binary files differ
diff --git a/icons/22x22/reload.png b/icons/22x22/reload.png
new file mode 100644
index 0000000..3fa8db7
--- /dev/null
+++ b/icons/22x22/reload.png
Binary files differ
diff --git a/icons/22x22/resume.png b/icons/22x22/resume.png
new file mode 100644
index 0000000..ae8fa7a
--- /dev/null
+++ b/icons/22x22/resume.png
Binary files differ
diff --git a/icons/22x22/run.png b/icons/22x22/run.png
new file mode 100644
index 0000000..b5c8949
--- /dev/null
+++ b/icons/22x22/run.png
Binary files differ
diff --git a/icons/22x22/save_all.png b/icons/22x22/save_all.png
new file mode 100644
index 0000000..af29975
--- /dev/null
+++ b/icons/22x22/save_all.png
Binary files differ
diff --git a/icons/22x22/simplekeypad.png b/icons/22x22/simplekeypad.png
new file mode 100644
index 0000000..61af570
--- /dev/null
+++ b/icons/22x22/simplekeypad.png
Binary files differ
diff --git a/icons/22x22/stop.png b/icons/22x22/stop.png
new file mode 100644
index 0000000..73b27d9
--- /dev/null
+++ b/icons/22x22/stop.png
Binary files differ
diff --git a/icons/22x22/symbol.png b/icons/22x22/symbol.png
new file mode 100644
index 0000000..6b5d40b
--- /dev/null
+++ b/icons/22x22/symbol.png
Binary files differ
diff --git a/icons/22x22/tex.png b/icons/22x22/tex.png
new file mode 100644
index 0000000..21901b4
--- /dev/null
+++ b/icons/22x22/tex.png
Binary files differ
diff --git a/icons/22x22/undo.png b/icons/22x22/undo.png
new file mode 100644
index 0000000..d4b682b
--- /dev/null
+++ b/icons/22x22/undo.png
Binary files differ
diff --git a/icons/22x22/view_detailed.png b/icons/22x22/view_detailed.png
new file mode 100644
index 0000000..19ab36e
--- /dev/null
+++ b/icons/22x22/view_detailed.png
Binary files differ
diff --git a/icons/22x22/view_icon.png b/icons/22x22/view_icon.png
new file mode 100644
index 0000000..f6ced88
--- /dev/null
+++ b/icons/22x22/view_icon.png
Binary files differ
diff --git a/icons/22x22/window_fullscreen.png b/icons/22x22/window_fullscreen.png
new file mode 100644
index 0000000..4242f97
--- /dev/null
+++ b/icons/22x22/window_fullscreen.png
Binary files differ
diff --git a/icons/22x22/window_nofullscreen.png b/icons/22x22/window_nofullscreen.png
new file mode 100644
index 0000000..b934ff2
--- /dev/null
+++ b/icons/22x22/window_nofullscreen.png
Binary files differ
diff --git a/icons/22x22/xcalc.png b/icons/22x22/xcalc.png
new file mode 100644
index 0000000..fbb277f
--- /dev/null
+++ b/icons/22x22/xcalc.png
Binary files differ
diff --git a/icons/32x32/button_ok.png b/icons/32x32/button_ok.png
new file mode 100644
index 0000000..230de53
--- /dev/null
+++ b/icons/32x32/button_ok.png
Binary files differ
diff --git a/icons/32x32/configure.png b/icons/32x32/configure.png
new file mode 100644
index 0000000..1141564
--- /dev/null
+++ b/icons/32x32/configure.png
Binary files differ
diff --git a/icons/32x32/exec.png b/icons/32x32/exec.png
new file mode 100644
index 0000000..d385386
--- /dev/null
+++ b/icons/32x32/exec.png
Binary files differ
diff --git a/icons/32x32/fileclose.png b/icons/32x32/fileclose.png
new file mode 100644
index 0000000..8acc84d
--- /dev/null
+++ b/icons/32x32/fileclose.png
Binary files differ
diff --git a/icons/32x32/help.png b/icons/32x32/help.png
new file mode 100644
index 0000000..93bf094
--- /dev/null
+++ b/icons/32x32/help.png
Binary files differ
diff --git a/icons/32x32/kcmmemory.png b/icons/32x32/kcmmemory.png
new file mode 100644
index 0000000..3db3506
--- /dev/null
+++ b/icons/32x32/kcmmemory.png
Binary files differ
diff --git a/icons/32x32/mcu8051ide.png b/icons/32x32/mcu8051ide.png
new file mode 100644
index 0000000..25f51aa
--- /dev/null
+++ b/icons/32x32/mcu8051ide.png
Binary files differ
diff --git a/icons/32x32/messagebox_critical.png b/icons/32x32/messagebox_critical.png
new file mode 100644
index 0000000..1de7a6f
--- /dev/null
+++ b/icons/32x32/messagebox_critical.png
Binary files differ
diff --git a/icons/32x32/messagebox_info.png b/icons/32x32/messagebox_info.png
new file mode 100644
index 0000000..96642db
--- /dev/null
+++ b/icons/32x32/messagebox_info.png
Binary files differ
diff --git a/icons/32x32/messagebox_warning.png b/icons/32x32/messagebox_warning.png
new file mode 100644
index 0000000..d83f349
--- /dev/null
+++ b/icons/32x32/messagebox_warning.png
Binary files differ
diff --git a/icons/32x32/user_away.png b/icons/32x32/user_away.png
new file mode 100644
index 0000000..233b124
--- /dev/null
+++ b/icons/32x32/user_away.png
Binary files differ
diff --git a/icons/32x32/wizard.png b/icons/32x32/wizard.png
new file mode 100644
index 0000000..686a2da
--- /dev/null
+++ b/icons/32x32/wizard.png
Binary files differ
diff --git a/icons/mcu/8031.png b/icons/mcu/8031.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/8031.png
Binary files differ
diff --git a/icons/mcu/8032.png b/icons/mcu/8032.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/8032.png
Binary files differ
diff --git a/icons/mcu/8051.png b/icons/mcu/8051.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/8051.png
Binary files differ
diff --git a/icons/mcu/8052.png b/icons/mcu/8052.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/8052.png
Binary files differ
diff --git a/icons/mcu/80C31.png b/icons/mcu/80C31.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/80C31.png
Binary files differ
diff --git a/icons/mcu/80C31X2.png b/icons/mcu/80C31X2.png
new file mode 100644
index 0000000..2d0d855
--- /dev/null
+++ b/icons/mcu/80C31X2.png
Binary files differ
diff --git a/icons/mcu/80C32.png b/icons/mcu/80C32.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/80C32.png
Binary files differ
diff --git a/icons/mcu/80C32X2.png b/icons/mcu/80C32X2.png
new file mode 100644
index 0000000..1000f2f
--- /dev/null
+++ b/icons/mcu/80C32X2.png
Binary files differ
diff --git a/icons/mcu/80C51.png b/icons/mcu/80C51.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/80C51.png
Binary files differ
diff --git a/icons/mcu/80C52.png b/icons/mcu/80C52.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/80C52.png
Binary files differ
diff --git a/icons/mcu/80C52X2.png b/icons/mcu/80C52X2.png
new file mode 100644
index 0000000..1000f2f
--- /dev/null
+++ b/icons/mcu/80C52X2.png
Binary files differ
diff --git a/icons/mcu/80C54.png b/icons/mcu/80C54.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/80C54.png
Binary files differ
diff --git a/icons/mcu/80C54X2.png b/icons/mcu/80C54X2.png
new file mode 100644
index 0000000..53f469d
--- /dev/null
+++ b/icons/mcu/80C54X2.png
Binary files differ
diff --git a/icons/mcu/80C58.png b/icons/mcu/80C58.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/80C58.png
Binary files differ
diff --git a/icons/mcu/80C58X2.png b/icons/mcu/80C58X2.png
new file mode 100644
index 0000000..53f469d
--- /dev/null
+++ b/icons/mcu/80C58X2.png
Binary files differ
diff --git a/icons/mcu/8731.png b/icons/mcu/8731.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/8731.png
Binary files differ
diff --git a/icons/mcu/8751.png b/icons/mcu/8751.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/8751.png
Binary files differ
diff --git a/icons/mcu/8752.png b/icons/mcu/8752.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/8752.png
Binary files differ
diff --git a/icons/mcu/87C51.png b/icons/mcu/87C51.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/87C51.png
Binary files differ
diff --git a/icons/mcu/87C52.png b/icons/mcu/87C52.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/87C52.png
Binary files differ
diff --git a/icons/mcu/87C52X2.png b/icons/mcu/87C52X2.png
new file mode 100644
index 0000000..1000f2f
--- /dev/null
+++ b/icons/mcu/87C52X2.png
Binary files differ
diff --git a/icons/mcu/87C54.png b/icons/mcu/87C54.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/87C54.png
Binary files differ
diff --git a/icons/mcu/87C54X2.png b/icons/mcu/87C54X2.png
new file mode 100644
index 0000000..53f469d
--- /dev/null
+++ b/icons/mcu/87C54X2.png
Binary files differ
diff --git a/icons/mcu/87C58.png b/icons/mcu/87C58.png
new file mode 100644
index 0000000..5b47cdf
--- /dev/null
+++ b/icons/mcu/87C58.png
Binary files differ
diff --git a/icons/mcu/87C58X2.png b/icons/mcu/87C58X2.png
new file mode 100644
index 0000000..53f469d
--- /dev/null
+++ b/icons/mcu/87C58X2.png
Binary files differ
diff --git a/icons/mcu/AT80C31X2.png b/icons/mcu/AT80C31X2.png
new file mode 100644
index 0000000..3c14dc7
--- /dev/null
+++ b/icons/mcu/AT80C31X2.png
Binary files differ
diff --git a/icons/mcu/AT80C32X2.png b/icons/mcu/AT80C32X2.png
new file mode 100644
index 0000000..c3c18e4
--- /dev/null
+++ b/icons/mcu/AT80C32X2.png
Binary files differ
diff --git a/icons/mcu/AT80C52X2.png b/icons/mcu/AT80C52X2.png
new file mode 100644
index 0000000..c3c18e4
--- /dev/null
+++ b/icons/mcu/AT80C52X2.png
Binary files differ
diff --git a/icons/mcu/AT80C54X2.png b/icons/mcu/AT80C54X2.png
new file mode 100644
index 0000000..1a3ff11
--- /dev/null
+++ b/icons/mcu/AT80C54X2.png
Binary files differ
diff --git a/icons/mcu/AT80C58X2.png b/icons/mcu/AT80C58X2.png
new file mode 100644
index 0000000..1a3ff11
--- /dev/null
+++ b/icons/mcu/AT80C58X2.png
Binary files differ
diff --git a/icons/mcu/AT87C52X2.png b/icons/mcu/AT87C52X2.png
new file mode 100644
index 0000000..c3c18e4
--- /dev/null
+++ b/icons/mcu/AT87C52X2.png
Binary files differ
diff --git a/icons/mcu/AT87C54X2.png b/icons/mcu/AT87C54X2.png
new file mode 100644
index 0000000..1a3ff11
--- /dev/null
+++ b/icons/mcu/AT87C54X2.png
Binary files differ
diff --git a/icons/mcu/AT87C58X2.png b/icons/mcu/AT87C58X2.png
new file mode 100644
index 0000000..1a3ff11
--- /dev/null
+++ b/icons/mcu/AT87C58X2.png
Binary files differ
diff --git a/icons/mcu/AT89C2051.png b/icons/mcu/AT89C2051.png
new file mode 100644
index 0000000..6211ccf
--- /dev/null
+++ b/icons/mcu/AT89C2051.png
Binary files differ
diff --git a/icons/mcu/AT89C4051.png b/icons/mcu/AT89C4051.png
new file mode 100644
index 0000000..6211ccf
--- /dev/null
+++ b/icons/mcu/AT89C4051.png
Binary files differ
diff --git a/icons/mcu/AT89C51.png b/icons/mcu/AT89C51.png
new file mode 100644
index 0000000..5fe430d
--- /dev/null
+++ b/icons/mcu/AT89C51.png
Binary files differ
diff --git a/icons/mcu/AT89C51RC.png b/icons/mcu/AT89C51RC.png
new file mode 100644
index 0000000..f0c0b8b
--- /dev/null
+++ b/icons/mcu/AT89C51RC.png
Binary files differ
diff --git a/icons/mcu/AT89C52.png b/icons/mcu/AT89C52.png
new file mode 100644
index 0000000..d2c7244
--- /dev/null
+++ b/icons/mcu/AT89C52.png
Binary files differ
diff --git a/icons/mcu/AT89C55WD.png b/icons/mcu/AT89C55WD.png
new file mode 100644
index 0000000..3e753a6
--- /dev/null
+++ b/icons/mcu/AT89C55WD.png
Binary files differ
diff --git a/icons/mcu/AT89LP2052.png b/icons/mcu/AT89LP2052.png
new file mode 100644
index 0000000..83f797d
--- /dev/null
+++ b/icons/mcu/AT89LP2052.png
Binary files differ
diff --git a/icons/mcu/AT89LS51.png b/icons/mcu/AT89LS51.png
new file mode 100644
index 0000000..4bc7ffb
--- /dev/null
+++ b/icons/mcu/AT89LS51.png
Binary files differ
diff --git a/icons/mcu/AT89LS52.png b/icons/mcu/AT89LS52.png
new file mode 100644
index 0000000..1b2441a
--- /dev/null
+++ b/icons/mcu/AT89LS52.png
Binary files differ
diff --git a/icons/mcu/AT89LV51.png b/icons/mcu/AT89LV51.png
new file mode 100644
index 0000000..4180a1b
--- /dev/null
+++ b/icons/mcu/AT89LV51.png
Binary files differ
diff --git a/icons/mcu/AT89LV52.png b/icons/mcu/AT89LV52.png
new file mode 100644
index 0000000..68b56d6
--- /dev/null
+++ b/icons/mcu/AT89LV52.png
Binary files differ
diff --git a/icons/mcu/AT89LV55.png b/icons/mcu/AT89LV55.png
new file mode 100644
index 0000000..967000f
--- /dev/null
+++ b/icons/mcu/AT89LV55.png
Binary files differ
diff --git a/icons/mcu/AT89S2051.png b/icons/mcu/AT89S2051.png
new file mode 100644
index 0000000..34787e0
--- /dev/null
+++ b/icons/mcu/AT89S2051.png
Binary files differ
diff --git a/icons/mcu/AT89S4051.png b/icons/mcu/AT89S4051.png
new file mode 100644
index 0000000..34787e0
--- /dev/null
+++ b/icons/mcu/AT89S4051.png
Binary files differ
diff --git a/icons/mcu/AT89S52.png b/icons/mcu/AT89S52.png
new file mode 100644
index 0000000..37a0685
--- /dev/null
+++ b/icons/mcu/AT89S52.png
Binary files differ
diff --git a/icons/mcu/AT89S8253.png b/icons/mcu/AT89S8253.png
new file mode 100644
index 0000000..fd3ac45
--- /dev/null
+++ b/icons/mcu/AT89S8253.png
Binary files differ
diff --git a/icons/mcu/T83C5101.png b/icons/mcu/T83C5101.png
new file mode 100644
index 0000000..3ca786c
--- /dev/null
+++ b/icons/mcu/T83C5101.png
Binary files differ
diff --git a/icons/mcu/T83C5102.png b/icons/mcu/T83C5102.png
new file mode 100644
index 0000000..3ca786c
--- /dev/null
+++ b/icons/mcu/T83C5102.png
Binary files differ
diff --git a/icons/mcu/T87C5101.png b/icons/mcu/T87C5101.png
new file mode 100644
index 0000000..3ca786c
--- /dev/null
+++ b/icons/mcu/T87C5101.png
Binary files differ
diff --git a/icons/mcu/TS80C31X2.png b/icons/mcu/TS80C31X2.png
new file mode 100644
index 0000000..3c14dc7
--- /dev/null
+++ b/icons/mcu/TS80C31X2.png
Binary files differ
diff --git a/icons/mcu/TS80C32X2.png b/icons/mcu/TS80C32X2.png
new file mode 100644
index 0000000..c3c18e4
--- /dev/null
+++ b/icons/mcu/TS80C32X2.png
Binary files differ
diff --git a/icons/mcu/TS80C52X2.png b/icons/mcu/TS80C52X2.png
new file mode 100644
index 0000000..c3c18e4
--- /dev/null
+++ b/icons/mcu/TS80C52X2.png
Binary files differ
diff --git a/icons/mcu/TS80C54X2.png b/icons/mcu/TS80C54X2.png
new file mode 100644
index 0000000..1a3ff11
--- /dev/null
+++ b/icons/mcu/TS80C54X2.png
Binary files differ
diff --git a/icons/mcu/TS80C58X2.png b/icons/mcu/TS80C58X2.png
new file mode 100644
index 0000000..1a3ff11
--- /dev/null
+++ b/icons/mcu/TS80C58X2.png
Binary files differ
diff --git a/icons/mcu/TS87C52X2.png b/icons/mcu/TS87C52X2.png
new file mode 100644
index 0000000..c3c18e4
--- /dev/null
+++ b/icons/mcu/TS87C52X2.png
Binary files differ
diff --git a/icons/mcu/TS87C54X2.png b/icons/mcu/TS87C54X2.png
new file mode 100644
index 0000000..1a3ff11
--- /dev/null
+++ b/icons/mcu/TS87C54X2.png
Binary files differ
diff --git a/icons/mcu/TS87C58X2.png b/icons/mcu/TS87C58X2.png
new file mode 100644
index 0000000..1a3ff11
--- /dev/null
+++ b/icons/mcu/TS87C58X2.png
Binary files differ
diff --git a/icons/other/choff.png b/icons/other/choff.png
new file mode 100644
index 0000000..ba156e8
--- /dev/null
+++ b/icons/other/choff.png
Binary files differ
diff --git a/icons/other/chon.png b/icons/other/chon.png
new file mode 100644
index 0000000..98d20a0
--- /dev/null
+++ b/icons/other/chon.png
Binary files differ
diff --git a/icons/other/ibrg_brg.png b/icons/other/ibrg_brg.png
new file mode 100644
index 0000000..9f1df6f
--- /dev/null
+++ b/icons/other/ibrg_brg.png
Binary files differ
diff --git a/icons/other/math0.png b/icons/other/math0.png
new file mode 100644
index 0000000..93c427b
--- /dev/null
+++ b/icons/other/math0.png
Binary files differ
diff --git a/icons/other/raoff.png b/icons/other/raoff.png
new file mode 100644
index 0000000..cfd2cf0
--- /dev/null
+++ b/icons/other/raoff.png
Binary files differ
diff --git a/icons/other/raon.png b/icons/other/raon.png
new file mode 100644
index 0000000..5180124
--- /dev/null
+++ b/icons/other/raon.png
Binary files differ
diff --git a/icons/other/splash.png b/icons/other/splash.png
new file mode 100644
index 0000000..d844f57
--- /dev/null
+++ b/icons/other/splash.png
Binary files differ
diff --git a/icons/other/timer2_updown.png b/icons/other/timer2_updown.png
new file mode 100644
index 0000000..faec869
--- /dev/null
+++ b/icons/other/timer2_updown.png
Binary files differ
diff --git a/icons/other/timer_01_0.png b/icons/other/timer_01_0.png
new file mode 100644
index 0000000..70c8bb5
--- /dev/null
+++ b/icons/other/timer_01_0.png
Binary files differ
diff --git a/icons/other/timer_01_0e.png b/icons/other/timer_01_0e.png
new file mode 100644
index 0000000..8c663d1
--- /dev/null
+++ b/icons/other/timer_01_0e.png
Binary files differ
diff --git a/icons/other/timer_01_1.png b/icons/other/timer_01_1.png
new file mode 100644
index 0000000..7fd91a7
--- /dev/null
+++ b/icons/other/timer_01_1.png
Binary files differ
diff --git a/icons/other/timer_01_1e.png b/icons/other/timer_01_1e.png
new file mode 100644
index 0000000..b8bdb4e
--- /dev/null
+++ b/icons/other/timer_01_1e.png
Binary files differ
diff --git a/icons/other/timer_01_2.png b/icons/other/timer_01_2.png
new file mode 100644
index 0000000..990ea9a
--- /dev/null
+++ b/icons/other/timer_01_2.png
Binary files differ
diff --git a/icons/other/timer_01_2e.png b/icons/other/timer_01_2e.png
new file mode 100644
index 0000000..d3e1885
--- /dev/null
+++ b/icons/other/timer_01_2e.png
Binary files differ
diff --git a/icons/other/timer_brg.png b/icons/other/timer_brg.png
new file mode 100644
index 0000000..2f246f5
--- /dev/null
+++ b/icons/other/timer_brg.png
Binary files differ
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..ab4357d
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+# --------------------------------------------------------
+# Copyright (C) Martin Ošmera <martin.osmera@gmail.com>
+# Licence: GPL
+# Version: 1.3.0
+# Homepage: http://mcu8051ide.sf.net
+# --------------------------------------------------------
+#
+# Installation script for MCU 8051 IDE
+# Usage:
+# ./install [--help | --uninstall]
+# ./install --no-check
+# --------------------------------------------------------
+
+
+echo "+--------------------------------------------------+"
+echo "| IMPORTANT NOTICE: |"
+echo "| |"
+echo "| This installation method is deprecated and will |"
+echo "| be removed in future versions ! |"
+echo "| Use 'cmake . && make && make install' instead. |"
+echo "+--------------------------------------------------+"
+
+if [ $UID -ne 0 ]; then
+ echo "You must have root privileges in order to perform installation"
+ exit 1
+fi
+
+check_for_library() {
+ echo -n "Checking for ${1} ..."
+ if ./test-lib.sh ${1} ${2} >> /dev/null; then
+ echo "Ok"
+ else
+ echo "FAILED"
+ echo
+ echo "Please install the missing library or:"
+ echo "\$ ./install.sh --no-check"
+ echo "\$ mcu8051ide --check-libraries"
+ echo "and see exactly what is missing"
+ exit 1
+ fi
+}
+
+if [ "${1}" = "--help" ] || [ "${1}" = "-h" ]; then
+ echo "Installation script for MCU 8051 IDE"
+ echo " Installation:"
+ echo " ./install.sh"
+ echo " Installation without checking for libraries:"
+ echo " ./install.sh --no-check"
+ echo " Uninstallation:"
+ echo " ./install.sh --uninstall"
+ echo ""
+ exit
+fi
+
+if [ "${1}" = "--uninstall" ]; then
+ echo "Uninstalling MCU 8051 IDE"
+ rm -rfv /usr/share/mcu8051ide || exit 1
+ rm -fv /usr/bin/mcu8051ide || exit 1
+ rm -fv /usr/share/man/man1/mcu8051ide.1.gz
+ echo "Uninstallation successful"
+ exit
+fi
+
+echo "Installing MCU 8051 IDE"
+echo
+
+if [ "${1}" != "--no-check" ]; then
+ check_for_library BWidget 1.8.0
+ check_for_library Itcl 3.4
+ check_for_library Tcl 8.2
+ check_for_library md5 2.0
+ check_for_library Tk 8.5
+ check_for_library img::png 1.3
+ check_for_library tdom 0.8
+ check_for_library Tclx 8.4
+fi
+
+echo "Creating launcher"
+./make-launcher --path-to-lib=/usr/share/mcu8051ide/lib || exit 1
+
+echo "Creating destination directory: /usr/share/mcu8051ide"
+mkdir -p /usr/share/mcu8051ide || exit 1
+
+echo "Copying files"
+cp -prv ./{demo,doc,lib,icons,data,translations} /usr/share/mcu8051ide || exit 1
+
+echo "Copying manual page"
+cp -pv ./doc/man/mcu8051ide.1.gz /usr/share/man/man1/mcu8051ide.1.gz
+
+echo "Copying .desktop spec and application icon"
+mkdir -p /usr/share/applications
+mkdir -p /usr/share/pixmaps
+cp -pv ./mcu8051ide.png /usr/share/pixmaps/mcu8051ide.png
+cp -pv ./mcu8051ide.desktop /usr/share/applications/mcu8051ide.desktop
+
+echo "Copying launcher"
+cp -prv mcu8051ide /usr/bin || exit 1
+
+echo
+echo "Installation successful"
diff --git a/lib/X.tcl b/lib/X.tcl
new file mode 100755
index 0000000..0875d3d
--- /dev/null
+++ b/lib/X.tcl
@@ -0,0 +1,10648 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# "Provides various dialogs and various variables for various things"
+# For instance the "Go to" dialog is placed here
+# --------------------------------------------------------------------------
+
+# Dialog for selecting MCU and loading MCU details from definition file
+source "${::LIB_DIRNAME}/dialogs/selectmcu.tcl"
+
+namespace eval X {
+
+ ## General
+ variable unsaved_projects {} ;# List: List of project object marked as "unsaved"
+ variable critical_procedure_in_progress 1 ;# Bool: Disable critical procedures (like compilation, start simulator, etc.)
+ variable foo_procedure_in_progress 0 ;# Bool: Disables some non-critical procedures
+ variable last_WIN_GEOMETRY {} ;# Last window geometry (main window)
+ variable actualProject {} ;# Object: Current project
+ variable openedProjects {} ;# List of opened projects (Object references)
+ variable actualProjectIdx -1 ;# Index of the current project in $openedProjects
+ variable project_menu_locked 1 ;# Bool: Indicates than there is at least one opened project
+ if {!$::MICROSOFT_WINDOWS} {
+ variable defaultDirectory ${::env(HOME)} ;# Default directory
+ } {
+ variable defaultDirectory ${::env(USERPROFILE)} ;# Default directory
+ }
+ variable simulator_enabled {} ;# List of booleans: Simulator engaged
+ variable editor_lines ;# Number of lines in the current editor
+ variable fsd_result {} ;# Value returnded by file selection dialog (in some cases)
+ variable projectmenu {.project_menu} ;# ID of Popup menu for project tabs
+ variable projectmenu_project {} ;# Object: project selected by project popup menu
+ variable selectedView ;# Int: Selected editor by editor statusbar popup menu
+ variable open_f_external_editor 0 ;# Bool: Use procedure __open to open new file for embedded external editor
+ variable file_recent_files {} ;# List: recently opened files
+ variable project_recent_files {} ;# List: recently opened projects
+ variable vhw_recent_files {} ;# List: recently opened Virtual HW files
+ # List of supported processors
+ variable avaliable_processors [::SelectMCU::get_avaliable_processors]
+ variable procedure_exit_in_progress 0 ;# Bool: proc "__exit" in progress
+
+ ## Doxygen
+ variable doxygen_run_doxywizard 0 ;# Bool: Run doxywizard
+ variable doxygen_build_api_doc 0 ;# Bool: Build API documentation
+ variable doxygen_pid 0 ;# Int: Doxygen PID
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+
+ ## ASCII chart
+ variable ascii_chart_win_object {} ;# Object: ASCII chart window object
+
+ ## 8-segment LED editor
+ variable eightsegment_editors {} ;# List: All 8-segment LED display editors invoked
+
+ ## Base convertor
+ variable base_convertors {} ;# List: All base convertor objects
+
+ ## Special calculator
+ variable spec_calc_objects {} ;# List: All special calculator objects
+
+ ## UART/RS232 debugger
+ variable rs232debugger_objects {} ;# List: All "RS232 debugger" objects
+
+ ## Dialog "Go to"
+ variable goto ;# Line where to go
+
+ ## Function "Auto-indent"
+ variable reformat_code_abort ;# Bool: Abort function 'reformat_code'
+
+ ## Dialog "Find"
+ variable find_String ;# Search string
+ variable find_forward_index ;# Search index for forward search
+ variable find_backward_index ;# Search index for backward search
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_notCS ;# Bool: Case insensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable find_allow_selection ;# Bool: There is some selected text in editor
+ variable find_retry_search ;# Bool: Search restarted from begining/end
+ variable find_back_dir ;# Bool: Search backwards (real option)
+ variable find_history {} ;# List of the last 10 search strings
+ variable find_next_prev_in_P 0 ;# Bool: Procedure 'find_next_prev' in progress
+
+ ## Dialog "Replace"
+ variable replace_String ;# String to replace
+ variable replace_Replacement ;# Replacement for the search string
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_prompt ;# Bool: Prompt on replace
+ variable replace_prompt_opened 0 ;# Bool: Replace prompt dialog opened
+ variable replace_prompt_return_value ;# Replace prompt dialog return value
+ variable replace_prompt_geometry ;# Geometry of replace prompt dialog window
+ variable replace_search_history {} ;# List of the last 10 search strings
+ variable replace_repl_history {} ;# List of the last 10 replacement strings
+
+ ## Dialog "Select directory"
+ variable select_directory_var {} ;# Selected directory
+
+ ## Dialog "New project"
+ variable project_new_name ;# Name of the new project
+ variable project_new_dir ;# Directory of the new project
+
+ ## Variable common for "New project" and "Edit project"
+ variable project_new_processor ;# Processor type (e.g. "8051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable project_new_max_xcode ;# Int: Maximum valid value of external program memory
+ variable project_new_xd_chb ;# Widget: XDATA enable checkbutton
+ variable project_new_xd_scl ;# Widget: XDATA scale
+ variable project_new_xd_spb ;# Widget: XDATA spinbox
+ variable project_new_xc_chb ;# Widget: XCODE enable checkbutton
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ ## Dialog "Edit project"
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_authors ;# Project authors
+ variable project_edit_description ;# Project description
+ variable project_edit_clock ;# Default clock rate
+ variable project_edit_main_file ;# Project main file
+ variable project_edit_main_file_clr_but ;# Widget: Project main file clear button
+ # Some default project values
+ # format: {{variable value} {variable value} ...}
+ variable project_edit_defaults {
+ {project_edit_family 8051 }
+ {project_edit_clock 12000 }
+ {project_edit_calc_rad Dec }
+ {project_edit_calc_ang rad }
+ }
+
+ ## Functions related to project management (save, load)
+ variable project_watches_file ;# File of register watches of the current poject
+ variable project_todo ;# Todo text
+ variable project_graph ;# Graph configuration list
+ variable project_calculator ;# Calculator list (display contents, etc.)
+ variable project_other_options ;# Other project options
+ variable project_compiler_options ;# Compiler options
+ variable project_files ;# List of project files (special format)
+ variable project_file ;# Full name of the project file
+ variable project_dir ;# Path to project directory
+
+ ## Compilation related variables
+ variable compilation_success_callback {} ;# String: Indented for HW plugins
+ variable compilation_fail_callback {} ;# String: Indented for HW plugins
+ variable compilation_mess_project {} ;# Object: Project related to running compilation
+ variable compilation_successfull 1 ;# Bool: Compilation successfull
+ variable compilation_in_progress 0 ;# Bool: Compiler engaged
+ variable compilation_progress 0 ;# Variable for compilation progressbar
+ variable compiler_pid 0 ;# Int: PID of external compiler if used
+ variable compilation_start_simulator 0 ;# Bool: Start simulator after successful compilation
+ variable compile_this_file_only 0 ;# Bool: Compile the current file only
+
+ ## Dialog "Select input/uotput file"
+ variable input_file ;# Input file
+ variable output_file ;# Output file
+ variable IO ;# Bool: 1 == choose input file; 0 == choose output file
+
+ ### Dialogs "Hex->Bin; Bin->Hex; Sim->Hex; Sim->Bin; Nomalize Hex"
+ # Type of conversion
+ # 0 == Bin -> Hex
+ # 1 == Hex -> Bin
+ # 2 == Sim -> Hex
+ # 3 == Sim -> Bin
+ variable hex__bin
+
+ ## XDATA/CODE/ERAM/EEPROM/UNI memory hexadecimal editors
+ variable opended_code_mem_windows {} ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects {} ;# List of CODE memory hex editor objects
+ variable opended_xdata_mem_windows {} ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects {} ;# List of XDATA memory hex editor objects
+ variable opended_eram_windows {} ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects {} ;# List of ERAM hex editor objects
+ variable opended_eeprom_mem_windows {} ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects {} ;# List of data EEPROM hex editor objects
+ variable opended_eeprom_wr_bf_windows {} ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects {} ;# List of data EEPROM write buffer hex editor objects
+ variable eeprom_wr_buf_counter 0 ;# Counter of EEPROM write buffer hex editor objects
+ variable saving_progress 0 ;# Variable for progressbars representing saving progress
+ variable abort_saving 0 ;# Bool: Abort saving of IHEX8 file
+ variable independent_hexeditor_count 0 ;# Counter of intances of independent hexadecimal editor
+
+ # Path to file defining the last session
+ variable session_file "${::CONFIG_DIR}/last_session.conf"
+
+ ## Dialog "Cleanup project folder"
+ # GLOB patterns in certain order !
+ variable cleanup_masks {
+ *.asm~ *.lst~ *.sim~ *.hex~
+ *.bin~ *.html~ *.tex~ *.wtc~
+ *.mcu8051ide~ *.m5ihib~ *.cdb~ *.ihx~
+ *.adf~ *.omf~ *.map~ *.c~
+ *.h~ *.vhc~ *.vhw~ *.txt~
+ *~
+
+ *.lst *.sim *.hex *.bin *.html *.tex *.m5ihib
+ *.noi *.obj *.map *.p *.mac *.i *.ihx
+ *.adf *.adb *.rel *.cdb *.mem *.lnk *.sym
+ *.omf *.rst *.hashes *bak
+ }
+
+ ## Dialog "Change letter case"
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ ## Dialog "Line to address"
+ variable line2pc ;# Int: Selected line in source code
+ variable line2pc_jump 1 ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable line2pc_line_max ;# Int: Number of lines in the source code
+ variable line2pc_value_lbl ;# Widget: Label containing PC value
+ variable line2pc_new_value ;# Int: Resolved address or {}
+ variable line2pc_org_line ;# Int: Original line
+ variable line2pc_ok_button ;# Widget: Button "OK"
+ variable line2pc_file_number ;# Int: File number
+
+ ## Dialog "File statistics"
+ variable statistics_counter 0 ;# Int: Counter of invocations of this dialog
+
+ ## Project details window
+ variable PROJECTDETAILSWIN ;# ID of project details window
+ variable projectdetails_last_project {} ;# Project object of the last project details window
+
+ ## Cutom commands related variables
+ variable custom_cmd_dialog_index 0 ;# Index of results dialog (to keep win IDs unique)
+ variable custom_command_cmd ;# Array of custom commands (shell scripts)
+ variable custom_command_options ;# Array of Lists of custom command options
+ variable custom_command_desc ;# Array of custom command descriptions
+ variable custom_command_PID ;# Array of custom command PIDs (Process IDentifiers)
+ variable custom_command_NUM ;# Array of custom command numbers
+ variable custom_command_counter 0 ;# Counter of custom command invocations
+
+ ## Initialize custom commands related variables
+ # Shell scripts
+ set custom_command_cmd(0) [mc "echo \"This is a custom command\"\necho \"\tYou can configure it in Main menu->Configure->Edit user commands.\"\necho \"\tCustom commands are intended for running external programs from this IDE (e.g. program uploaders)\""]
+ append custom_command_cmd(0) "\n\necho \"\nThis is a custom command\"\necho \"\tYou can configure it in Main menu->Configure->Edit user commands.\"\necho \"\tCustom commands are intended for running external programs from this IDE (e.g. program uploaders)\""
+ set custom_command_cmd(1) $custom_command_cmd(0)
+ set custom_command_cmd(2) $custom_command_cmd(0)
+ # Command options
+ set custom_command_options(0) {0 1 0}
+ set custom_command_options(1) $custom_command_options(0)
+ set custom_command_options(2) $custom_command_options(0)
+ # Command descritpions
+ set custom_command_desc(0) [mc "More: Main menu -> Configure -> Edit user commands"]
+ set custom_command_desc(1) $custom_command_desc(0)
+ set custom_command_desc(2) $custom_command_desc(0)
+ # Command Thread IDentifiers
+ set custom_command_PID(0) {}
+ set custom_command_PID(1) $custom_command_PID(0)
+ set custom_command_PID(2) $custom_command_PID(0)
+ # Custom command numbers
+ set custom_command_NUM(0) {}
+ set custom_command_NUM(1) $custom_command_NUM(0)
+ set custom_command_NUM(2) $custom_command_NUM(0)
+
+ ## Menu and Toolbar related variables
+ # Menu bar items which require opened project
+ variable mainmenu_project_dependent_buttons {
+ { ".mainMenu"
+ { "Edit" "View" "Simulator" "Virtual MCU" "Virtual HW" "Tools"}
+ } { ".mainMenu.project"
+ { "Save" "Edit project" "Close without saving" "Save and close"}
+ } { ".mainMenu.file"
+ { "New" "Open" "Open recent" "Save" "Save as" "Save all" "Close" "Close all" "File statistics"}
+ } { ".mainMenu.configure"
+ { "Configure Compiler"}
+ }
+ }
+ # Menu bar items which require ENGAGED simulator
+ variable mainmenu_simulator_engaged {
+ { ".mainMenu.simulator"
+ { "Step" "Step over" "Animate" "Run"
+ "Jump to line" "Find cursor" "Step back" "Clear highlight"
+ "Hiberante program" "Resume hibernated program"
+ }
+ } { ".mainMenu.virtual_mcu"
+ { "Reset" }
+ }
+ }
+ # Menu bar items which require DISENGAGED simulator
+ variable mainmenu_simulator_disengaged {
+ { ".mainMenu.file"
+ { "New" "Open" "Close" "Close all"}
+ } { ".mainMenu.edit"
+ { "Undo" "Redo" "Cut" "Paste" "Replace"
+ "Comment" "Uncomment" "Indent" "Unindent"}
+ } { ".mainMenu.display"
+ { "Read only mode" "Reload"}
+ }
+ { ".mainMenu.simulator"
+ { "Debug this file only" }
+ } { ".mainMenu.tools"
+ { "Compile" "Disassemble" "Encoding" "End of line"
+ "Auto indent" "Change letter case" "Document current function"
+ "Compile this file"}
+ }
+ }
+ # Menu bar items which are not avaliable when editor is in read only mode
+ variable mainmenu_editor_readonly {
+ { ".mainMenu.edit"
+ { "Undo" "Redo" "Cut" "Paste" "Replace"
+ "Comment" "Uncomment" "Indent" "Unindent"}
+ } { ".mainMenu.tools"
+ { "Auto indent" "Change letter case" "Document current function"}
+ }
+ }
+ # Menu bar items which are not avaliable only for C language
+ variable mainmenu_editor_c_only {
+ { ".mainMenu.tools"
+ { "Document current function"}
+ }
+ }
+ # Menu bar items which are not avaliable when external embedded editor is used
+ variable mainmenu_editor_external_na {
+ {.mainMenu.tools {
+ {Encoding} {End of line}
+ {Auto indent} {Change letter case}
+ {Export as XHTML} {Export as LaTeX}
+ {Auto indent} {Change letter case}
+ {Document current function}
+ }
+ } {.mainMenu.file {
+ {Save} {Save as}
+ {Save all} {File statistics}
+ }
+ } {.mainMenu.display {
+ {Read only mode} {Switch to command line}
+ {Highlight} {Show/Hide line numbers}
+ {Reload} {Show/Hide icon border}
+ }
+ } {.mainMenu.simulator {
+ {Find cursor} {Jump to line}
+ }
+ } {.mainMenu {
+ {Edit}
+ }
+ }
+ }
+
+ # Toolbar buttons which require opened project
+ variable toolbar_project_dependent_buttons {
+ new open save save_as save_all close close_all undo redo cut
+ copy paste find findnext findprev replace goto reload clear
+ proj_save proj_edit proj_close proj_close_imm show_code_mem
+ show_ext_mem start_sim reset step stepover animate run
+ assemble disasm reformat_code toHTML toLaTeX cleanup custom0
+ custom1 custom2 change_case forward back clear_hg intrmon
+ hibernate resume stepback find_sim_cur line2addr show_exp_mem
+ sfrmap show_eeprom show_eem_wr_b stopwatch bitmap
+
+ ledpanel leddisplay ledmatrix mleddisplay simplekeypad
+ matrixkeypad vhw_open vhw_load vhw_save vhw_saveas
+ vhw_remove_all
+
+ stack
+ }
+ # Toolbar buttons which require ENGAGED simulator
+ variable toolbar_simulator_engaged {
+ reset step stepover animate run clear_hg
+ find_sim_cur line2addr stepback hibernate resume
+ }
+ # Toolbar buttons which require DISENGAGED simulator
+ variable toolbar_simulator_disengaged {
+ new open close close_all undo redo cut
+ copy paste replace reload assemble start_sim0
+ disasm reformat_code change_case assemble0
+ }
+ # Toolbar items which are not avaliable when editor is in read only mode
+ variable toolbar_editor_readonly {
+ undo redo cut paste replace reformat_code change_case
+ }
+ # Toolbar items which are not avaliable only for C language
+ variable toolbar_editor_c_only {
+ }
+ # Toolbar items which are not avaliable when external embedded editor is used
+ variable toolbar_editor_external_na {
+ save save_as undo redo cut
+ copy paste find findnext findprev
+ replace goto reload reformat_code change_case
+ toHTML toLaTeX find_sim_cur line2addr save_all
+ }
+
+ ## This function should be immediately after load of environment.tcl
+ # @return void
+ proc initialize {} {
+ variable projectmenu ;# ID of Popup menu for project tabs
+
+ menuFactory {
+ {command "Save" "$project:proj_save" 0
+ {__project_pmenu_save}
+ "filesave" "Save this project"}
+ {command "Edit project" "$project:proj_edit" 0
+ {__project_pmenu_edit}
+ "configure" "Edit additional project detail"}
+ {separator}
+ {command "Save and close" "$project:proj_close" 1
+ {__project_pmenu_close}
+ "fileclose" "Save and close this project"}
+ {command "Close without saving" "$project:proj_clsimm" 0
+ {__project_pmenu_close_imm}
+ "no" "Close this project"}
+ {separator}
+ {command "Move left" "" 5
+ {__project_move_to_left}
+ "1leftarrow" "Move this tab to right the beginning of the tab bar"}
+ {command "Move right" "" 5
+ {__project_move_to_right}
+ "1rightarrow" "Move this tab to right the end of the tab bar"}
+ {separator}
+ {command "Move to beginning" "" 8
+ {__project_move_to_beginning}
+ "2leftarrow" "Move this tab to right the beginning of the tab bar"}
+ {command "Move to end" "" 9
+ {__project_move_to_end}
+ "2rightarrow" "Move this tab to right the end of the tab bar"}
+ } $projectmenu 0 "::X::" 0 {}
+ }
+
+ ## Switch current project
+ # @parm String project_name - Project object reference
+ # @return void
+ proc switch_project {project_name} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable openedProjects ;# List of opened projects (Object references)
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+
+ # Ensure that autocompletion window is closed
+ ::Editor::close_completion_popup_window_NOW
+
+ if {$actualProjectIdx != -1 && ([lindex $simulator_enabled $actualProjectIdx] == 1)} {
+ if {[$actualProject sim_stepover_in_progress]} {
+ $actualProject sim_stepover
+ } elseif {[$actualProject sim_run_in_progress]} {
+ $actualProject sim_run
+ } elseif {[$actualProject sim_anim_in_progress]} {
+ $actualProject sim_animate
+ }
+ }
+
+ set actualProject [string trimleft $project_name {:}]
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+
+ disaena_menu_toolbar_for_current_project
+ adjust_title
+
+ $actualProject adjust_compiler_settings
+ }
+
+ ## Enable / Disable menu and toolbar item acording to current state of current project
+ # @return void
+ proc disaena_menu_toolbar_for_current_project {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+
+ # This procedure requires at least one opened project
+ if {$project_menu_locked} {return}
+
+ # Adjust state simulator related menu/toolbar items
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ Unlock_simulator_menu
+
+ # Enable / Disabled stepback buttons
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ } {
+ Lock_simulator_menu
+ adjust_mainmenu_and_toolbar_to_editor \
+ ${::editor_RO_MODE} \
+ [expr {1 == [$actualProject editor_procedure {} get_language {}]}]
+ }
+
+ ## Disable/Enable menu+toolbar entries related to simulator controls which depends on current MCU
+ disena_simulator_menu $actualProject
+ }
+
+ ## Disable/Enable menu+toolbar entries related to simulator
+ # +controls which depends on current MCU
+ # @parm Object project - Current project
+ # @return void
+ proc disena_simulator_menu {project} {
+ # Enable/Disable controls related to hexadecimal editors
+ ena_dis_menu_buttons 0 {{ ".mainMenu.virtual_mcu"
+ { "Show XDATA memory" "Show ERAM" "Show EEPROM write buffer" "Show Data EEPROM"}
+ }}
+ ena_dis_iconBar_buttons 0 .mainIconBar. {
+ show_ext_mem show_exp_mem show_eeprom show_eem_wr_b
+ }
+ set toolbar {}
+ set mainmenu {}
+ if {[lindex [$project cget -procData] 8]} {
+ lappend toolbar {show_exp_mem}
+ lappend mainmenu {Show ERAM}
+ }
+ if {[$project cget -P_option_mcu_xdata]} {
+ lappend toolbar {show_ext_mem}
+ lappend mainmenu {Show XDATA memory}
+ }
+ if {[lindex [$project cget -procData] 32]} {
+ lappend toolbar {show_eeprom}
+ lappend toolbar {show_eem_wr_b}
+ lappend mainmenu {Show EEPROM write buffer}
+ lappend mainmenu {Show Data EEPROM}
+ }
+ ena_dis_menu_buttons 1 [list [list {.mainMenu.virtual_mcu} $mainmenu]]
+ ena_dis_iconBar_buttons 1 .mainIconBar. $toolbar
+ }
+
+ ## Ensure than simulator isn't engaged
+ # @parm Bool message - Invoke error message if simulator is engaged
+ # @return Bool - result (1 == is engaged; 0 == is not engaged)
+ proc simulator_must_be_disabled {message} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+
+ if {[lindex $simulator_enabled $actualProjectIdx] == {}} {
+ return 1
+ }
+
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ if {$message} {
+ tk_messageBox \
+ -title [mc "Unable to compile"] \
+ -icon info \
+ -type ok \
+ -message [mc "Simulator is engaged, shutdown the simulator first."]
+ }
+ return 1
+ }
+
+ return 0
+ }
+
+ ## New file
+ # @return void
+ proc __new {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # Use dialog "Open file" to create new file with embedded external editor
+ if {${::Editor::editor_to_use}} {
+ __open 1
+ return
+ }
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Create new editor
+ $actualProject editor_new
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Open file
+ # @parm Bool = 0 - 1 == New file (for embedded external editor); 0 == Open an existing file
+ # @return void
+ proc __open args {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable open_f_external_editor ;# Bool: Use procedure __open to open new file for embedded external editor
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Parse input arguments
+ set open_f_external_editor [lindex $args 0]
+ if {$open_f_external_editor != 1} {
+ set title [mc "Open file - MCU 8051 IDE"]
+ set open_f_external_editor 0
+ } {
+ set title [mc "New file - MCU 8051 IDE"]
+ set open_f_external_editor 1
+ }
+
+ # Invoke the file selection dialog
+ switch -- [file extension [lindex [$actualProject editor_procedure {} getFileName {}] 1]] {
+ {.asm} {set defaultmask 0}
+ {.c} {set defaultmask 1}
+ {.h} {set defaultmask 2}
+ {.lst} {set defaultmask 3}
+ default {set defaultmask 4}
+ }
+ set directory [lindex [$actualProject editor_procedure {} getFileName {}] 0]
+ if {$directory == {.}} {
+ set directory [$actualProject cget -projectPath]
+ }
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title $title -directory $directory \
+ -defaultmask $defaultmask -multiple 1 -filetypes [list \
+ [list [mc "Assembly language"] {*.asm}] \
+ [list [mc "C source"] {*.c}] \
+ [list [mc "C header"] {*.h}] \
+ [list [mc "Code listing"] {*.lst}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ fsd setokcmd {
+ foreach filename [X::fsd get] {
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+
+ if {[file isdirectory $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent . \
+ -title [mc "Operation aborted"] \
+ -message [mc "The file you choosed appears to be a directory:\n%s\n\nSuch an operation doesn't make sense." $filename]
+ continue
+ }
+
+ # Open the specified file
+ if {${::X::open_f_external_editor} || [file exists $filename]} {
+ if {[${X::actualProject} openfile $filename 1 \
+ [X::fsd get_window_name] def def 0 0 {}] != {}
+ } {
+ ${X::actualProject} switch_to_last
+ update idle
+ ${X::actualProject} editor_procedure {} parseAll {}
+
+ # Make LST read only
+ if {[file extension $filename] == {.lst}} {
+ set ::editor_RO_MODE 1
+ ${X::actualProject} switch_editor_RO_MODE
+ }
+
+ ::X::recent_files_add 1 $filename
+ }
+ } {
+ ${X::actualProject} editor_new
+ ${X::actualProject} save_as $filename
+ if {!${::Editor::editor_to_use}} {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent [::X::fsd get_window_name] \
+ -title [mc "File not found - MCU 8051 IDE"] \
+ -message [mc "The selected file do not exist:\n%s" $filename]
+ }
+ }
+ }
+ }
+
+ # activate the dialog
+ fsd activate
+
+ adjust_title
+ set critical_procedure_in_progress 0
+ }
+
+ ## Save file
+ # @return void
+ proc __save {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Save file
+ $actualProject editor_procedure {} save {}
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Save file under different filename
+ # @return void
+ proc __save_as {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Invoke the dialog
+ set filename [$actualProject editor_procedure {} getFileName {}]
+ switch -- [file extension [lindex $filename 1]] {
+ {.asm} {set defaultmask 0}
+ {.c} {set defaultmask 1}
+ {.h} {set defaultmask 2}
+ default {set defaultmask 3}
+ }
+ set directory [lindex [$actualProject editor_procedure {} getFileName {}] 0]
+ if {$directory == {.}} {
+ set directory [$actualProject cget -projectPath]
+ }
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -initialfile [lindex $filename 1] \
+ -title [mc "Save file - MCU 8051 IDE"] \
+ -directory $directory \
+ -defaultmask $defaultmask -multiple 0 -filetypes {
+ {{Assembly language} {*.asm} }
+ {{C source} {*.c} }
+ {{C header} {*.h} }
+ {{All files} {*} }
+ }
+
+ # Save file after press of OK button
+ fsd setokcmd {
+ set filename [X::fsd get]
+ ${X::actualProject} save_as $filename
+ }
+
+ # activate the dialog
+ fsd activate
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Save all opened file of the current project
+ # @return void
+ proc __save_all {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Save all opended files
+ $actualProject editor_save_all
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Close the curent file
+ # @return void
+ proc __close {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Close file
+ $actualProject editor_close 1 {}
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Close all opended files
+ # @return void
+ proc __close_all {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Close all files
+ $actualProject editor_close_all 1 0
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Take back the last operation
+ # @return void
+ proc __undo {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Undo
+ $actualProject editor_procedure {} undo {}
+ }
+
+ ## Take back the last undo operation
+ # @return void
+ proc __redo {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Redo
+ $actualProject editor_procedure {} redo {}
+ }
+
+ ## Copy selected text to clipboard
+ # @return void
+ proc __copy {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Copy
+ $actualProject editor_procedure {} copy {}
+ }
+
+ ## Cut selected text (copy to clipboard and remove)
+ # @return void
+ proc __cut {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Cut
+ $actualProject editor_procedure {} cut {}
+ }
+
+ ## Paste text from clipboard
+ # @return void
+ proc __paste {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Paste
+ $actualProject editor_procedure {} paste {}
+ }
+
+ ## Indent selected text or the current line
+ # @return void
+ proc __indent {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Indent
+ $actualProject editor_procedure {} indent {}
+ }
+
+ ## Unindent selected text or the current line
+ # @return void
+ proc __unindent {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Unindent
+ $actualProject editor_procedure {} unindent {}
+ }
+
+ ## Invoke find dialog
+ # @return void
+ proc __find {} {
+ variable actualProject ;# Object: Current project
+ variable find_String ;# Search string
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable find_allow_selection ;# Bool: There is some selected text in editor
+ variable find_history ;# List of the last 10 search strings
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {${::Editor::editor_to_use}} {return}
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Determinate selected text
+ set selectedText [$actualProject editor_procedure {} getselection {}]
+ if {$selectedText != {}} {
+ set find_String $selectedText
+ }
+
+ # Create a new toplevel window for the dialog
+ set win [toplevel .find -class {Find dialog} -bg {#EEEEEE}]
+
+ # String to search for
+ label $win.findLabel -compound left -image ::ICONS::16::find -text [mc "Text to find:"]
+ set findFrame [ttk::labelframe $win.findFrame \
+ -labelwidget $win.findLabel \
+ -relief flat \
+ ]
+ pack $findFrame -fill x -expand 1 -pady 10 -padx 5
+ pack [ttk::combobox $findFrame.entry \
+ -textvariable X::find_String \
+ -exportselection 0 \
+ -values $find_history \
+ ] -fill x -expand 1 -padx 10
+ DynamicHelp::add $findFrame.entry -text [mc "String to find"]
+
+ # Create and pack options labelframe
+ label $win.optionsLabel -compound left -image ::ICONS::16::configure -text [mc "Options"]
+ set optionsFrame [ttk::labelframe $win.optionsFrame \
+ -labelwidget $win.optionsLabel \
+ ]
+ pack $optionsFrame -fill both -expand 1 -padx 10
+
+ # Determinate wheather there is some selected text
+ if {[$actualProject editor_procedure {} getselection {}] == {}} {
+ set find_allow_selection 0
+ } {
+ set find_allow_selection 1
+ }
+
+ # Create matrix of option checkbuttons
+ set col 0 ;# Grid column
+ set row 0 ;# Grid row
+ foreach opt { CS back cur sel reg } \
+ txt { "Case sensitive" "Backwards" "From cursor" "Selected text" "Regular expr." } \
+ helptext {
+ {Case sensitive search}
+ {Search backwards from the specified location}
+ {Start search from cursor instead of begining}
+ {Search within selected text only}
+ {Use search string as regular expression}
+ } \
+ {
+ # Disable/Enable "in selection" checkbox
+ if {$opt == {sel} && !$find_allow_selection} {
+ set state disabled
+ set X::find_option_sel 0
+ } {
+ set state normal
+ }
+
+ # Create checkbutton
+ grid [checkbutton $optionsFrame.option_$opt \
+ -text [mc $txt] \
+ -variable X::find_option_$opt \
+ -state $state \
+ ] -column $col -row $row -sticky wns
+ DynamicHelp::add $optionsFrame.option_$opt -text $helptext
+
+ incr col
+ if {$col == 2} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $win.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::find_FIND} \
+ ] -side left -padx 2
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::find_CANCEL} \
+ ] -side left -padx 2
+ pack $buttonFrame -pady 5
+
+ # Events binding (Enter == Find; Escape == Cancel)
+ bind $win <KeyRelease-Return> {X::find_FIND; break}
+ bind $win <KeyRelease-KP_Enter> {X::find_FIND; break}
+ bind $win <KeyRelease-Escape> {X::find_CANCEL; break}
+
+ # Nessesary window manager options -- for modal window
+ wm iconphoto $win ::ICONS::16::find
+ wm title $win [mc "Find - MCU 8051 IDE"]
+ wm minsize $win 300 210
+ wm protocol $win WM_DELETE_WINDOW {
+ X::find_CANCEL
+ }
+ wm transient $win .
+ update
+ raise $win
+ catch {grab $win}
+ focus $findFrame.entry
+ catch {
+ $findFrame.entry.e selection range 0 end
+ }
+ tkwait window $win
+ }
+
+ ## Cancel find dialog -- auxiliary procedure for '__find'
+ # @return void
+ proc find_CANCEL {} {
+ if {![winfo exists .find]} {return}
+
+ destroy .find
+ grab release .find
+ }
+
+ ## Perform search -- auxiliary procedure for '__find'
+ # @return Bool - result
+ proc find_FIND {} {
+ variable actualProject ;# Object: Current project
+ variable find_allow_selection ;# Bool: There is some selected text in editor
+ variable find_String ;# Search string
+ variable find_forward_index ;# Search index for forward search
+ variable find_backward_index ;# Search index for backward search
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_notCS ;# Bool: Case insensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable find_retry_search ;# Bool: Search restarted from begining/end
+ variable find_back_dir ;# Bool: Search backwards (real option)
+ variable find_history ;# List of the last 10 search strings
+
+ # Append search string to history
+ if {[lsearch -exact -ascii $find_history $find_String] == -1} {
+ lappend find_history $find_String
+ }
+ # History mustn't contain more than 10 items
+ if {[llength $find_history] > 10} {
+ set find_history [lrange $find_history [expr {[llength $find_history] - 10}] end]
+ }
+
+ # New search
+ set find_retry_search 0 ;# Search has not been restarted
+ set find_back_dir $find_option_back ;# Search backwards/forwards
+
+ # Cancel the find dialog
+ find_CANCEL
+
+ # Check for validity of the search string
+ if {$find_String == {}} {
+ return 0
+ }
+
+ # Adjust option "Search in selected text"
+ set find_option_notCS [expr {!$find_option_CS}]
+ if {!$find_allow_selection} {
+ set option_sel 0
+ } {
+ set option_sel $find_option_sel
+ }
+
+ # Perform search
+ set result [$actualProject editor_procedure {} find [list \
+ $find_option_cur $find_option_back \
+ $find_option_reg $find_option_notCS \
+ $option_sel {} \
+ $find_String]]
+
+ # Search failed -> show error message
+ if {[lindex $result 0] == -1} {
+ tk_messageBox -icon warning \
+ -parent . -type ok \
+ -title [mc "Unable to execute"] \
+ -message [lindex $result 1]
+ return 0
+ }
+
+ # Set search indexes
+ set find_backward_index [lindex $result 0]
+ set find_forward_index [lindex $result 1]
+
+ # Finalize
+ set matches [lindex $result 2]
+ Sbar [mc "Search result: %s matches found" $matches] ;# Show final result
+ if {$matches == 0} retry_search ;# Ask for retry
+
+ # Success
+ return 1
+ }
+
+ ## Retry search -- auxiliary procedure for '__find'
+ # Useful when search cursor reach begining/end of the document
+ # @return Bool result
+ proc retry_search {} {
+ variable find_retry_search ;# Bool: Search restarted from begining/end
+ variable find_String ;# Search string
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_backward_index ;# Search index for backward search
+ variable find_forward_index ;# Search index for forward search
+ variable find_back_dir ;# Bool: Search backwards (real option)
+ variable find_next_prev_in_P ;# Bool: Procedure 'find_next_prev' in progress
+
+ # There is only one allowed retry
+ if {$find_retry_search || !$find_option_cur} {
+ set find_retry_search 0
+ tk_messageBox \
+ -icon warning \
+ -type ok \
+ -title [mc "Find - %s" ${::APPNAME}] \
+ -message [mc "Search string '%s' not found !" $find_String] \
+ -parent .
+ set find_next_prev_in_P 0
+ return
+ }
+
+ set find_option_cur_tmp $find_option_cur ;# Search cursor
+ set find_retry_search 1 ;# This is the first retry
+
+ # Backward search
+ if {$find_back_dir} {
+ if {[tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent . \
+ -title [mc "Find - %s" ${::APPNAME}] \
+ -message [mc "Begining of document reached\n\nContinue from end ?"] \
+ ]} {
+ set find_next_prev_in_P 0
+ set find_backward_index end
+ set find_forward_index 1.0
+ set find_option_cur 0
+ # Retry search
+ find_next_prev [expr {!$find_option_back}]
+ }
+
+ # Forward search
+ } {
+ if {[tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent . \
+ -title [mc "Find - %s" ${::APPNAME}] \
+ -message [mc "End of document reached\n\nContinue from begining ?"] \
+ ]} {
+ set find_next_prev_in_P 0
+ set find_backward_index end
+ set find_forward_index 1.0
+ set find_option_cur 0
+ # Retry search
+ find_next_prev $find_option_back
+ }
+ }
+
+ set find_next_prev_in_P 0
+ set find_option_cur $find_option_cur_tmp
+ set find_retry_search 0
+ }
+
+ ## Find next occurence of the search string
+ # @return void
+ proc __find_next {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Perform search
+ find_next_prev 0
+ }
+
+ ## Find previous occurence of the search string
+ # @return void
+ proc __find_prev {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Perform search
+ find_next_prev 1
+ }
+
+ ## Find next/previous occurence of the search string
+ # @parm Bool back_dir - Search backwards
+ # @return void
+ proc find_next_prev {back_dir} {
+ variable actualProject ;# Object: Current project
+ variable find_String ;# Search string
+ variable find_backward_index ;# Search index for backward search
+ variable find_forward_index ;# Search index for forward search
+ variable find_option_notCS ;# Bool: Case insensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable find_retry_search ;# Bool: Search restarted from begining/end
+ variable find_back_dir ;# Bool: Search backwards (real option)
+ variable find_next_prev_in_P ;# Bool: Procedure 'find_next_prev' in progress
+
+ # This function is not avaliable for exeternal embedded editors
+ if {${::Editor::editor_to_use}} {return}
+
+ # This function cannot run multithreaded
+ if {$find_next_prev_in_P} {return}
+ set find_next_prev_in_P 1
+
+ # Check for valid search index
+ if {![info exists find_backward_index]} {
+ Sbar [mc "Editor: Nothing to search ..."]
+ set find_next_prev_in_P 0
+ return
+ }
+
+ # Determinate direction
+ set find_back_dir [expr {$find_option_back ^ $back_dir}]
+
+ # Determinate start index
+ if {$find_option_cur} {
+ set editor [[$actualProject get_current_editor_object] cget -editor]
+ if {$find_back_dir} {
+ if {[$editor compare $find_forward_index == insert]} {
+ $editor mark set insert $find_backward_index
+ }
+ } {
+ if {[$editor compare $find_backward_index == insert]} {
+ $editor mark set insert $find_forward_index
+ }
+ }
+ set index insert
+ } {
+ if {$find_back_dir} {
+ set index $find_backward_index
+ } {
+ set index $find_forward_index
+ }
+ }
+
+ # Perform search
+ set result [$actualProject editor_procedure {} find [list \
+ $find_option_cur $find_back_dir \
+ $find_option_reg $find_option_notCS \
+ $find_option_sel $index \
+ $find_String]]
+
+ # Set search indexes
+ set find_backward_index [lindex $result 0]
+ set find_forward_index [lindex $result 1]
+
+ # Finalize
+ set matches [lindex $result 2]
+ Sbar [mc "Search result: %s matches found" $matches] ;# Show final result
+ if {$matches == 0} retry_search ;# Retry search if this one failed
+ set find_next_prev_in_P 0
+ }
+
+ ## Invoke dialog to replace one string with another (in editor)
+ # @return void
+ proc __replace {} {
+ variable actualProject ;# Object: Current project
+ variable replace_String ;# String to replace
+ variable replace_Replacement ;# Replacement for the search string
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_prompt ;# Bool: Prompt on replace
+ variable replace_search_history ;# List of the last 10 search strings
+ variable replace_repl_history ;# List of the last 10 replacement strings
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {${::Editor::editor_to_use}} {return}
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Determinate selected text
+ set selectedText [$actualProject editor_procedure {} getselection {}]
+ if {$selectedText != {}} {
+ set replace_String $selectedText
+ }
+
+ # Create a new toplevel window for the dialog
+ set win [toplevel .replace -class {Replace dialog} -bg {#EEEEEE}]
+
+ # Create labelframe "String to find"
+ label $win.findLabel -compound left -image ::ICONS::16::find -text [mc "Text to find: "]
+ set findFrame [ttk::labelframe $win.findFrame \
+ -labelwidget $win.findLabel \
+ -relief flat \
+ ]
+ pack $findFrame -fill x -expand 1 -pady 10 -padx 5
+ pack [ttk::combobox $findFrame.entry \
+ -textvariable X::replace_String \
+ -exportselection 0 \
+ -values $replace_search_history \
+ ] -fill x -expand 1 -padx 10
+ DynamicHelp::add $findFrame.entry -text [mc "String to replace"]
+ pack $findFrame
+
+ # Create labelframe "Replace with"
+ set replaceFrame [ttk::labelframe $win.replaceFrame \
+ -text [mc "Replace with:"] \
+ -relief flat \
+ ]
+ pack $replaceFrame -fill x -expand 1 -pady 5 -padx 5
+ pack [ttk::combobox $replaceFrame.entry \
+ -textvariable X::replace_Replacement \
+ -exportselection 0 \
+ -values $replace_repl_history \
+ ] -fill x -expand 1 -padx 10
+ DynamicHelp::add $replaceFrame.entry -text [mc "Replacement for search string"]
+
+ # Create and pack options checkboxes labelframe
+ label $win.optionsLabel -compound left -image ::ICONS::16::configure -text "Options"
+ set optionsFrame [ttk::labelframe $win.optionsFrame \
+ -labelwidget $win.optionsLabel \
+ ]
+ pack $optionsFrame -fill both -expand 1 -padx 10
+
+ # Create matrix of option checkboxes
+ set col 0 ;# Grid column
+ set row 0 ;# Grid row
+ foreach opt { CS back cur reg prompt} \
+ txt { "Case sensitive" "Backwards" "From cursor" "Regular expr." "Prompt on replace"} \
+ helptext {
+ {Case sensitive search}
+ {Search backwards from the specified location}
+ {Start search from cursor instead of begining}
+ {Use search string as regular expression}
+ {Prompt on replace}
+ } {
+
+ # Create checkbutton
+ grid [checkbutton $optionsFrame.option_$opt \
+ -text [mc $txt] \
+ -variable X::replace_option_$opt \
+ ] -column $col -row $row -sticky wns
+ DynamicHelp::add $optionsFrame.option_$opt -text $helptext
+
+ incr col
+ if {$col == 2} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $win.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::replace_REPLACE} \
+ ] -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::replace_CANCEL} \
+ ] -side left
+ pack $buttonFrame -pady 5
+
+ # Events binding (Enter == Replace; Escape == Cancel)
+ bind $win <KeyRelease-Return> {X::replace_REPLACE; break}
+ bind $win <KeyRelease-KP_Enter> {X::replace_REPLACE; break}
+ bind $win <KeyRelease-Escape> {X::replace_CANCEL; break}
+
+ # Nessesary window manager options -- for modal window
+ wm iconphoto $win ::ICONS::16::find
+ wm title $win [mc "Replace - MCU 8051 IDE"]
+ wm minsize $win 300 270
+ wm protocol $win WM_DELETE_WINDOW {
+ X::replace_CANCEL
+ }
+ wm transient $win .
+ update
+ raise $win
+ catch {grab $win}
+ focus $findFrame.entry
+ catch {
+ $findFrame.entry.e selection range 0 end
+ }
+ tkwait window $win
+ }
+
+ ## Perform replacement -- auxiliary procedure for '__replace'
+ # @return Bool - result
+ proc replace_REPLACE {} {
+ variable actualProject ;# Object: Current project
+ variable replace_String ;# String to replace
+ variable replace_Replacement ;# Replacement for the search string
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_prompt ;# Bool: Prompt on replace
+ variable replace_search_history ;# List of the last 10 search strings
+ variable replace_repl_history ;# List of the last 10 replacement strings
+
+ # Append search string to history
+ if {[lsearch -exact -ascii $replace_search_history $replace_String] == -1} {
+ lappend replace_search_history $replace_String
+ }
+ # History mustn't contain more than 10 items
+ if {[llength $replace_search_history] > 10} {
+ set replace_search_history [lrange $replace_search_history \
+ [expr {[llength $replace_search_history] - 10}] end]
+ }
+
+ # Append replace string to history
+ if {[lsearch -exact -ascii $replace_repl_history $replace_Replacement] == -1} {
+ lappend replace_repl_history $replace_Replacement
+ }
+ # History mustn't contain more than 10 items
+ if {[llength $replace_repl_history] > 10} {
+ set replace_repl_history [lrange \
+ $replace_repl_history \
+ [expr {[llength $replace_repl_history] - 10}] \
+ end \
+ ]
+ }
+
+ # Cancel the replace dialog
+ replace_CANCEL
+
+ # Perform replacement
+ set replace_option_notCS [expr {!$replace_option_CS}]
+ if {![$actualProject editor_procedure {} replace [list \
+ $replace_option_cur $replace_option_back \
+ $replace_option_reg $replace_option_notCS \
+ $replace_String $replace_Replacement \
+ $replace_option_prompt X::replace_prompt]
+ ]} {
+ if {!$replace_option_cur} {return}
+
+ set replace_option_cur_tmp $replace_option_cur
+ set replace_option_cur 0
+
+ # Retry search
+ if {$replace_option_back} {
+ if {[tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent . \
+ -title [mc "Replace - %s" ${::APPNAME}] \
+ -message [mc "Begining of document reached\n\nContinue from end ?"] \
+ ]} {
+ replace_REPLACE
+ }
+ } {
+ if {[tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent . \
+ -title [mc "Replace - %s" ${::APPNAME}] \
+ -message [mc "End of document reached\n\nContinue from begining ?"] \
+ ]} {
+ replace_REPLACE
+ }
+ }
+
+ set replace_option_cur $replace_option_cur_tmp
+ }
+ }
+
+ ## Cancel replace dialog -- auxiliary procedure for '__replace'
+ # @return bool
+ proc replace_CANCEL {} {
+ destroy .replace
+ grab release .replace
+ }
+
+ ## Invoke dialog "Replace confirmation"
+ # @return bool
+ proc replace_prompt {} {
+ variable replace_prompt_opened ;# Bool: Replace prompt dialog opened
+ variable replace_prompt_return_value ;# Replace prompt dialog return value
+ variable replace_prompt_geometry ;# Geometry of replace prompt dialog window
+
+ # Dialog already opened -> close it
+ if {$replace_prompt_opened} {
+ replace_prompt_DESTROY
+ # Open the dialog
+ } {
+ set replace_prompt_opened 1
+
+ # Create dialog window and restore previous geometry
+ toplevel .replace_prompt -class {Replace prompt dialog} -bg {#EEEEEE}
+ if {[info exists replace_prompt_geometry]} {
+ wm geometry .replace_prompt $replace_prompt_geometry
+ }
+
+ # Create window header
+ pack [frame .replace_prompt.topFrame] -fill x -expand 1
+ pack [label .replace_prompt.topFrame.image \
+ -image ::ICONS::32::help \
+ ] -side left -padx 10
+ pack [label .replace_prompt.topFrame.label \
+ -text [mc "Found an occurence of your search term.\nWhat do you want to do ?"] \
+ ] -fill both -expand 1 -side right
+
+ # Create separator
+ pack [ttk::separator .replace_prompt.separator -orient horizontal] -fill x -expand 1
+ pack [frame .replace_prompt.buttonFrame] -fill x -expand 1
+
+ # Create buttuns
+ foreach id { repl relp_close repl_all find_next close } \
+ text { "Replace" "Replace & close" "Replace all" "Find next" "Close" } \
+ val { 0 1 2 3 4 } \
+ under { 0 2 8 0 0 } {
+
+ pack [ttk::button .replace_prompt.buttonFrame.$id \
+ -text [mc $text] -underline $under \
+ -command "X::replace_prompt_return $val;set wait 1;unset wait" \
+ ] -fill x -expand 1 -side left -padx 5
+ }
+
+ # Set key-events bindings
+ bind .replace_prompt <Alt-Key-r> {
+ X::replace_prompt_return 0
+ set wait 1
+ unset wait
+ break
+ }
+ bind .replace_prompt <Alt-Key-p> {
+ X::replace_prompt_return 1
+ set wait 1
+ unset wait
+ break
+ }
+ bind .replace_prompt <Alt-Key-a> {
+ X::replace_prompt_return 2
+ set wait 1
+ unset wait
+ break
+ }
+ bind .replace_prompt <Alt-Key-f> {
+ X::replace_prompt_return 3
+ set wait 1
+ unset wait
+ break
+ }
+ bind .replace_prompt <Alt-Key-c> {
+ X::replace_prompt_return 4
+ set wait 1
+ unset wait
+ break
+ }
+
+ # Nessesary window manager options -- modal window
+ wm iconphoto .replace_prompt ::ICONS::16::help
+ wm title .replace_prompt [mc "Replace confirmation - %s" ${::APPNAME}]
+ wm minsize .replace_prompt 480 100
+ wm protocol .replace_prompt WM_DELETE_WINDOW {
+ X::replace_prompt_DESTROY
+ }
+ wm transient .replace_prompt .
+ raise .replace_prompt
+
+ vwait ::wait
+ return $replace_prompt_return_value
+ }
+ }
+
+ ## Cancel replace prompt dialog -- auxiliary procedure for 'replace_prompt'
+ # @return bool
+ proc replace_prompt_DESTROY {} {
+ variable replace_prompt_opened ;# Bool: Replace prompt dialog opened
+ variable replace_prompt_geometry ;# Geometry of replace prompt dialog window
+
+ # Save the current dialog geometry
+ set replace_prompt_geometry [wm geometry .replace_prompt]
+
+ # Destroy dislog window
+ destroy .replace_prompt
+ set replace_prompt_opened 0
+ }
+
+ ## Cancel replace prompt dialog and set its return value
+ # @parm Int val - result value of the dialog
+ # @return void
+ proc replace_prompt_return {val} {
+ variable replace_prompt_return_value ;# Replace prompt dialog return value
+
+ set replace_prompt_return_value $val
+ replace_prompt_DESTROY
+ }
+
+ ## Select all text in the editor
+ # @return void
+ proc __select_all {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Select all
+ $actualProject editor_procedure {} select_all {}
+ }
+
+ ## Invoke dialog "Go to"
+ # If simulator is engaged the run this: __simulator_set_PC_by_line
+ # @return void
+ proc __goto {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable goto ;# Line where to go
+ variable editor_lines ;# Number of lines in the current editor
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ __simulator_set_PC_by_line
+ return
+ }
+
+ set goto [$actualProject editor_actLineNumber]
+ set editor_lines [$actualProject editor_linescount]
+
+ # Create dialog window
+ set goto_opened 1
+ set win [toplevel .goto -class {Goto dialog} -bg {#EEEEEE}]
+
+ # Create window label frame
+ label $win.header -text [mc "Go to line"] -image ::ICONS::16::goto -compound left
+ set topFrame [ttk::labelframe $win.topFrame -labelwidget $win.header -relief flat]
+ pack $topFrame -expand 1 -fill x -padx 10
+
+ # Create scale widget
+ pack [ttk::scale $topFrame.scale \
+ -from 1 -to $editor_lines \
+ -orient horizontal \
+ -variable X::goto \
+ -command "
+ set ::X::goto \[expr {int(\${::X::goto})}\]
+ $topFrame.spinbox selection range 0 end
+ #" \
+ ] -side left -expand 1 -fill x -padx 2
+ DynamicHelp::add $topFrame.scale \
+ -text [mc "Graphical representation of line where to go"]
+
+ # Create spinbox widget
+ pack [spinbox $topFrame.spinbox \
+ -from 1 -to $editor_lines \
+ -textvariable X::goto \
+ -validate key \
+ -validatecommand {X::goto_validate %P} \
+ -width 6 \
+ -command "$topFrame.spinbox selection range 0 end" \
+ ] -side left
+ DynamicHelp::add $topFrame.spinbox -text [mc "Line where to go"]
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame .goto.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::goto_OK} \
+ ] -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::goto_CANCEL} \
+ ] -side left
+ pack $buttonFrame -pady 5
+
+ # Events binding (Enter == Ok, Esc == CANCEL)
+ bind $win <KeyRelease-Return> {X::goto_OK; break}
+ bind $win <KeyRelease-KP_Enter> {X::goto_OK; break}
+ bind $win <KeyRelease-Escape> {X::goto_CANCEL; break}
+
+ # Focus on the Spinbox
+ focus $topFrame.spinbox
+ $topFrame.spinbox selection range 0 end
+
+ # Nessesary window manager options -- modal window
+ wm iconphoto $win ::ICONS::16::goto
+ wm title $win [mc "Goto line - MCU 8051 IDE"]
+ wm minsize $win 200 100
+ wm protocol $win WM_DELETE_WINDOW {
+ X::goto_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Validate value of spinbox in the Go to dialog -- auxiliary procedure for '__goto'
+ # @parm
+ # @return bool
+ proc goto_validate {value} {
+ variable editor_lines ;# Number of lines in the current editor
+
+ if {$value > $editor_lines} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Cancel Go to dialog -- auxiliary procedure for '__goto'
+ # @return bool
+ proc goto_CANCEL {} {
+ destroy .goto
+ grab release .goto
+ }
+
+ ## Go to line -- auxiliary procedure for '__goto'
+ # @return bool
+ proc goto_OK {} {
+ variable actualProject ;# Object: Current project
+ variable goto ;# Line where to go
+
+ # Go to the specified line
+ $actualProject editor_procedure {} goto $goto
+ # Destroy dialog window
+ goto_CANCEL
+ }
+
+ ## Comment block of selected text in the editor
+ # @return void
+ proc __comment {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Comment
+ $actualProject editor_procedure {} comment {}
+ }
+
+ ## Uncomment block of selected text in the editor
+ # @return void
+ proc __uncomment {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Uncomment
+ $actualProject editor_procedure {} uncomment {}
+ }
+
+ ## Reload the current file
+ # @return void
+ proc __reload {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} return
+ if {$critical_procedure_in_progress} {return}
+
+ # Reload
+ $actualProject filelist_reload_file
+ }
+
+ ## Invoke directory selection dialog
+ # @parm Widget master - GUI parent
+ # @return void
+ proc select_directory {master} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+ variable select_directory_var {} ;# Selected directory
+ variable defaultDirectory ;# Default directory
+
+ # Determinate initial directory
+ if {$project_menu_locked} {
+ set directory {~}
+ } {
+ set directory [$actualProject cget -projectPath]
+ }
+
+ # Invoke the dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Choose directory - MCU 8051 IDE"] \
+ -directory $directory -fileson 0 -master $master
+
+ # Save choice to variable select_directory_var
+ fsd setokcmd {
+ set X::select_directory_var [X::fsd get]
+ }
+
+ fsd activate ;# Activate the dialog
+
+ # Return path to the selected directory
+ return $select_directory_var
+ }
+
+ ## Invoke dialog "New Project"
+ # @return void
+ proc __proj_new {} {
+ variable avaliable_processors ;# List of supported processors
+ variable actualProject ;# Object: Current project
+ variable project_new_name ;# Name of the new project
+ variable project_new_dir ;# Directory of the new project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_new_processor {AT89S52};# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena 0 ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena 0 ;# Bool: XCODE memory connected
+ variable project_new_xdata 0 ;# Int: Amount of XDATA memory
+ variable project_new_xcode 0 ;# Int: Amount of XCODE memory
+ variable project_new_max_xcode 0 ;# Int: Maximum valid value of external program memory
+ variable project_new_xd_chb ;# Widget: XDATA enable checkbutton
+ variable project_new_xd_scl ;# Widget: XDATA scale
+ variable project_new_xd_spb ;# Widget: XDATA spinbox
+ variable project_new_xc_chb ;# Widget: XCODE enable checkbutton
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ if {$critical_procedure_in_progress} {return}
+
+ # Create dialog window
+ set win [toplevel .project_new -class {New project} -bg {#EEEEEE}]
+
+ # Create window header (text and some icon)
+ set header [frame $win.header]
+
+ pack [label $header.image -image ::ICONS::32::wizard] -padx 10 -side left
+ pack [label $header.text \
+ -text [mc "Create a new project.\n All entries are required. Other options --> edit project."] \
+ ] -side left -expand 1 -fill x
+ pack $header -fill both -expand 1
+
+ # Create labelframe "General"
+ set genaral_labelframe [ttk::labelframe $win.general -text [mc "General"]]
+
+ # Entry "Project name"
+ set name [ttk::labelframe $genaral_labelframe.name \
+ -text [mc "Project name"] \
+ -relief flat \
+ ]
+ pack [ttk::entry $name.entry \
+ -textvariable X::project_new_name \
+ -width 20 \
+ ] -fill x -expand 1
+ DynamicHelp::add $name.entry -text [mc "Name of XML file representing the project"]
+ pack $name -fill x -expand 1 -padx 10 -pady 5
+
+ # Entry "Project directory"
+ set dir [ttk::labelframe $genaral_labelframe.dir \
+ -text [mc "Project directory"] \
+ -relief flat \
+ ]
+ pack [ttk::entry $dir.entry \
+ -textvariable X::project_new_dir \
+ -width 20 \
+ ] -side left -fill x -expand 1
+ DynamicHelp::add $dir.entry -text [mc "Directory where the project file should be located"]
+
+ pack [ttk::button $dir.choose \
+ -image ::ICONS::16::fileopen \
+ -style Flat.TButton \
+ -command {
+ set foo [X::select_directory .project_new]
+ if {$foo != {}} {
+ set X::project_new_dir $foo
+ }
+ unset foo
+ } \
+ ] -side left
+ DynamicHelp::add $dir.choose -text [mc "Choose destination location"]
+
+ pack $dir -fill x -expand 1 -padx 10 -pady 5
+ pack $genaral_labelframe -fill both -expand 1 -pady 10 -padx 10
+
+ # Create labelframe "Processor"
+ set proc_frame [ttk::labelframe $win.proc_frame -text [mc "Processor"]]
+ set proc_frame_top [frame $proc_frame.top]
+ set proc_frame_middle [frame $proc_frame.middle]
+ set proc_frame_middle_left [ttk::labelframe $proc_frame_middle.middle \
+ -padding 5 -text [mc "XDATA"]]
+ set proc_frame_middle_right [ttk::labelframe $proc_frame_middle.right \
+ -padding 5 -text [mc "XCODE"]]
+
+ # Create components of top frame (Type: <ComboBox> <Button>)
+ pack [label $proc_frame_top.lbl -text [mc "Type:"]] -side left
+ pack [ttk::combobox $proc_frame_top.combo \
+ -values $avaliable_processors \
+ -state readonly \
+ -textvariable ::X::project_new_processor \
+ ] -side left -fill x -fill x
+ bind $proc_frame_top.combo <<ComboboxSelected>> {::X::proj_new_mcu_changed}
+ DynamicHelp::add $proc_frame_top.combo -text [mc "Selected uC"]
+
+ pack [ttk::button $proc_frame_top.but \
+ -text [mc "Select MCU"] \
+ -image ::ICONS::16::back \
+ -compound left \
+ -command {::X::proj_new_select_mcu .project_new} \
+ ] -side right -after $proc_frame_top.combo -padx 10
+ DynamicHelp::add $proc_frame_top.but -text [mc "Choose processor from database"]
+
+ # Create components of XDATA labelframe
+ set project_new_xd_chb [checkbutton $proc_frame_middle_left.checkbutton \
+ -variable ::X::project_new_xdata_ena \
+ -text [mc "Enable"] \
+ -command ::X::proj_new_xdata_disena \
+ ]
+ pack $project_new_xd_chb -anchor w
+ DynamicHelp::add $proc_frame_middle_left.checkbutton \
+ -text [mc "Connect external data memory"]
+ set proc_frame_left_btm [frame $proc_frame_middle_left.btm]
+ set project_new_xd_scl [ttk::scale $proc_frame_left_btm.scale \
+ -orient horizontal \
+ -variable ::X::project_new_xdata \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::X::project_new_xdata \[expr {int(\${::X::project_new_xdata})}\]
+ $proc_frame_left_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $project_new_xd_scl \
+ -text [mc "Amount of external data memory"]
+ pack $project_new_xd_scl -fill x -side left -expand 1 -padx 2
+ set project_new_xd_spb [spinbox $proc_frame_left_btm.spinbox \
+ -textvariable ::X::project_new_xdata \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::SelectMCU::validate_xdata %P} \
+ -command "$proc_frame_left_btm.spinbox selection range 0 end ;#" \
+ ]
+ DynamicHelp::add $project_new_xd_spb \
+ -text [mc "Amount of external data memory"]
+ pack $project_new_xd_spb -side right -after $project_new_xd_scl
+ pack $proc_frame_left_btm -fill both -expand 1
+
+ # Create components of XCODE labelframe
+ set project_new_xc_chb [checkbutton $proc_frame_middle_right.checkbutton \
+ -variable ::X::project_new_xcode_ena \
+ -text [mc "Enable"] \
+ -command ::X::proj_new_xcode_disena \
+ ]
+ pack $project_new_xc_chb -anchor w
+ DynamicHelp::add $proc_frame_middle_right.checkbutton \
+ -text [mc "Connect external program memory"]
+ set proc_frame_right_btm [frame $proc_frame_middle_right.btm]
+ set project_new_xc_scl [ttk::scale $proc_frame_right_btm.scale \
+ -orient horizontal \
+ -variable ::X::project_new_xcode \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::X::project_new_xcode \[expr {int(\${::X::project_new_xcode})}\]
+ $proc_frame_right_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $project_new_xc_scl \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $project_new_xc_scl -fill x -side left -expand 1 -padx 2
+ set project_new_xc_spb [spinbox $proc_frame_right_btm.spinbox \
+ -textvariable ::X::project_new_xcode \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::X::proj_new_validate_xcode %P} \
+ -command "$proc_frame_right_btm.spinbox selection range 0 end ;#" \
+ ]
+ DynamicHelp::add $project_new_xc_spb \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $project_new_xc_spb -side right -after $project_new_xc_scl
+ pack $proc_frame_right_btm -fill both -expand 1
+
+ pack $proc_frame_top -anchor w -pady 10 -padx 10 -fill x
+ pack $proc_frame_middle_left -side left -fill x -expand 1 -padx 7
+ pack $proc_frame_middle_right -side left -fill x -expand 1 -padx 7
+ pack $proc_frame_middle -fill both -expand 1 -pady 5
+ pack $proc_frame -fill both -expand 1 -padx 10 -pady 10
+
+ # Create 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $win.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::project_new_OK} \
+ ] -side left -padx 5
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::project_new_CANCEL} \
+ ] -side left -padx 5
+ pack $buttonFrame -pady 5
+
+ # Adjust XDATA & XCODE controls
+ proj_new_mcu_changed
+
+ # Events binding (Enter == Ok; Escape == Cancel)
+ bind $win <Key-Return> {X::project_new_OK; break}
+ bind $win <Key-KP_Enter> {X::project_new_OK; break}
+ bind $win <Key-Escape> {X::project_new_CANCEL; break}
+
+ # Nessesary window manager options -- modal window
+ wm iconphoto $win ::ICONS::16::filenew
+ wm title $win [mc "New project - MCU 8051 IDE"]
+ wm minsize $win 400 400
+ wm protocol $win WM_DELETE_WINDOW {
+ X::project_new_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Binding for processor type combobox -modifycmd
+ # Usage: ComboBox -modifycmd ::X::proj_new_mcu_changed
+ # This function gets informations about selected processor
+ # and adjusts XCODE & XDATA memory constrols.
+ # @return void
+ proc proj_new_mcu_changed {} {
+ variable project_new_processor ;# Processor type (e.g. "8051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_max_xcode ;# Int: Maximum valid value of external program memory
+ variable project_new_xd_chb ;# Widget: XDATA enable checkbutton
+ variable project_new_xc_chb ;# Widget: XCODE enable checkbutton
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ # Get processor details
+ set details [::SelectMCU::get_processor_details $project_new_processor]
+ if {$details == {}} {
+ puts stderr "Unknown error occured in ::X::proj_new_mcu_changed !\nPlease check your installation."
+ return
+ }
+
+ # Enable/Disable XDATA memory enable checkbutton
+ if {[lindex $details 0] != {yes}} {
+ set project_new_xdata_ena 0
+ $project_new_xd_chb configure -state disabled
+ } {
+ $project_new_xd_chb configure -state normal
+ }
+
+ # Enable/Disable XCODE memory enable checkbutton
+ if {[lindex $details 1] != {yes}} {
+ set project_new_xcode_ena 0
+ $project_new_xc_chb configure -state disabled
+ } {
+ $project_new_xc_chb configure -state normal
+ }
+
+ # Adjust XCODE memory scale & spinbox maximum value
+ set project_new_max_xcode [expr {0xFFFF - ([lindex $details 2] * 1024)}]
+ $project_new_xc_scl configure -to $project_new_max_xcode
+ $project_new_xc_spb configure -to $project_new_max_xcode
+
+ # Enable/Disable XDATA & XCODE scale + XDATA & XCODE spinbox
+ proj_new_xdata_disena
+ proj_new_xcode_disena
+ }
+
+ ## Enable/Disable XDATA scale & spinbox acording to $project_new_xdata_ena
+ # @return void
+ proc proj_new_xdata_disena {} {
+ variable project_new_xd_scl ;# Widget: XDATA scale
+ variable project_new_xd_spb ;# Widget: XDATA spinbox
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+
+ # Enable
+ if {$project_new_xdata_ena} {
+ $project_new_xd_scl state !disabled
+ $project_new_xd_spb configure -state normal
+ # Disable
+ } {
+ $project_new_xd_scl state disabled
+ $project_new_xd_spb configure -state disabled
+ }
+ }
+
+ ## Enable/Disable XCODE scale & spinbox acording to $project_new_xcode_ena
+ # @return void
+ proc proj_new_xcode_disena {} {
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+
+ # Enable
+ if {$project_new_xcode_ena} {
+ $project_new_xc_scl state !disabled
+# $project_new_xc_scl configure -troughcolor {#FFFFFF}
+ $project_new_xc_spb configure -state normal
+ # Disable
+ } {
+ $project_new_xc_scl state disabled
+# $project_new_xc_scl configure -troughcolor {#AAAAAA}
+ $project_new_xc_spb configure -state disabled
+ }
+ }
+
+ ## Validate content of XCODE spinbox
+ # @parm String string - string to validate
+ # @return Bool - true if validation successful
+ proc proj_new_validate_xcode {string} {
+ variable project_new_max_xcode ;# Int: Maximum valid value of external program memory
+ if {![string is digit $string]} {
+ return 0
+ }
+ if {$string == {}} {
+ return 1
+ }
+ if {$string < 0 || $string > $project_new_max_xcode} {
+ return 0
+ }
+ return 1
+ }
+
+ ## Invoke MCU selection dialog
+ # @parm Widget win - parent window
+ # @return void
+ proc proj_new_select_mcu {win} {
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+
+ # Determinate initial XDATA memory for the dialog
+ if {$project_new_xdata_ena} {
+ set xdata $project_new_xdata
+ } {
+ set xdata 0
+ }
+ # Determinate initial XCODE memory for the dialog
+ if {$project_new_xcode_ena} {
+ set xcode $project_new_xcode
+ } {
+ set xcode 0
+ }
+
+ # Invoke dialog
+ set result [SelectMCU::activate $win [list $project_new_processor $xdata $xcode]]
+ if {$result == {}} {
+ return
+ }
+
+ # Process results
+ set project_new_processor [lindex $result 0]
+ set project_new_xdata [lindex $result 1]
+ set project_new_xcoda [lindex $result 2]
+ proj_new_mcu_changed
+
+ # Adjust XCODE & XDATA checkbuttons
+ if {$project_new_xdata} {
+ set project_new_xdata_ena 1
+ } {
+ set project_new_xdata_ena 0
+ }
+ if {$project_new_xcode} {
+ set project_new_xcode_ena 1
+ } {
+ set project_new_xcode_ena 0
+ }
+ }
+
+ ## Cancel dialog "Create new project" -- auxiliary procedure for '__proj_new'
+ # @return void
+ proc project_new_CANCEL {} {
+ grab release .project_new
+ destroy .project_new
+ }
+
+ ## Create new project -- auxiliary procedure for '__proj_new'
+ # @return void
+ proc project_new_OK {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+ variable project_new_name ;# Name of the new project
+ variable project_new_dir ;# Directory of the new project
+ variable project_edit_defaults ;# Some default project values
+ variable project_edit_clock ;# Default clock rate
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable openedProjects ;# List of opened projects (Object references)
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # This is critical procedure
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check for presence of all nessesary informations
+ if {$project_new_dir == {} || $project_new_name == {}} {
+ tk_messageBox \
+ -icon warning \
+ -type ok \
+ -title [mc "Ivalid request"] \
+ -message [mc "Both entries in section general must be filled."] \
+ -parent .project_new
+ set critical_procedure_in_progress 0
+ return 0
+ }
+
+ # Adjust project directory
+ regsub {[\\\/]$} $project_new_dir {} project_new_dir
+
+ # Check for validity of the specified directory
+ if {![file exists $project_new_dir] || ![file isdirectory $project_new_dir]} {
+ # Ask for creating a new directory
+ set result [tk_messageBox \
+ -icon question \
+ -type yesno \
+ -parent .project_new \
+ -title [mc "Create directory - MCU 8051 IDE"] \
+ -message [mc "The specified directory does not exist do you want to create it ?"] \
+ ]
+ if {$result == {yes}} {
+ # (Yes) -> Create new directory
+ if {[catch {file mkdir $project_new_dir}]} {
+ tk_messageBox \
+ -icon error \
+ -parent .project_new \
+ -type ok \
+ -title [mc "File access error"] \
+ -message [mc "Creation of directory '%s' FAILED !\nPlease check your permissions." $project_new_dir]
+ set critical_procedure_in_progress 0
+ return 0
+ }
+ # (No) -> Cancel
+ } else {
+ set critical_procedure_in_progress 0
+ return 0
+ }
+ } {
+ # Check if this the project does not already exist
+ if {[file exists "$project_new_dir/$project_new_name.mcu8051ide"]} {
+ # Ask for owerwrite
+ if {
+ ![tk_messageBox \
+ -icon question \
+ -type yesno \
+ -default no \
+ -parent .project_new \
+ -title [mc "File already exists - MCU 8051 IDE"] \
+ -message [mc "Some project with the same name already exists in the specified directory. \nDo you want to overwrite it ?"] \
+ ]
+ } {
+ # (No) -> Cancel
+ set critical_procedure_in_progress 0
+ return 0
+ }
+ }
+ }
+
+ # Close the dialog window
+ project_new_CANCEL
+
+ # Set project values to defaults
+ foreach default $project_edit_defaults {
+ switch -- [lindex $default 0] {
+ {project_edit_calc_rad} {
+ set calc_radix [lindex $default 1]
+ }
+ {project_edit_calc_ang} {
+ set calc_angle [lindex $default 1]
+ }
+ default {
+ set [lindex $default 0] [lindex $default 1]
+ }
+ }
+ }
+ set project_new_xdata [expr {int($project_new_xdata)}]
+ set project_new_xcode [expr {int($project_new_xcode)}]
+ set project_data [list \
+ [list {} [clock format [clock seconds] -format {%D}] {}]\
+ [list [file tail [file normalize ~]] {} {}] \
+ [list \
+ $project_new_processor \
+ $project_edit_clock \
+ $project_new_xdata \
+ $project_new_xcode] \
+ [list {} {} {} 1] \
+ [list {y} 0 0 \
+ [string repeat 0 170] \
+ [string repeat 0 170] \
+ [string repeat 0 170] \
+ {state} \
+ ] \
+ [list {} {}] \
+ [list $calc_radix $calc_angle {} {} {} {} {} {}] \
+ {} {} \
+ [list 0 [list {} {} 0 {}]] \
+ ]
+
+ # Create a new project file
+ if {[catch {
+ set prj_file [open "$project_new_dir/$project_new_name.mcu8051ide" w 420]
+ }]} then {
+ # Failed
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon error \
+ -message [mc "Unable to write to file:\n\"%s\"" $project_new_dir/$project_new_name.mcu8051ide]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Fill in the file with project definition data
+ puts -nonewline $prj_file [Project::create_project_file_as_string $project_data]
+ close $prj_file
+ set done 0
+
+ # Insure than the project descriptor is unique
+ set projectDescriptor [regsub -all -- {\s} $project_new_name {-}]
+ regsub -all {[\\\/\.\,`\!@#\$%\^&:\;\|\*\"\(\)\[\]\{\}]} $projectDescriptor \
+ {_} projectDescriptor
+
+ if {[lsearch -exact -ascii ${X::openedProjects} $projectDescriptor] != -1} {
+ append project_new_name {(0)}
+ append projectDescriptor {_0}
+
+ while 1 {
+ if {[lsearch -exact -ascii ${X::openedProjects} $projectDescriptor] == -1} {break}
+
+ regexp {\d+$} $projectDescriptor index
+ regsub {_\d+$} $projectDescriptor {} projectDescriptor
+
+ regexp {\d+\)$} $project_new_name index
+ set index [string trimright $index {\)}]
+ regsub {\(\d+\)$} $project_new_name {} project_new_name
+
+ incr index
+ append project_new_name "($index)"
+ append projectDescriptor "_$index"
+ }
+ }
+
+ # Show project notebook
+ if {$project_menu_locked} {
+ pack .mainFrame.mainNB -expand 1 -fill both
+ }
+
+ # Open created project
+ lappend openedProjects $projectDescriptor
+ lappend simulator_enabled 0
+ MainTab ::$projectDescriptor $project_new_name $project_new_dir $project_new_name.mcu8051ide $project_data
+ switch_project $projectDescriptor
+
+ ::X::recent_files_add 0 [file join [file normalize $project_new_dir] $project_new_name.mcu8051ide]
+
+ # Project opened
+ if {$project_menu_locked} {
+ Unlock_project_menu
+ }
+ disaena_menu_toolbar_for_current_project
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Disable menu items and functions functions which are
+ # avaliable only if there is at least one opened project
+ # @return void
+ proc Lock_project_menu {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable toolbar_project_dependent_buttons ;# Toolbar buttons which require opened project
+ variable mainmenu_project_dependent_buttons ;# Menu bar items which require opened project
+
+ # Hide project notebook
+ pack forget .mainFrame.mainNB
+
+ # Disable menu items
+ set project_menu_locked 1
+ ena_dis_menu_buttons 0 $mainmenu_project_dependent_buttons
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_project_dependent_buttons
+ adjust_mm_and_tb_ext_editor
+ }
+
+ ## Enable menu items and functions functions which are avaliable only if there
+ # is at least one opened project and create NoteBook for project tabs
+ # @return void
+ proc Unlock_project_menu {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable toolbar_project_dependent_buttons ;# Toolbar buttons which require opened project
+ variable mainmenu_project_dependent_buttons ;# Menu bar items which require opened project
+ variable toolbar_simulator_engaged ;# Toolbar buttons which require ENGAGED simulator
+ variable mainmenu_simulator_engaged ;# Menu bar items which require ENGAGED simulator
+
+ # Enable menu items
+ set project_menu_locked 0
+ ena_dis_menu_buttons 1 $mainmenu_project_dependent_buttons
+ ena_dis_menu_buttons 0 $mainmenu_simulator_engaged
+ ena_dis_iconBar_buttons 1 .mainIconBar. $toolbar_project_dependent_buttons
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_simulator_engaged
+ adjust_mm_and_tb_ext_editor
+ }
+
+ ## Disable menu entries and toolbar buttons which are functional on when simulator is on
+ # @return void
+ proc Lock_simulator_menu {} {
+ variable toolbar_simulator_disengaged ;# Toolbar buttons which require DISENGAGED simulator
+ variable toolbar_simulator_engaged ;# Toolbar buttons which require ENGAGED simulator
+ variable mainmenu_simulator_engaged ;# Menu bar items which require ENGAGED simulator
+ variable mainmenu_simulator_disengaged ;# Menu bar items which require DISENGAGED simulator
+
+ ena_dis_menu_buttons 1 $mainmenu_simulator_disengaged
+ ena_dis_menu_buttons 0 $mainmenu_simulator_engaged
+ ena_dis_iconBar_buttons 1 .mainIconBar. $toolbar_simulator_disengaged
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_simulator_engaged
+ adjust_mm_and_tb_ext_editor
+ }
+
+ ## Enable menu entries and toolbar buttons which are functional on when simulator is on
+ # @return void
+ proc Unlock_simulator_menu {} {
+ variable toolbar_simulator_disengaged ;# Toolbar buttons which require DISENGAGED simulator
+ variable toolbar_simulator_engaged ;# Toolbar buttons which require ENGAGED simulator
+ variable mainmenu_simulator_engaged ;# Menu bar items which require ENGAGED simulator
+ variable mainmenu_simulator_disengaged ;# Menu bar items which require DISENGAGED simulator
+
+ ena_dis_menu_buttons 0 $mainmenu_simulator_disengaged
+ ena_dis_menu_buttons 1 $mainmenu_simulator_engaged
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_simulator_disengaged
+ ena_dis_iconBar_buttons 1 .mainIconBar. $toolbar_simulator_engaged
+ adjust_mm_and_tb_ext_editor
+ }
+
+ ## Open project
+ # @return void
+ proc __proj_open {} {
+ variable defaultDirectory ;# Default directory
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Invoke project selection dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Open project - MCU 8051 IDE"] \
+ -directory $defaultDirectory \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{MCU 8051 IDE project} {*.mcu8051ide} }
+ {{All files} {*} }
+ }
+
+ # Open the selected after press of OK button
+ fsd setokcmd {
+ set filename [X::fsd get]
+ X::fsd deactivate
+ if {![Project::open_project_file $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent . \
+ -title [mc "Error - MCU 8051 IDE"] \
+ -message [mc "Unable to load file: %s" $filename]
+ } {
+ ${::X::actualProject} editor_procedure {} highlight_visible_area {}
+ ::X::recent_files_add 0 $filename
+ }
+ }
+
+ fsd activate ;# Activate the dialog
+
+ adjust_title
+ disaena_menu_toolbar_for_current_project
+ set critical_procedure_in_progress 0
+ }
+
+ ## Retrieve project related data from object of the current project
+ # @parm Bool all_info - All data (include todo list and such)
+ # @return void
+ proc Project_retrieve_data_from_application {all_info} {
+ variable actualProject ;# Object: Current project
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_authors ;# Project authors
+ variable project_edit_description ;# Project description
+ variable project_edit_main_file ;# Project main file
+ variable project_watches_file ;# File of register watches definition
+ variable project_todo ;# Todo text
+ variable project_graph ;# Graph configuration list
+ variable project_calculator ;# Calculator list (display contents, etc.)
+ variable project_other_options ;# Other project options
+ variable project_compiler_options ;# Compiler options
+ variable project_files ;# List of project files (special format)
+ variable project_file ;# Full name of the project file
+ variable project_dir ;# Path to project directory
+ variable project_edit_clock ;# Default clock rate
+ variable project_scenario_file ;# Scenario file
+
+ set project_edit_version [ $actualProject cget -P_information_version ]
+ set project_edit_date [ $actualProject cget -P_information_date ]
+ set project_edit_authors [ $actualProject cget -G_information_authors ]
+ set project_edit_copyright [ $actualProject cget -G_information_copyright ]
+ set project_edit_licence [ $actualProject cget -G_information_licence ]
+ set project_edit_clock [ $actualProject cget -P_option_clock ]
+ set project_edit_description [ $actualProject cget -project_description ]
+ set project_new_processor [ $actualProject cget -P_option_mcu_type ]
+ set project_new_xdata [ $actualProject cget -P_option_mcu_xdata ]
+ set project_new_xcode [ $actualProject cget -P_option_mcu_xcode ]
+ set project_edit_main_file [ $actualProject cget -P_option_main_file ]
+ set project_new_xdata_ena 0
+ set project_new_xcode_ena 0
+ if {$project_new_xdata} {set project_new_xdata_ena 1}
+ if {$project_new_xcode} {set project_new_xcode_ena 1}
+ if {$all_info} {
+ set project_graph [ $actualProject graph_get_config ]
+ set project_todo [ $actualProject TodoProc_read_text_as_sgml ]
+ set project_calculator [ $actualProject get_calculator_list ]
+ set project_other_options [ $actualProject cget -other_options ]
+ set project_files [ $actualProject get_project_files_list ]
+ set project_file [ $actualProject cget -projectFile ]
+ set project_dir [ $actualProject cget -projectPath ]
+ set project_watches_file [ $actualProject getWatchesFileName ]
+ set project_scenario_file [ $actualProject pale_get_scenario_filename ]
+ set project_compiler_options [ $actualProject get_compiler_config ]
+ }
+ }
+
+ ## Free some resources reserved by procedure 'Project_retrieve_data_from_application'
+ # @return void
+ proc Project_RDFA_cleanup {} {
+ variable project_watches_file {} ;# File of register watches of the current poject
+ variable project_scenario_file {} ;# Scenario file
+ variable project_todo {} ;# Todo text
+ variable project_graph {} ;# Graph configuration list
+ variable project_calculator {} ;# Calculator list (display contents, etc.)
+ variable project_other_options {} ;# Other project options
+ variable project_compiler_options {} ;# Compiler options
+ variable project_files {} ;# List of project files (special format)
+ variable project_file {} ;# Full name of the project file
+ variable project_dir {} ;# Path to project directory
+ variable project_edit_clock {} ;# Default clock rate
+ }
+
+ ## Save the current project
+ # @return void
+ proc __proj_save {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_authors ;# Project authors
+ variable project_edit_description ;# Project description
+ variable project_edit_clock ;# Default clock rate
+ variable project_edit_main_file ;# Project main file
+ variable project_todo ;# Todo text
+ variable project_graph ;# Graph configuration list
+ variable project_calculator ;# Calculator list (display contents, etc.)
+ variable project_other_options ;# Other project options
+ variable project_compiler_options ;# Compiler options
+ variable project_files ;# List of project files (special format)
+ variable project_file ;# Full name of the project file
+ variable project_dir ;# Path to project directory
+ variable project_watches_file ;# File of register watches of the current poject
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable project_scenario_file ;# Scenario file
+
+ if {$project_menu_locked} {return}
+
+ # This is critical procedure
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Save register watches definition file
+ if {[$actualProject rightPanel_watch_modified]} {
+ $actualProject rightPanel_watch_save {} 1
+ }
+
+ # Save PALE Virtual HW connections
+ if {[$actualProject pale_modified]} {
+ $actualProject pale_save_scenario_file
+ }
+
+ # Create project definition data
+ Project_retrieve_data_from_application 1
+ set project_data [list \
+ [list \
+ [Project::escape_curlies $project_edit_version] \
+ [Project::escape_curlies $project_edit_date] \
+ ${::VERSION}] \
+ [list \
+ $project_edit_authors \
+ [Project::escape_curlies $project_edit_copyright] \
+ [Project::escape_curlies $project_edit_licence]] \
+ [list \
+ $project_new_processor \
+ $project_edit_clock \
+ $project_new_xdata \
+ $project_new_xcode] \
+ [list \
+ $project_watches_file \
+ $project_scenario_file \
+ $project_edit_main_file \
+ [$actualProject get_file_switching_enabled]] \
+ $project_graph \
+ [list \
+ [Project::escape_curlies $project_edit_description] \
+ [Project::escape_curlies $project_todo]] \
+ $project_calculator \
+ [Project::escape_curlies $project_other_options] \
+ [list $project_compiler_options] \
+ $project_files \
+ ]
+
+ set project_data [Project::create_project_file_as_string $project_data]
+ set filename "$project_dir/$project_file"
+ Project_RDFA_cleanup
+
+ # Create backup copy for the project file
+ if {[file exists $filename]} {
+ catch {
+ file rename -force $filename "$filename~"
+ }
+ }
+
+ # Save project definition file
+ if {[catch {
+ set prj_file [open $filename w 420]
+ }]} then {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to write to file:\n\"%s\"" $filename]
+ set critical_procedure_in_progress 0
+ return
+ }
+ puts -nonewline $prj_file $project_data
+ close $prj_file
+
+ # Done ...
+ Sbar [mc "Project saved to %s" $filename]
+ set critical_procedure_in_progress 0
+ }
+
+ ## Invoke dialog "Edit project"
+ # @return void
+ proc __proj_edit {} {
+ variable actualProject ;# Object: Current project
+ variable avaliable_processors ;# List of supported processors
+
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_authors ;# Project authors
+ variable project_edit_description ;# Project description
+ variable project_edit_clock ;# Default clock rate
+ variable project_edit_main_file ;# Project main file
+
+ variable project_edit_main_file_clr_but ;# Widget: Project main file clear button
+
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ variable project_new_processor {8051} ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena 0 ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena 0 ;# Bool: XCODE memory connected
+ variable project_new_xdata 0 ;# Int: Amount of XDATA memory
+ variable project_new_xcode 0 ;# Int: Amount of XCODE memory
+ variable project_new_max_xcode 0 ;# Int: Maximum valid value of external program memory
+ variable project_new_xd_chb ;# Widget: XDATA enable checkbutton
+ variable project_new_xd_scl ;# Widget: XDATA scale
+ variable project_new_xd_spb ;# Widget: XDATA spinbox
+ variable project_new_xc_chb ;# Widget: XCODE enable checkbutton
+ variable project_new_xc_scl ;# Widget: XCODE scale
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Retrieve existing informations about the project
+ Project_retrieve_data_from_application 0
+
+ # Create dialog window
+ set win [toplevel .project_edit -class {Edit project} -bg {#EEEEEE}]
+
+ # Create main frames (top.left; top.right; bottom)
+ set top_frame [frame $win.top]
+ set bottom_frame [frame $win.bottom]
+ set top_left_frame [frame $top_frame.left]
+ set top_right_frame [frame $top_frame.right]
+
+ ## GENERAL INFORMATION (version, date, authors, copyright, licence)
+ label $win.lb_general_info_label \
+ -compound left \
+ -text [mc "General information"] \
+ -image ::ICONS::16::contents
+ set lb_general_info [ttk::labelframe $top_left_frame.lb_general_info \
+ -labelwidget $win.lb_general_info_label -padding 7 \
+ ]
+ pack $lb_general_info -fill both -expand 1
+
+ set bframe [frame $lb_general_info.bframe]
+ pack $bframe -fill x -expand 1 -anchor w
+
+ # version
+ grid [Label $bframe.version_label \
+ -text [mc "Version"] \
+ -helptext [mc "Project version (any string)"] \
+ ] -row 1 -column 1 -sticky w
+ grid [ttk::entry $bframe.version_entry \
+ -textvariable X::project_edit_version \
+ -validate key \
+ -validatecommand {::X::project_edit_validate %P} \
+ ] -row 1 -column 2 -sticky we -columnspan 2
+ DynamicHelp::add $bframe.version_entry -text [mc "Project version (any string)"]
+
+ # date
+ grid [Label $bframe.date_label \
+ -text [mc "Date"] \
+ -helptext [mc "Project last update"] \
+ ] -row 2 -column 1 -sticky w
+ grid [ttk::entry $bframe.date_entry \
+ -textvariable X::project_edit_date \
+ -validate key \
+ -validatecommand {::X::project_edit_validate %P} \
+ ] -row 2 -column 2 -sticky we
+ DynamicHelp::add $bframe.date_entry -text [mc "Project last update"]
+
+ # button 'today'
+ grid [ttk::button $bframe.now \
+ -style Flat.TButton \
+ -takefocus 0 \
+ -image ::ICONS::16::today \
+ -command {X::project_edit_today} \
+ ] -row 2 -column 3 -sticky e
+ DynamicHelp::add $bframe.now -text [mc "Fill date entry with the current date"]
+
+ # copyright
+ grid [Label $bframe.copyright_label \
+ -text [mc "Copyright"] \
+ -helptext [mc "Copyright information"] \
+ ] -row 3 -column 1 -sticky w
+ grid [ttk::entry $bframe.copyright_entry \
+ -textvariable X::project_edit_copyright \
+ -validate key \
+ -validatecommand {::X::project_edit_validate %P} \
+ ] -row 3 -column 2 -sticky we -columnspan 2
+ DynamicHelp::add $bframe.copyright_entry -text [mc "Copyright information"]
+
+ # licence
+ grid [Label $bframe.licence_label \
+ -text [mc "Licence"] \
+ -helptext [mc "Name of the licence"] \
+ ] -row 4 -column 1 -sticky w
+ grid [ttk::entry $bframe.licence_entry \
+ -textvariable X::project_edit_licence \
+ -validate key \
+ -validatecommand {::X::project_edit_validate %P} \
+ ] -row 4 -column 2 -sticky we -columnspan 2
+ DynamicHelp::add $bframe.licence_entry -text [mc "Name of the licence"]
+
+ # authors
+ set tframe [frame .project_edit.top.left.lb_general_info.tframe]
+ pack $tframe -fill both -expand 1 -padx 5
+ pack [Label $tframe.label \
+ -text [mc "Authors:"] \
+ -helptext {List of project authors (one per line)} \
+ ] -anchor w
+ pack [frame $tframe.frame] -fill both -expand 1
+
+ pack [text $tframe.frame.text \
+ -width 0 -height 0 \
+ -yscrollcommand "$tframe.frame.scrollbar set" \
+ ] -fill both -expand 1 -side left
+ $tframe.frame.text insert end $project_edit_authors
+ pack [ttk::scrollbar $tframe.frame.scrollbar \
+ -orient vertical \
+ -command "$tframe.frame.text yview" \
+ ] -fill y -side right
+
+ ## Simulator & Compiler (MCU type, XDATA + XCODE memory + CLOCK)
+ label $win.lb_compiler_label \
+ -compound left \
+ -text [mc "Processor"] \
+ -image ::ICONS::16::kcmmemory
+ set lb_compiler [ttk::labelframe $top_right_frame.lb_compiler \
+ -labelwidget $win.lb_compiler_label \
+ ]
+ set proc_frame_top0 [frame $lb_compiler.top0]
+ set proc_frame_top1 [frame $lb_compiler.top1]
+ set proc_frame_middle [frame $lb_compiler.middle]
+ set proc_frame_middle_left [ttk::labelframe $proc_frame_middle.middle \
+ -padding 5 -text [mc "XDATA"]]
+ set proc_frame_middle_right [ttk::labelframe $proc_frame_middle.right \
+ -padding 5 -text [mc "XCODE"]]
+
+ # MCU clock frequency
+ grid [Label $proc_frame_top1.clock_label \
+ -text [mc "Clock \[kHz\]:"] -width 11 -anchor w \
+ -helptext [mc "Default clock used by simulator engine"] \
+ ] -row 0 -column 1 -sticky w
+ grid [ttk::entry $proc_frame_top1.clock_entry \
+ -width 10 \
+ -textvariable X::project_edit_clock \
+ -validate key \
+ -validatecommand {::X::project_edit_CLOCK_validate %P} \
+ ] -row 0 -column 3 -sticky w
+ DynamicHelp::add $proc_frame_top1.clock_entry \
+ -text [mc "Default clock used by simulator engine"]
+
+ # Main file
+ grid [Label $proc_frame_top1.file_label \
+ -text [mc "Main file:"] -width 11 -anchor w \
+ -helptext [mc "Project main file (e.g. main.c)\n(empty string means always compile current file)"] \
+ ] -row 1 -column 1 -sticky w
+ set project_edit_main_file_clr_but [ttk::button \
+ $proc_frame_top1.clear_but \
+ -style Flat.TButton \
+ -takefocus 0 \
+ -image ::ICONS::16::locationbar_erase \
+ -command {set ::X::project_edit_main_file {}} \
+ -state disabled \
+ ]
+ DynamicHelp::add $proc_frame_top1.clear_but -text [mc "Clear"]
+ grid $project_edit_main_file_clr_but -row 1 -column 2 -sticky w
+ grid [ttk::entry $proc_frame_top1.file_entry \
+ -width 25 \
+ -validate all \
+ -validatecommand {::X::proj_edit_mf_validator %P} \
+ -textvariable X::project_edit_main_file \
+ ] -row 1 -column 3 -sticky we
+ DynamicHelp::add $proc_frame_top1.file_entry \
+ -text [mc "Project main file (e.g. main.c)\n(empty string means always compile current file)"]
+ grid [ttk::button $proc_frame_top1.file_select_but \
+ -style Flat.TButton \
+ -takefocus 0 \
+ -image ::ICONS::16::fileopen \
+ -command {X::project_edit_select_main_file} \
+ ] -row 1 -column 4 -sticky e -pady 5
+ DynamicHelp::add $proc_frame_top1.file_select_but -text [mc "Select main file"]
+
+ # Create components of top frame (Type: <ComboBox> <Button>)
+ pack [label $proc_frame_top0.lbl -text [mc "Type:"] -width 14 -anchor w] -side left
+ pack [ttk::combobox $proc_frame_top0.combo \
+ -values $avaliable_processors \
+ -state readonly \
+ -textvariable ::X::project_new_processor\
+ ] -side left -fill x
+ bind $proc_frame_top0.combo <<ComboboxSelected>> {::X::proj_new_mcu_changed}
+ DynamicHelp::add $proc_frame_top0.combo -text [mc "Selected uC"]
+
+ pack [ttk::button $proc_frame_top0.but \
+ -text [mc "Select MCU"] \
+ -image ::ICONS::16::back \
+ -compound left \
+ -command {::X::proj_new_select_mcu .project_edit} \
+ ] -side right -after $proc_frame_top0.combo -padx 5
+ DynamicHelp::add $proc_frame_top0.combo -text [mc "Choose processor from database"]
+
+ # Create components of XDATA labelframe
+ set project_new_xd_chb [checkbutton $proc_frame_middle_left.checkbutton \
+ -variable ::X::project_new_xdata_ena \
+ -text [mc "Enable"] \
+ -command ::X::proj_new_xdata_disena \
+ ]
+ pack $project_new_xd_chb -anchor w
+ DynamicHelp::add $proc_frame_middle_left.checkbutton \
+ -text [mc "Connect external data memory"]
+ set proc_frame_left_btm [frame $proc_frame_middle_left.btm]
+ set project_new_xd_scl [ttk::scale $proc_frame_left_btm.scale \
+ -orient horizontal \
+ -variable ::X::project_new_xdata \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::X::project_new_xdata \[expr {int(\${::X::project_new_xdata})}\]
+ $proc_frame_left_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $project_new_xd_scl \
+ -text [mc "Size of external data memory"]
+ pack $project_new_xd_scl -fill x -side left -expand 1 -padx 2
+ set project_new_xd_spb [spinbox $proc_frame_left_btm.spinbox \
+ -textvariable ::X::project_new_xdata \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::SelectMCU::validate_xdata %P} \
+ -command "$proc_frame_left_btm.spinbox selection range 0 end ;#" \
+ ]
+ DynamicHelp::add $project_new_xd_spb \
+ -text [mc "Size of external data memory"]
+ pack $project_new_xd_spb -side right -after $project_new_xd_scl
+ pack $proc_frame_left_btm -fill both -expand 1
+
+ # Create components of XCODE labelframe
+ set project_new_xc_chb [checkbutton $proc_frame_middle_right.checkbutton \
+ -variable ::X::project_new_xcode_ena \
+ -text [mc "Enable"] \
+ -command ::X::proj_new_xcode_disena \
+ ]
+ pack $project_new_xc_chb -anchor w
+ DynamicHelp::add $proc_frame_middle_right.checkbutton \
+ -text [mc "Connect external program memory"]
+ set proc_frame_right_btm [frame $proc_frame_middle_right.btm]
+ set project_new_xc_scl [ttk::scale $proc_frame_right_btm.scale \
+ -orient horizontal \
+ -variable ::X::project_new_xcode \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::X::project_new_xcode \[expr {int(\${::X::project_new_xcode})}\]
+ $proc_frame_right_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $project_new_xc_scl \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $project_new_xc_scl -fill x -side left -expand 1 -padx 2
+ set project_new_xc_spb [spinbox $proc_frame_right_btm.spinbox \
+ -textvariable ::X::project_new_xcode \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::X::proj_new_validate_xcode %P} \
+ -command "$proc_frame_right_btm.spinbox selection range 0 end ;#" \
+ ]
+ DynamicHelp::add $project_new_xc_spb \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $project_new_xc_spb -side right -after $project_new_xc_scl
+ pack $proc_frame_right_btm -fill both -expand 1
+
+ pack $proc_frame_top0 -anchor w -pady 5 -padx 10
+ pack $proc_frame_top1 -anchor w -pady 5 -padx 10
+ pack $proc_frame_middle_left -side left -fill x -expand 1 -padx 7
+ pack $proc_frame_middle_right -side left -fill x -expand 1 -padx 7
+ pack $proc_frame_middle -fill both -expand 1 -pady 5
+ pack $lb_compiler -fill both -expand 1
+
+ # Adjust XDATA & XCODE controls
+ proj_new_mcu_changed
+
+ ## PROJECT DESCRIPTION
+ label $win.lb_desc_label \
+ -compound left \
+ -text [mc "Project description"] \
+ -image ::ICONS::16::edit
+ set lb_desc [ttk::labelframe $bottom_frame.lb_desc \
+ -labelwidget $win.lb_desc_label -padding 7 \
+ ]
+ pack $lb_desc -fill both -expand 1
+ pack [text $lb_desc.text \
+ -width 0 -height 7 \
+ -yscrollcommand "$lb_desc.scrollbar set" \
+ ] -fill both -expand 1 -side left
+ $lb_desc.text insert end $project_edit_description
+ pack [ttk::scrollbar $lb_desc.scrollbar \
+ -orient vertical \
+ -command "$lb_desc.text yview" \
+ ] -side right -fill y
+
+ # Pack main frames
+ pack $top_left_frame -fill both -expand 1 -padx 5 -side left -pady 10
+ pack $top_right_frame -fill both -expand 1 -padx 5 -side right -pady 10
+ pack $top_frame -fill both -expand 1 -pady 5
+ pack $bottom_frame -fill both -expand 1 -pady 5 -padx 5
+
+ # Buttons 'Ok' and 'Cancel'
+ pack [ttk::separator $win.separator -orient horizontal] -pady 5 -fill x
+ set buttons [frame $win.buttons]
+ pack [ttk::button $buttons.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::project_edit_OK} \
+ ] -side left -padx 5
+ pack [ttk::button $buttons.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::project_edit_CANCEL} \
+ ] -side left -padx 5
+ pack $buttons -anchor center -pady 5
+
+ # Setup some nessesary window manager options -- for modal window
+ wm iconphoto $win ::ICONS::16::edit
+ wm title $win [mc "Edit project - MCU 8051 IDE"]
+ wm minsize $win 660 440
+ wm protocol $win WM_DELETE_WINDOW {
+ X::project_edit_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Project main file EntryBox validator
+ # Enables/Disables project main file clear button
+ # @parm String string - EntryBox contents
+ # @return Bool - allways 1
+ proc proj_edit_mf_validator {string} {
+ variable project_edit_main_file_clr_but ;# Widget: Project main file clear button
+ if {[string length $string]} {
+ $project_edit_main_file_clr_but configure -state normal
+ } {
+ $project_edit_main_file_clr_but configure -state disabled
+ }
+ return 1
+ }
+
+ ## Select project main file
+ # -- Auxiliary procedure for __proj_edit
+ # @return void
+ proc project_edit_select_main_file {} {
+ variable project_edit_main_file ;# Project main file
+ variable actualProject ;# Object: Current project
+
+ set ext [file extension $project_edit_main_file]
+ if {$ext == {.asm} || $ext == {.inc}} {
+ set defaultmask 0
+ } elseif {$ext == {.c} || $ext == {.cpp} || $ext == {.cc} || $ext == {.cxx}} {
+ set defaultmask 1
+ } elseif {$ext == {.h}} {
+ set defaultmask 2
+ } {
+ set defaultmask 3
+ }
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -initialfile $project_edit_main_file \
+ -directory [$actualProject cget -projectPath] \
+ -title [mc "Select main file - %s - MCU 8051 IDE" $actualProject] \
+ -defaultmask $defaultmask -multiple 0 -filetypes [list \
+ [list [mc "Assembly language"] {*.asm} ] \
+ [list [mc "C source"] {*.c} ] \
+ [list [mc "C header"] {*.h} ] \
+ [list [mc "All files"] {*} ] \
+ ]
+ fsd setokcmd {
+ set ::X::project_edit_main_file [X::fsd get]
+ if {![string first [$::X::actualProject cget -projectPath] $::X::project_edit_main_file]} {
+ set ::X::project_edit_main_file \
+ [string replace $::X::project_edit_main_file \
+ 0 [string length [$::X::actualProject cget -projectPath]]]
+ }
+ }
+ fsd activate
+ }
+
+ ## Validate content of entry wingets in dialog "Edit project"
+ # -- axiliary procedure for '__proj_edit'
+ # @parm String string - String to validate
+ # @return Bool - result
+ proc project_edit_validate {string} {
+ if {[string length $string] > 40} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Set project date to today -- axiliary procedure for '__proj_edit'
+ # @return void
+ proc project_edit_today {} {
+ variable project_edit_date ;# Project date (last update)
+
+ set sec [clock seconds]
+ set project_edit_date [clock format $sec -format {%D}]
+ }
+
+ ## Validate content of clock entry in dialog "Edit project"
+ # -- axiliary procedure for '__proj_edit'
+ # @parm String number - String to validate
+ # @return Bool - result
+ proc project_edit_CLOCK_validate {number} {
+ if {![regexp {^\d*$} $number]} {return 0}
+ if {$number > 99999} {return 0}
+ return 1
+ }
+
+ ## Cancel dialog "Edit project" -- axiliary procedure for '__proj_edit'
+ # @return void
+ proc project_edit_CANCEL {} {
+ grab release .project_edit
+ destroy .project_edit
+ }
+
+ ## Save project values -- axiliary procedure for '__proj_edit'
+ # @return void
+ proc project_edit_OK {} {
+ variable actualProject ;# Object: Current project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_edit_version ;# Project version
+ variable project_edit_date ;# Project date (last update)
+ variable project_edit_copyright ;# Copyright information
+ variable project_edit_licence ;# Licence information
+ variable project_edit_clock ;# Default clock rate
+ variable project_edit_main_file ;# Project main file
+ variable project_new_processor ;# Processor type (e.g. "AT89C2051")
+ variable project_new_xdata_ena ;# Bool: XDATA memory connected
+ variable project_new_xcode_ena ;# Bool: XCODE memory connected
+ variable project_new_xdata ;# Int: Amount of XDATA memory
+ variable project_new_xcode ;# Int: Amount of XCODE memory
+ variable project_new_xc_spb ;# Widget: XCODE spinbox
+
+ variable projectdetails_last_project {} ;# Project object of the last project details window
+
+ # Adjust XCODE & XDATA values
+ if {!$project_new_xdata_ena} {
+ set project_new_xdata 0
+ }
+ if {!$project_new_xcode_ena} {
+ set project_new_xcode 0
+ }
+
+ # Adjust values
+ if {$project_edit_clock == {}} {
+ set project_edit_clock [lindex $project_edit_defaults {1 1}]
+ }
+ set project_new_xdata [expr {int($project_new_xdata)}]
+ set project_new_xcode [expr {int($project_new_xcode)}]
+
+ # Determinate original values
+ set xdata_prev [$actualProject cget -P_option_mcu_xdata]
+ set xcode_prev [$actualProject cget -P_option_mcu_xcode]
+ set proc_prev [$actualProject cget -P_option_mcu_type]
+
+ # Change object variables
+ foreach parm {
+ P_option_mcu_xdata P_option_mcu_xcode P_information_version
+ P_information_date G_information_licence G_information_copyright
+ P_option_clock P_option_mcu_type P_option_main_file
+ } \
+ value {
+ project_new_xdata project_new_xcode project_edit_version
+ project_edit_date project_edit_licence project_edit_copyright
+ project_edit_clock project_new_processor project_edit_main_file
+ } {
+ $actualProject configure -$parm [subst "\$$value"]
+ }
+ $actualProject Simulator_set_clock $project_edit_clock
+ $actualProject configure -project_description \
+ [.project_edit.bottom.lb_desc.text get 1.0 end-1c]
+ $actualProject configure -G_information_authors \
+ [.project_edit.top.left.lb_general_info.tframe.frame.text get 1.0 end-1c]
+
+ ## Adjust simulator control panel, register watches and hexeditors
+ # Hex editors
+ close_hexedit eram $actualProject
+ close_hexedit eeprom $actualProject
+ close_hexedit eeprom_wr_bf $actualProject
+ if {$xdata_prev != $project_new_xdata} {
+ close_hexedit xdata $actualProject
+ $actualProject simulator_resize_xdata_memory $project_new_xdata
+ }
+ if {$xcode_prev != $project_new_xcode} {
+ close_hexedit code $actualProject
+ $actualProject simulator_resize_code_memory \
+ [expr {$project_new_xcode + 0xFFFF - [$project_new_xc_spb cget -to]}]
+ }
+ # Simulator control panel and register watches
+ if {$proc_prev != $project_new_processor} {
+ change_processor $project_new_processor
+ }
+ # Adjust register watches
+ if {$xdata_prev != $project_new_xdata && $proc_prev == $project_new_processor} {
+ $actualProject rightPanel_watch_force_enable
+ $actualProject rightPanel_watch_sync_all
+ $actualProject rightPanel_watch_disable
+ }
+ # Menu and toolbar
+ disena_simulator_menu $actualProject
+
+ # Finalize
+ Sbar [mc "New values saved."]
+ project_edit_CANCEL ;# Close the dialog
+ return 1
+ }
+
+ ## Change current MCU even in running simulator
+ # @parm String new_processor - Processor type
+ # @return void
+ proc change_processor {new_processor} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProject ;# Object: Current project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+
+ set intr_mon_opeded [$actualProject interrupt_monitor_is_opened]
+ set was_enabled [lindex $simulator_enabled $actualProjectIdx]
+ if {$was_enabled} {
+ set tmp $critical_procedure_in_progress
+ set critical_procedure_in_progress 0
+ __initiate_sim
+ }
+
+ $actualProject configure -P_option_mcu_type $new_processor
+ $actualProject configure -procData \
+ [SelectMCU::get_processor_details $new_processor]
+ $actualProject refresh_project_avaliable_SFR
+
+ $actualProject stack_monitor_monitor_close
+ $actualProject interrupt_monitor_close
+ $actualProject simulator_initialize_mcu
+ $actualProject SimGUI_clean_up
+ $actualProject simulator_itialize_simulator_control_panel
+ $actualProject graph_itialize_simulator_graph_panel {}
+
+ $actualProject sfrmap_commit_new_sfr_set
+ $actualProject rightPanel_watch_force_enable
+ $actualProject rightPanel_watch_sync_all
+ $actualProject rightPanel_watch_disable
+ $actualProject sfr_watches_commit_new_sfr_set
+ $actualProject pale_MCU_changed
+
+ if {$was_enabled} {
+ __initiate_sim
+ set critical_procedure_in_progress $tmp
+ }
+ if {$intr_mon_opeded} {
+ $actualProject interrupt_monitor_invoke_dialog
+ }
+
+ # Refresh syntax highligh in all editors
+ foreach e [$actualProject cget -editors] {
+ $e parseAll
+ }
+ }
+
+ ## Close the current project
+ # @return void
+ proc __proj_close {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ __proj_save ;# Save project
+ $actualProject editor_close_all 0 1 ;# Close all opened files
+ close_project ;# Close project
+ }
+
+ ## Close the current project without saving
+ # @return Bool - project closed
+ proc __proj_close_imm {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+
+ if {$project_menu_locked} {return}
+
+ set modified 0
+ foreach e [$actualProject cget -editors] {
+ if {[$e cget -modified]} {
+ set modified 1
+ break
+ }
+ }
+
+ set response {yes}
+
+ # Invoke confirmation dialog
+ if {$modified} {
+ set response [tk_messageBox \
+ -icon question \
+ -parent . \
+ -type yesno \
+ -title [mc "Requesting confirmation %s" ${::APPNAME}] \
+ -message [mc "Are you sure want to close the project without saving changes ?"] \
+ ]
+ }
+ # Close project
+ if {$response == {yes}} {
+ close_project
+ return 1
+ } {
+ return 0
+ }
+ }
+
+ ## Close the current project -- auxiliary procedure for '__proj_close_imm' and '__proj_close'
+ # @return void
+ proc close_project {} {
+ variable compilation_mess_project ;# Object: Project related to running compilation
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable openedProjects ;# List of opened projects (Object references)
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Abort running compilation
+ if {$compilation_in_progress && $compilation_mess_project == $actualProject} {
+ __abort_compilation
+ }
+
+ # Abort running simulation
+ if {$actualProjectIdx != -1 && ([lindex $simulator_enabled $actualProjectIdx] == 1)} {
+ set critical_procedure_in_progress 0
+ __initiate_sim
+ set critical_procedure_in_progress 1
+ }
+
+ # Delete project object
+ close_hexedit xdata $actualProject
+ close_hexedit code $actualProject
+ close_hexedit eram $actualProject
+ close_hexedit eeprom $actualProject
+ delete object $actualProject
+ # Adjust list of opened project and simlator started flag
+ set openedProjects [lreplace $openedProjects $actualProjectIdx $actualProjectIdx]
+ set simulator_enabled [lreplace $simulator_enabled $actualProjectIdx $actualProjectIdx]
+
+ # Raise nex tab or disable project menu and procedures
+ if {[llength $openedProjects] > 0} {
+ set actualProject [lindex $openedProjects 0]
+ .mainFrame.mainNB raise [string trimleft $actualProject {:}]
+ } {
+ set project_menu_locked 1
+ Lock_project_menu
+ }
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Compile current file
+ # @parm Bool = 0 - Force compilation -- ignore running critical procedure
+ # @parm Bool = 0 - Start simulator after successful compilation
+ # @parm Bool = 0 - Compile current file only (not the main file)
+ # @return Bool - result or {}
+ proc __compile args {
+ variable compilation_successfull ;# Bool: Compilation successfull
+ variable actualProject ;# Object: Current project
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable compiler_pid ;# Int: PID of external compiler if used
+ variable compilation_start_simulator ;# Bool: Start simulator after successful compilation
+ variable compile_this_file_only ;# Bool: Compile the current file only
+ variable compilation_mess_project ;# Object: Project related to running compilation
+
+ # Parse input arguments
+ if {[lindex $args 0] == 1} {
+ set force 1
+ } {
+ set force 0
+ }
+ if {[lindex $args 1] == 1} {
+ set compilation_start_simulator 1
+ } {
+ set compilation_start_simulator 0
+ }
+ if {[lindex $args 2] == 1} {
+ set compile_this_file_only 1
+ } {
+ set compile_this_file_only 0
+ }
+
+ if {$project_menu_locked} {return}
+ if {!$force && $critical_procedure_in_progress} {return}
+ if {$compilation_in_progress} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to run assembler"] \
+ -message [mc "Something is already running in background."]
+ return 0
+ }
+
+ # Compilation started
+ set compilation_mess_project $actualProject
+ set compilation_successfull 1
+ set result 0
+ set compiler_pid 0
+ set compilation_in_progress 1
+ set Compiler::Settings::ABORT_VARIABLE 0
+ # Save current file
+ if {![$actualProject editor_procedure {} save {}]} {
+ set compilation_in_progress 0
+ return 0
+ }
+ # Raise tab "Messages"
+ $actualProject bottomNB_show_up {Messages}
+ # Determinate name of file to compile
+ if {$compile_this_file_only} {
+ set input_file {}
+ } {
+ set input_file [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ }
+ if {[lindex $input_file 1] == {}} {
+ set input_file [$actualProject editor_procedure {} getFileName {}]
+ set language [$actualProject editor_procedure {} get_language {}]
+ } {
+ set ext [string trimleft [file extension [lindex $input_file 1]] {.}]
+ if {$ext == {c} || $ext == {h} || $ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set language 1
+ } elseif {$ext == {lst}} {
+ set language 2
+ } else {
+ set language 0
+ }
+ }
+ # Adjust filename
+ set cur_dir [lindex $input_file 0]
+ set input_file_name [lindex $input_file 1]
+ if {[regexp {\.[^\.]*$} $input_file_name input_file_extension]} {
+ regsub {\.[^\.]*$} $input_file_name {} input_file_name
+ set input_file_extension [string range $input_file_extension 1 end]
+ } {
+ set input_file_extension {}
+ }
+ # Asjust file extension
+ if {$input_file_extension == {h}} {
+ set input_file_extension {c}
+ } elseif {$input_file_extension == {lst}} {
+ set input_file_extension {asm}
+ }
+
+ # Adjust statusbar
+ Sbar [mc "Compiling ..."]
+ make_progressBar_on_Sbar
+ compilation_progress
+
+ # Determinate memory limits
+ set iram_size [lindex [$actualProject cget -procData] 3]
+ set eram_size [lindex [$actualProject cget -procData] 8]
+ set xram_size [$actualProject cget -P_option_mcu_xdata]
+ if {$eram_size > $xram_size} {
+ set xram_size $eram_size
+ }
+ set code_size [expr {
+ ([lindex [$actualProject cget -procData] 2] * 1024)
+ +
+ [$actualProject cget -P_option_mcu_xcode]
+ }]
+
+ ## C language
+ if {$language == 1} {
+ if {!${::PROGRAM_AVALIABLE(sdcc)} && !${::PROGRAM_AVALIABLE(sdcc-sdcc)}} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Compiler not found"] \
+ -message [mc "Unable to find sdcc, please install sdcc and restart MCU 8051 IDE"]
+ } {
+ # Start compiler
+ set compiler_pid [::ExternalCompiler::compile_C \
+ $cur_dir $input_file_name.$input_file_extension \
+ $iram_size $xram_size $code_size \
+ ]
+ return 2
+ }
+
+ ## Assembly language
+ } else {
+ # Check if the choosen assembler is avaliable in the system
+ set avaliable 0
+ switch -- $::ExternalCompiler::selected_assembler {
+ 0 { ;# Native assembler
+ set avaliable 1
+ set assembler_name [mc "MCU 8051 IDE Native assembler"]
+ set assembler_cmd {mcu8051ide --compile}
+ }
+ 1 { ;# ASEM-51
+ set avaliable ${::PROGRAM_AVALIABLE(asem)}
+ set assembler_name "ASEM-51"
+ set assembler_cmd {asem}
+ }
+ 2 { ;# ASL
+ set avaliable ${::PROGRAM_AVALIABLE(asl)}
+ set assembler_name "ASL"
+ set assembler_cmd {asl}
+ }
+ 3 { ;# AS31
+ set avaliable ${::PROGRAM_AVALIABLE(as31)}
+ set assembler_name "AS31"
+ set assembler_cmd {as31}
+ }
+ default {
+ error "Unknown internal error -- Invalid ID of the selected assembler"
+ }
+ }
+ if {!$avaliable} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon error \
+ -title [mc "%s assembler not found" $assembler_name] \
+ -message [mc "Unable to run program \"%s\". Please check if you have installed this assembler or choose a different one in compiler configuration dialog." $assembler_cmd]
+ finalize_compilation 0
+ return 0
+ }
+
+ # Execute compiler
+ switch -- $::ExternalCompiler::selected_assembler {
+ 0 { ;# Native assembler
+ # Adjust compiler settings
+ set ::Compiler::Settings::TEXT_OUPUT_COMMAND X::messages_text_append
+ set ::Compiler::Settings::UPDATE_COMMAND {update}
+ set ::Compiler::Settings::iram_size $iram_size
+ set ::Compiler::Settings::xram_size $xram_size
+ set ::Compiler::Settings::code_size $code_size
+ set ::PreProcessor::check_sfr_usage 1
+ set ::PreProcessor::avaliable_SFR [string tolower [$actualProject cget -avaliable_SFR]]
+
+ # Perform code compilation
+ if {[catch {
+ set result [Compiler::compile \
+ [$actualProject cget -projectPath] \
+ $cur_dir $input_file_name $input_file_extension \
+ ]
+ }]} then {
+ puts stderr "Compiler crashed: \"${::errorInfo}\""
+ tk_messageBox \
+ -parent . \
+ -icon error \
+ -type ok \
+ -title [mc "Compiler crash - MCU 8051 IDE"] \
+ -message [mc "Compiler crased, we are terribly sorry about that.\n\nPlease report this bug via project web or mail to author and please don't forget to include source code on which this error occured."]
+ }
+ ::Compiler::free_resources
+ set Compiler::Settings::ABORT_VARIABLE 0
+ }
+ 1 { ;# ASEM-51
+ set compiler_pid [::ExternalCompiler::asem51_compile $cur_dir \
+ $input_file_name.$input_file_extension \
+ [$actualProject cget -projectPath] \
+ ]
+ return 2
+ }
+ 2 { ;# ASL
+ set compiler_pid [::ExternalCompiler::asl_compile $cur_dir \
+ $input_file_name.$input_file_extension \
+ [$actualProject cget -projectPath] \
+ ]
+ return 2
+ }
+ 3 { ;# AS31
+ set compiler_pid [::ExternalCompiler::as31_compile $cur_dir \
+ $input_file_name.$input_file_extension \
+ [$actualProject cget -projectPath] \
+ ]
+ return 2
+ }
+ default {
+ error "Unknown internal error -- Invalid ID of the selected assembler"
+ }
+ }
+ }
+
+ finalize_compilation $result
+ return $result
+ }
+
+ ## Compile the current file or the main file if it has not been already compiled
+ # @parm String success_callback - Procedure to call upon successfull compilation
+ # @parm String fail_callback - Procedure to call upon failed compilation
+ # @return void
+ proc compile_if_nessesary_and_callback {success_callback fail_callback} {
+ variable actualProject ;# Object: Current project
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable compilation_success_callback ;# String: Indented for HW plugins
+ variable compilation_fail_callback ;# String: Indented for HW plugins
+
+ set compilation_success_callback $success_callback
+ set compilation_fail_callback $fail_callback
+
+ set full_file_name [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ set relative_name [lindex $full_file_name 1]
+ if {$relative_name == {}} {
+ set full_file_name [$actualProject editor_procedure {} getFileName {}]
+ set language [$actualProject editor_procedure {} get_language {}]
+ set relative_name [lindex $full_file_name 1]
+ } {
+ set ext [string trimleft [file extension $relative_name] {.}]
+ if {$ext == {c} || $ext == {h} || $ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set language 1
+ } elseif {$ext == {lst}} {
+ set language 2
+ } else {
+ set language 0
+ }
+ }
+ set full_file_name [file join [lindex $full_file_name 0] [lindex $full_file_name 1]]
+ set full_file_name [file rootname $full_file_name]
+ if {$language != 1} {
+ append full_file_name {.adf}
+ } {
+ append full_file_name {.hashes}
+ }
+
+
+ if {![catch {
+ # C language
+ if {$language == 1} {
+ set hashes_file [open $full_file_name r]
+ set expected_md5s [read $hashes_file]
+ close $hashes_file
+
+ # Assembly language
+ } elseif {$language == 0} {
+ set expected_md5s {}
+ set simulator_file [open $full_file_name r]
+ while {![eof $simulator_file]} {
+ set line [gets $simulator_file]
+ if {$line == {} || [regexp {^\s*#} $line]} {
+ continue
+ }
+ set expected_md5s $line
+ break
+ }
+ close $simulator_file
+
+ # Invalid request!
+ } else {
+ error "Invalid request!"
+ }
+
+ }]} then {
+ if {[verify_md5_hashes 1 $expected_md5s]} {
+ __compile
+ return
+ }
+ } else {
+ __compile
+ return
+ }
+
+ eval "$compilation_success_callback"
+ }
+
+ ## Finalize compilation process
+ # Auxiliary procedure for procedures: __compile && ext_compilation_complete
+ # @parm Bool result - 1 == Compilation successfull; 0 == Compilation failed
+ # @return void
+ proc finalize_compilation {result} {
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable compilation_success_callback ;# String: Indented for HW plugins
+ variable compilation_fail_callback ;# String: Indented for HW plugins
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ set critical_procedure_in_progress 0
+
+ # Adjust statusbar
+ destroy_progressBar_on_Sbar
+ if {$result} {
+ Sbar [mc "Compilation successful"]
+ if {$compilation_success_callback != {}} {
+ eval "$compilation_success_callback"
+ set compilation_fail_callback {}
+ set compilation_success_callback {}
+ }
+ } {
+ Sbar [mc "Compilation failed"]
+ if {$compilation_fail_callback != {}} {
+ eval "$compilation_fail_callback"
+ set compilation_fail_callback {}
+ set compilation_success_callback {}
+ }
+ }
+
+ # Done ...
+ set compilation_in_progress 0
+ }
+
+ ## Handle text output from external or internal compiler
+ # @parm String text - Output from external compiler
+ # @return void
+ proc compilation_message args {
+ variable compilation_successfull ;# Bool: Compilation successfull
+ variable compilation_mess_project ;# Object: Project related to running compilation
+
+ set args [string replace \
+ [regsub -all "\\\{" \
+ [regsub -all "\\\}" \
+ [lindex $args 0]\
+ "\}"] \
+ "\{"] \
+ 0 0]
+
+ # Backspace charactes
+ set idx 0
+ while 1 {
+ set idx [string first "\b" $args $idx]
+ if {$idx == -1} {
+ break
+ }
+ set args [string replace $args [expr {$idx - 1}] [expr {$idx + 1}]]
+ incr idx -1
+ }
+
+ if {[$compilation_mess_project messages_text_append [string trimright $args]]} {
+ set compilation_successfull 0
+ }
+ }
+
+ ## External compiler finnished its work
+ # @return void
+ proc ext_compilation_complete {} {
+ variable compilation_mess_project ;# Object: Project related to running compilation
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable openedProjects ;# List of opened projects (Object references)
+ variable compilation_start_simulator ;# Bool: Start simulator after successful compilation
+ variable compile_this_file_only ;# Bool: Compile the current file only
+ variable compilation_successfull ;# Bool: Compilation successfull
+
+ finalize_compilation $compilation_successfull
+
+ # Conditionaly start simulator
+ if {$compilation_start_simulator && $compilation_successfull} {
+ set actualProject_org $actualProject
+ set actualProjectIdx_org $actualProjectIdx
+
+ set actualProject $compilation_mess_project
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+
+ __initiate_sim $compile_this_file_only
+
+ set actualProject $actualProject_org
+ set actualProjectIdx $actualProjectIdx_org
+ } elseif {$compilation_start_simulator && !$compilation_successfull} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [mc "Compilation failed"] \
+ -message [mc "Compilation failed, see messages for details."]
+ }
+ }
+
+ ## Abort running compilation -- auxiliary procedure for '__compile'
+ # @return void
+ proc __abort_compilation {} {
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable doxygen_pid ;# Int: Doxygen PID
+ variable compiler_pid ;# Int: PID of external compiler if used
+
+ set Compiler::Settings::ABORT_VARIABLE 1
+ destroy_progressBar_on_Sbar
+
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no kill command on Microsoft Windows
+ # Kill doxygen
+ if {$doxygen_pid} {
+ foreach pid $doxygen_pid {
+ catch {
+ exec -- kill -9 $pid &
+ }
+ }
+
+ # Kill SDCC
+ } elseif {${compiler_pid} != {} && ${compiler_pid} != 0} {
+ foreach pid $compiler_pid {
+ catch {
+ exec -- kill -9 $pid &
+ }
+ }
+ }
+ }
+
+ set compilation_in_progress 0
+ set compiler_pid 0
+ set doxygen_pid 0
+ }
+
+ ## Create progressbar on status bar (showing compilation progress)
+ # -- auxiliary procedure for '__compile'
+ # @return void
+ proc make_progressBar_on_Sbar {} {
+ # Frame
+ pack [frame .statusbarR] -in .statusbarF -side right
+ # Label "Compilation"
+ pack [label .status_sim_label \
+ -text [mc "Compilation: "] \
+ ] -in .statusbarR -side left
+ # Button "Abort"
+ pack [ttk::button .status_sim_button \
+ -text [mc "Abort"] \
+ -image ::ICONS::16::cancel \
+ -compound left \
+ -command {X::__abort_compilation} \
+ ] -in .statusbarR -side left
+ # Progressbar
+ pack [ttk::progressbar .status_sim_prog \
+ -maximum 1000 \
+ -mode indeterminate \
+ -variable X::compilation_progress \
+ -length 100 \
+ ] -in .statusbarR -side left
+ }
+
+ ## Destroy progressbar on status bar (showing compilation progress)
+ # -- auxiliary procedure for '__compile'
+ # @return void
+ proc destroy_progressBar_on_Sbar {} {
+ catch {
+ destroy .statusbarR
+ destroy .status_sim_label
+ destroy .status_sim_button
+ destroy .status_sim_prog
+ }
+ }
+
+ ## Increment progreesbar on statusbar (compilation progress)
+ # -- auxiliary procedure for '__compile'
+ # @return void
+ proc compilation_progress {} {
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable compilation_in_progress ;# Bool: Compiler engaged
+
+ if {!$compilation_in_progress} {return}
+
+ incr compilation_progress
+ if {$compilation_progress > 100} {
+ set compilation_progress 0
+ }
+ after 200 {X::compilation_progress}
+ }
+
+ ## Append text to messages text (bottom panel - tab "Messages")
+ # @parm String text - Text to append
+ # @return Bool - True if error occured
+ proc messages_text_append {text} {
+ variable actualProject ;# Object: Current project
+ variable compilation_mess_project ;# Object: Project related to running compilation
+
+ return [$compilation_mess_project messages_text_append $text]
+ }
+
+ ## Copy selected text in messages text to clipboard (bottom panel - tab "Messages")
+ # @return void
+ proc __copy_messages_text {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Copy
+ $actualProject copy_messages_text
+ }
+
+ ## Select all text in messages text (bottom panel - tab "Messages")
+ # @return void
+ proc __select_all_messages_text {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Select all
+ $actualProject select_all_messages_text
+ }
+
+ ## Clear content of messages text (bottom panel - tab "Messages")
+ # @return void
+ proc __clear_messages_text {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # CLear
+ $actualProject clear_messages_text
+ }
+
+ ## Export content of the current editor as XHTML/LaTeX
+ # -- auxiliary procedure for '__toHTML' and '__toLaTeX'
+ # @parm String - Target type ('-html' or '-latex')
+ # @parm String - Title of the dialog window
+ # @return void
+ proc exportToX args {
+ variable actualProject ;# Object: Current project
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable fsd_result ;# Value returnded by file selection dialog (in some cases)
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Expect 2 arguments
+ if {[llength $args] != 2} {
+ error "expected exactly 2 arguments"
+ }
+
+ # Check if the editor isn't empty
+ if {
+ [$actualProject editor_procedure {} getLinesCount {}] == 1
+ &&
+ [$actualProject editor_procedure {} getLineContent 1] == {}
+ } {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "This editor seems to be empty"]
+ return
+ }
+
+ # Determinate target file type (html/latex)
+ set targetType [lindex $args 0]
+ # Compilation started
+ set compilation_progress 1
+ # Determinate maximum value for progress bar
+ set max [$actualProject editor_procedure {} highlight_all_count_of_iterations {}]
+ incr max
+
+ # Create diwlog window
+ set win [toplevel .exportToX_dialog -class [mc "Export dialog"] -bg {#EEEEEE}]
+ wm withdraw $win
+
+ # Label and progress bar
+ set main_frame [frame $win.main_frame]
+ pack [label $main_frame.header \
+ -text [mc "Finishing highlight ..."] \
+ ] -pady 10 -padx 20 -anchor w
+ pack [ttk::progressbar $main_frame.progress_bar \
+ -maximum $max \
+ -mode determinate \
+ -variable {X::compilation_progress} \
+ -length 430 \
+ ] -fill y
+ pack $main_frame -fill x -expand 1
+
+ # Button abort
+ pack [ttk::button $win.abort_button \
+ -text [mc "Abort"] \
+ -command "X::exportToX_abort $targetType" \
+ -image ::ICONS::16::cancel \
+ -compound left \
+ ]
+
+ # Determinate target file name
+ set file [$actualProject editor_procedure {} getFileName {}]
+ set filename [lindex $file 1]
+ if {[lindex $file 0] != {}} {
+ set dir [lindex $file 0]
+ } {
+ set dir [$actualProject cget -projectPath]
+ }
+ regsub {\.[^\.]*$} $filename {} filename
+ if {$targetType == "-html"} {
+ set suffix {html}
+ } {
+ set suffix {tex}
+ }
+ append filename {.} $suffix
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -initialfile $filename -directory $dir \
+ -title [mc "Export as %s - MCU 8051 IDE" [lindex $args 1]] \
+ -defaultmask 0 -multiple 0 -filetypes [subst "
+ {{[mc {[string toupper $suffix] file}]} {*.$suffix}}
+ {{[mc {All files}]} {*}}"]
+ fsd setokcmd {
+ set ::X::fsd_result [X::fsd get]
+ }
+ set fsd_result {}
+ fsd activate
+
+ set filename $fsd_result
+ if {[file isdirectory $filename] || ![string length $filename]} {
+ exportToX_abort $targetType
+ return
+ }
+ if {![regexp {\.\w+$} $filename]} {
+ append filename {.} $suffix
+ }
+
+ # Create backup file
+ if {[file exists $filename] && [file isfile $filename]} {
+ if {![file writable $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to access file: %s" $filename]
+ exportToX_abort $targetType
+ return
+ }
+ # Ask user for overwrite existing file
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent . \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $filename]]
+ ] != {yes}
+ } {
+ return
+ }
+ # Create a backup file
+ catch {
+ file rename -force $filename "$filename~"
+ }
+ }
+
+ # Open target file
+ if {[catch {
+ set file [open $filename w 420]
+ }]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to write to file: \"%s\"" $filename]
+ exportToX_abort $targetType
+ return
+ }
+
+ # Set window attributes
+ if {![winfo exists $win]} {return}
+ wm iconphoto $win ::ICONS::16::html
+ wm deiconify $win
+ wm title $win [mc "[lindex $args 1] - MCU 8051 IDE"]
+ wm minsize $win 450 70
+ wm protocol $win WM_DELETE_WINDOW {
+ exportToX_abort
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ update
+
+ # Highlight all lines in the editor
+ $actualProject editor_procedure {} highlight_all {}
+ if {![winfo exists $win]} {return}
+
+ # Ajust window (Second stage)
+ set max [$actualProject editor_procedure {} getDataAsXHTML_count_of_iterations {}]
+ incr max
+ $main_frame.header configure -text [mc "Converting ..."]
+ $main_frame.progress_bar configure -maximum $max
+ set compilation_progress 1
+ update
+
+ # Export and write data
+ if {$targetType == "-html"} {
+ puts -nonewline $file [$actualProject editor_procedure {} getDataAsXHTML {}]
+ } elseif {$targetType == "-latex"} {
+ puts -nonewline $file [$actualProject editor_procedure {} getDataAsLaTeX {}]
+ } else {
+ error "Unknown argument: $targetType\n\tpossible vaues are: -html -latex"
+ }
+ close $file
+ exportToX_abort $targetType
+
+ # Show result
+ Sbar [mc "Expoted data saved to %s" $filename]
+ }
+
+ ## Abort export content of the current editor as XHTML/LaTeX
+ # -- auxiliary procedure for '__toHTML' and '__toLaTeX'
+ # @parm String - Target type ('-html' or '-latex')
+ # @return void
+ proc exportToX_abort {targetType} {
+ variable actualProject ;# Object: Current project
+
+ # Abort export
+ if {$targetType == "-html"} {
+ $actualProject editor_procedure {} getDataAsXHTML_abort_now {}
+ } elseif {$targetType == "-latex"} {
+ $actualProject editor_procedure {} getDataAsLaTeX_abort_now {}
+ } else {
+ error "Unknown argument: $targetType\n\tpossible vaues are: -html -latex"
+ }
+
+ # Destroy dialog window
+ destroy .exportToX_dialog
+ grab release .exportToX_dialog
+ }
+
+ ## Export data contained in the current editor as XHTML
+ # @return void
+ proc __toHTML {} {
+ exportToX -html "Export to XHTML"
+ }
+
+ ## Export data contained in the current editor as LaTeX
+ # @return void
+ proc __toLaTeX {} {
+ exportToX -latex "Export to LaTeX"
+ }
+
+ ## Exit program
+ # - Ask for saving unsaved files and projects
+ # - Save all projects
+ # - Save session file
+ # - Exit
+ # @parm Bool = 0 - Print message "Exitong on user request"
+ # @return void
+ proc __exit args {
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProject ;# Object: Current project
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable procedure_exit_in_progress ;# Bool: proc "__exit" in progress
+ variable unsaved_projects ;# List: List of project object marked as "unsaved"
+ variable eightsegment_editors ;# List: All 8-segment LED display editors invoked
+ variable spec_calc_objects ;# List: All special calculator objects
+ variable rs232debugger_objects ;# List: All "RS232 debugger" objects
+
+ # If application is not loaded -> exit immediately
+ if {!${::APPLICATION_LOADED}} {
+ exit
+ }
+
+ # This procedure cannot be recursive
+ if {$procedure_exit_in_progress} {
+ return
+ }
+ set procedure_exit_in_progress 1
+
+ # Parse arguments
+ if {[lindex $args 0] == 1} {
+ set do_not_print_exit_message 1
+ } {
+ set do_not_print_exit_message 0
+ }
+
+ # Ask hardware whether it's ready for exit
+ foreach project $openedProjects {
+ if {![$project hw_manager_comfirm_exit]} {
+ set procedure_exit_in_progress 0
+ return
+ }
+ }
+
+ foreach obj [concat $eightsegment_editors $spec_calc_objects $rs232debugger_objects] {
+ catch {
+ delete object $obj
+ }
+ }
+
+ # Cancel running compilation
+ if {$compilation_in_progress} {
+ __abort_compilation
+ }
+
+ # Determinate list of unsaved projects
+ set unsaved_projects {}
+ foreach project $openedProjects {
+ foreach editor [$project cget -editors] {
+ if {[$editor cget -modified]} {
+ lappend unsaved_projects "{$project} {$editor}"
+ }
+ }
+ }
+
+ # Ask user for saving unsaved files -- use proc 'shutdown_dialog'
+ if {[llength $unsaved_projects] != 0} {
+ switch -- [shutdown_dialog] {
+ 0 { ;# SAVESELECTED
+ set i 0
+ foreach unsaved $unsaved_projects {
+ set bool [subst "\$::unsavedfile$i"]
+ if {$bool == 1} {
+ [lindex [lindex $unsaved_projects $i] 1] save
+ }
+ incr i
+ }
+
+ }
+ 1 { ;# SAVEALL
+ set last_project {}
+ foreach project $unsaved_projects {
+ set project [lindex $project 0]
+ if {$last_project == $project} {continue}
+ set last_project $project
+ $project editor_save_all
+ }
+ }
+ 2 { ;# DISCARD
+ }
+ 3 { ;# CANCEL
+ set procedure_exit_in_progress 0
+ return 0
+ }
+ }
+ }
+
+ if {!$do_not_print_exit_message} {
+ puts [mc "\nExiting program on user request ..."]
+ }
+
+ # Withdraw main window
+ wm withdraw .
+ # Withdraw all PALE windows
+ foreach project $openedProjects {
+ $project pale_withdraw_all_windows
+ }
+ update
+
+ # Save session
+ if {[catch {
+ save_session
+ } result]} then {
+ puts stderr [mc "An error occured when saving the last session"]
+ puts stderr $result
+ }
+
+ # Save all projects
+ foreach project $openedProjects {
+ $project kill_childern
+ set actualProject $project
+ __proj_save
+ }
+
+ puts [mc "Program terminated"]
+
+ exit
+ }
+
+ ## Save the current session
+ # @return void
+ proc save_session {} {
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProject ;# Object: Current project
+ variable session_file ;# Path to file defining the last session
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+
+ variable line2pc_jump ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+
+ variable file_recent_files ;# List: recently opened files
+ variable project_recent_files ;# List: recently opened projects
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ variable base_convertors ;# List: All base convertor objects
+
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ # Create configuration directory if it is not exist already
+ if {![file exists ${::CONFIG_DIR}] || ![file isdirectory ${::CONFIG_DIR}]} {
+ if {[catch {[file mkdir ${::CONFIG_DIR}]}]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to save running config"]
+ return 0
+ }
+ }
+
+ # Get project dependent options
+ if {([llength $openedProjects] > 0) && ($actualProject != {})} {
+ array set ::CONFIG [subst {
+ LINE_NUMBERS [$actualProject cget -lineNumbers]
+ ICON_BORDER [$actualProject cget -iconBorder]
+ LEFT_PANEL [$actualProject isLeftPanelVisible]
+ RIGHT_PANEL [$actualProject isRightPanelVisible]
+ BOTTOM_PANEL [$actualProject isBottomPanelVisible]
+ LEFT_PANEL_SIZE [$actualProject getLeftPanelSize]
+ RIGHT_PANEL_SIZE [$actualProject getRightPanelSize]
+ BOTTOM_PANEL_SIZE [$actualProject getBottomPanelSize]
+ LEFT_PANEL_ACTIVE_PAGE {[$actualProject getLeftPanelActivePage]}
+ RIGHT_PANEL_ACTIVE_PAGE {[$actualProject getRightPanelActivePage]}
+ BOTTOM_PANEL_ACTIVE_PAGE {[$actualProject getBottomPanelActivePage]}
+ SUBP_MON_CONFIG {[$actualProject subprograms_get_config]}
+ FS_BROWSER_MASK {[$actualProject fs_browser_get_current_mask]}
+ FIND_IN_FILES_CONFIG {[$actualProject findinfiles_get_config]}
+ STOPWATCH_CONFIG {[$actualProject stopwatch_get_config]}
+ C_VARS_VIEW_CONF {[$actualProject cvarsview_get_config]}
+ BITMAP_CONFIG {[$actualProject bitmap_get_config]}
+ HW_MANAGER_CONFIG {[$actualProject hw_manager_get_cfg]}
+ REGWATCHES_CONFIG {[$actualProject rightPanel_watch_get_config]}
+ FILE_NOTES {[$actualProject get_file_notes_config]}
+ }]
+ }
+ # Get project independent options
+ array set ::CONFIG [subst {
+ KIFSD_CONFIG {[::KIFSD::FSD::get_config_array]}
+ HEXEDIT_CONFIG {[::HexEditDlg::getConfig]}
+ FIND_OPTIONS {[list $find_option_CS \
+ $find_option_back \
+ $find_option_cur \
+ $find_option_sel \
+ $find_option_reg]}
+ REPLACE_OPTIONS {[list $replace_option_CS \
+ $replace_option_back \
+ $replace_option_cur \
+ $replace_option_reg]}
+ INTR_MON_GEOMETRY {${::InterruptMonitor::geometry}}
+ OPEN_WITH_DLG {${::FileList::open_with}}
+ SYMBOL_VIEWER_CONFIG {${::SymbolViewer::config_list}}
+ LINE2PC_JUMP {$line2pc_jump}
+ FILE_RECENT_FILES {$file_recent_files}
+ PROJECT_RECENT_FILES {$project_recent_files}
+ VHW_RECENT_FILES {$vhw_recent_files}
+ EIGHT_SEG_EDITOR {${::EightSegment::config}}
+ SPEC_CALC {${::SpecCalc::config}}
+ ASK_ON_FILE_OPEN {${::FileList::ask__append_file_to_project}}
+ RS232_DEBUGGER {${::RS232Debugger::config_list}}
+ STACK_MON_GEOMETRY {${::StackMonitor::geometry}}
+ STACK_MON_COLLAPSED {${::StackMonitor::collapsed}}
+ }]
+ set ::CONFIG(LETTER_CASE) {}
+ for {set i 0} {$i < 21} {incr i} {
+ lappend ::CONFIG(LETTER_CASE) $change_letter_case_options($i)
+ }
+ set ::CONFIG(BASE_CONVERTORS) {}
+ foreach obj $base_convertors {
+ lappend ::CONFIG(BASE_CONVERTORS) [$obj get_config]
+ }
+
+ # Open session file
+ if {[catch {
+ set file [open $session_file w 420]
+ }]} then {
+ tk_messageBox -parent . -type ok -icon error \
+ -title [mc "Access denied"] \
+ -message [mc "Unable to write to file: \"%s\"" $session_file]
+ return
+ }
+
+ # Write session file
+ puts $file "# ${::APPNAME} [clock format [clock seconds] -format {%T %D}]"
+ puts $file "# Please do not modify this file manualy.\n"
+
+ puts $file "# booleans"
+ if {$::MICROSOFT_WINDOWS} {
+ # There is no such thing on Windows OS
+ puts $file "WINDOW_ZOOMED = \"0\""
+ } {
+ puts $file "WINDOW_ZOOMED = \"[wm attributes . -zoomed]\""
+ }
+ puts $file "LINE_NUMBERS = $::CONFIG(LINE_NUMBERS)"
+ puts $file "ICON_BORDER = $::CONFIG(ICON_BORDER)"
+ puts $file "LEFT_PANEL = $::CONFIG(LEFT_PANEL)"
+ puts $file "RIGHT_PANEL = $::CONFIG(RIGHT_PANEL)"
+ puts $file "BOTTOM_PANEL = $::CONFIG(BOTTOM_PANEL)"
+ puts $file "TOOLBAR_VISIBLE = $::CONFIG(TOOLBAR_VISIBLE)"
+ puts $file "BREAKPOINTS_ALLOWED = $::CONFIG(BREAKPOINTS_ALLOWED)"
+ puts $file "LINE2PC_JUMP = $::CONFIG(LINE2PC_JUMP)"
+ puts $file "ASK_ON_FILE_OPEN = $::CONFIG(ASK_ON_FILE_OPEN)"
+ puts $file "SHOW_EDITOR_TAB_BAR = $::CONFIG(SHOW_EDITOR_TAB_BAR)"
+ puts $file "STACK_MON_COLLAPSED = $::CONFIG(STACK_MON_COLLAPSED)"
+ puts $file "\n# integers"
+ puts $file "LEFT_PANEL_SIZE = $::CONFIG(LEFT_PANEL_SIZE)"
+ puts $file "RIGHT_PANEL_SIZE = $::CONFIG(RIGHT_PANEL_SIZE)"
+ puts $file "BOTTOM_PANEL_SIZE = $::CONFIG(BOTTOM_PANEL_SIZE)"
+ puts $file "VALIDATION_LEVEL = $::CONFIG(VALIDATION_LEVEL)"
+ puts $file "\n# strings"
+ puts $file "LEFT_PANEL_ACTIVE_PAGE = \"$::CONFIG(LEFT_PANEL_ACTIVE_PAGE)\""
+ puts $file "RIGHT_PANEL_ACTIVE_PAGE = \"$::CONFIG(RIGHT_PANEL_ACTIVE_PAGE)\""
+ puts $file "BOTTOM_PANEL_ACTIVE_PAGE = \"$::CONFIG(BOTTOM_PANEL_ACTIVE_PAGE)\""
+ puts $file "OPEN_WITH_DLG = \"$::CONFIG(OPEN_WITH_DLG)\""
+ puts $file "FS_BROWSER_MASK = \"$::CONFIG(FS_BROWSER_MASK)\""
+ puts $file "FILE_RECENT_FILES = \"$::CONFIG(FILE_RECENT_FILES)\""
+ puts $file "PROJECT_RECENT_FILES = \"$::CONFIG(PROJECT_RECENT_FILES)\""
+ puts $file "VHW_RECENT_FILES = \"$::CONFIG(VHW_RECENT_FILES)\""
+ puts $file "\n# lists"
+ puts $file "CLEANUP_OPTIONS = \"[regsub -all {\s+} $::CONFIG(CLEANUP_OPTIONS) { }]\""
+ puts $file "FIND_OPTIONS = \"$::CONFIG(FIND_OPTIONS)\""
+ puts $file "REPLACE_OPTIONS = \"$::CONFIG(REPLACE_OPTIONS)\""
+ puts $file "LETTER_CASE = \"$::CONFIG(LETTER_CASE)\""
+ puts $file "KIFSD_CONFIG = \"$::CONFIG(KIFSD_CONFIG)\""
+ puts $file "HEXEDIT_CONFIG = \"$::CONFIG(HEXEDIT_CONFIG)\""
+ puts $file "SUBP_MON_CONFIG = \"$::CONFIG(SUBP_MON_CONFIG)\""
+ puts $file "FIND_IN_FILES_CONFIG = \"$::CONFIG(FIND_IN_FILES_CONFIG)\""
+ puts $file "SYMBOL_VIEWER_CONFIG = \"$::CONFIG(SYMBOL_VIEWER_CONFIG)\""
+ puts $file "STOPWATCH_CONFIG = \"$::CONFIG(STOPWATCH_CONFIG)\""
+ puts $file "C_VARS_VIEW_CONF = \"$::CONFIG(C_VARS_VIEW_CONF)\""
+ puts $file "BITMAP_CONFIG = \"$::CONFIG(BITMAP_CONFIG)\""
+ puts $file "HW_MANAGER_CONFIG = \"$::CONFIG(HW_MANAGER_CONFIG)\""
+ puts $file "REGWATCHES_CONFIG = \"$::CONFIG(REGWATCHES_CONFIG)\""
+ puts $file "FILE_NOTES = \"$::CONFIG(FILE_NOTES)\""
+ puts $file "EIGHT_SEG_EDITOR = \"$::CONFIG(EIGHT_SEG_EDITOR)\""
+ puts $file "BASE_CONVERTORS = \"$::CONFIG(BASE_CONVERTORS)\""
+ puts $file "SPEC_CALC = \"$::CONFIG(SPEC_CALC)\""
+ puts $file "RS232_DEBUGGER = \"$::CONFIG(RS232_DEBUGGER)\""
+ puts $file "\n# other"
+ puts $file "WINDOW_GEOMETRY = \"[wm geometry .]\""
+ puts $file "ACTIVE_PROJECT = $actualProjectIdx"
+ puts $file "INTR_MON_GEOMETRY = \"$::CONFIG(INTR_MON_GEOMETRY)\""
+ puts $file "STACK_MON_GEOMETRY = \"$::CONFIG(STACK_MON_GEOMETRY)\""
+
+ set projects {}
+ if {[winfo exists .mainFrame.mainNB]} {
+ set projects_len [llength [.mainFrame.mainNB pages]]
+ for {set i 0} {$i < $projects_len} {incr i} {
+ set prj [.mainFrame.mainNB pages $i]
+ lappend projects [file join \
+ [$prj cget -projectPath]\
+ [$prj cget -projectFile]\
+ ]
+ }
+ }
+
+ puts $file "OPENED_PROJECTS = ($projects)"
+
+ # Finalize
+ close $file
+ return 1
+ }
+
+ ## Restore previous session
+ # @return Bool - session file found
+ proc restore_session {} {
+ variable session_file ;# Path to file defining the last session
+
+ variable line2pc_jump ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable find_option_CS ;# Bool: Case sensitive
+ variable find_option_back ;# Bool: Search backwards (checkbox)
+ variable find_option_cur ;# Book: Search from cursor
+ variable find_option_sel ;# Bool: Search only in the seleted text
+ variable find_option_reg ;# Bool: Consider search string to be a regular expression
+ variable replace_option_CS ;# Bool: Case sensitive
+ variable replace_option_back ;# Bool: Search backwards (checkbox)
+ variable replace_option_cur ;# Book: Search from cursor
+ variable replace_option_reg ;# Bool: Consider search string to be a regular expression
+
+ variable file_recent_files ;# List: recently opened files
+ variable project_recent_files ;# List: recently opened projects
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ # Set default values
+ array set ::CONFIG {
+ WINDOW_ZOOMED 0
+ LINE_NUMBERS 1
+ ICON_BORDER 1
+ LEFT_PANEL 1
+ RIGHT_PANEL 1
+ BOTTOM_PANEL 1
+ LEFT_PANEL_SIZE 193
+ RIGHT_PANEL_SIZE 329
+ BOTTOM_PANEL_SIZE 190
+ LEFT_PANEL_ACTIVE_PAGE opened_files
+ RIGHT_PANEL_ACTIVE_PAGE Watches
+ BOTTOM_PANEL_ACTIVE_PAGE Simulator
+ WINDOW_GEOMETRY 800x600
+ ACTIVE_PROJECT {}
+ OPENED_PROJECTS {}
+ VALIDATION_LEVEL 2
+ TOOLBAR_VISIBLE 1
+ BREAKPOINTS_ALLOWED 1
+ CLEANUP_OPTIONS {
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0
+ }
+ FIND_OPTIONS {1 0 1 0 0}
+ REPLACE_OPTIONS {1 0 0 0}
+ LETTER_CASE {- - - - - - - - - - - - - - - - - - - - -}
+ KIFSD_CONFIG {}
+ HEXEDIT_CONFIG {+0+0 hex 0 left}
+ INTR_MON_GEOMETRY {780x250}
+ SUBP_MON_CONFIG {1 1}
+ OPEN_WITH_DLG {}
+ FS_BROWSER_MASK {*.asm}
+ FIND_IN_FILES_CONFIG {1 0 1 ~ {*.asm,*.c,*.h} {}}
+ SYMBOL_VIEWER_CONFIG {1 1 1 1 1 1 1 0 0 0 620x450}
+ LINE2PC_JUMP 1
+ STOPWATCH_CONFIG {{} 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
+ C_VARS_VIEW_CONF {400}
+ BITMAP_CONFIG {}
+ HW_MANAGER_CONFIG {}
+ FILE_RECENT_FILES {}
+ PROJECT_RECENT_FILES {}
+ VHW_RECENT_FILES {}
+ REGWATCHES_CONFIG {1 1}
+ FILE_NOTES {1 200}
+ EIGHT_SEG_EDITOR {
+ {0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7}
+ {0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0}
+ }
+ BASE_CONVERTORS {}
+ SPEC_CALC {}
+ ASK_ON_FILE_OPEN 1
+ SHOW_EDITOR_TAB_BAR 1
+ RS232_DEBUGGER {9600 n 8 1 1 0 {} {} 0 0}
+ STACK_MON_GEOMETRY {}
+ STACK_MON_COLLAPSED 1
+ }
+ if {$::MICROSOFT_WINDOWS} {
+ lset ::CONFIG(FIND_IN_FILES_CONFIG) 3 ${::env(USERPROFILE)}
+ }
+ set default_CLEANUP_OPTIONS {
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ 1 1 1 1 1 1 1 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0
+ }
+ set default_FIND_OPTIONS {1 0 1 0 0}
+ set default_REPLACE_OPTIONS {1 0 0 0}
+
+ set session_file_exists [file exists $session_file]
+
+ # Parse session file
+ if {!$::CLI_OPTION(defaults) && $session_file_exists} {
+ # List of keys which may appear in the session file
+ set acceptable_keys {
+ LINE_NUMBERS ICON_BORDER LEFT_PANEL
+ BOTTOM_PANEL LEFT_PANEL_SIZE RIGHT_PANEL_SIZE
+ BOTTOM_PANEL_SIZE LEFT_PANEL_ACTIVE_PAGE RIGHT_PANEL_ACTIVE_PAGE
+ BOTTOM_PANEL_ACTIVE_PAGE WINDOW_GEOMETRY ACTIVE_PROJECT
+ OPENED_PROJECTS RIGHT_PANEL KIFSD_CONFIG
+ VALIDATION_LEVEL TOOLBAR_VISIBLE CLEANUP_OPTIONS
+ BREAKPOINTS_ALLOWED FIND_OPTIONS REPLACE_OPTIONS
+ LETTER_CASE HEXEDIT_CONFIG INTR_MON_GEOMETRY
+ SUBP_MON_CONFIG OPEN_WITH_DLG FS_BROWSER_MASK
+ FIND_IN_FILES_CONFIG SYMBOL_VIEWER_CONFIG LINE2PC_JUMP
+ STOPWATCH_CONFIG C_VARS_VIEW_CONF BITMAP_CONFIG
+ HW_MANAGER_CONFIG FILE_RECENT_FILES PROJECT_RECENT_FILES
+ REGWATCHES_CONFIG EIGHT_SEG_EDITOR VHW_RECENT_FILES
+ BASE_CONVERTORS WINDOW_ZOOMED SPEC_CALC
+ ASK_ON_FILE_OPEN SHOW_EDITOR_TAB_BAR RS232_DEBUGGER
+ FILE_NOTES STACK_MON_GEOMETRY STACK_MON_COLLAPSED
+ }
+ # List of datatypes for these keys
+ set datatypes {
+ B B B
+ B I I
+ I S S
+ S G S
+ S B S
+ I B S
+ B S S
+ S S G
+ S S S
+ S S B
+ S S S
+ S S S
+ S S S
+ S B S
+ B B S
+ S S B
+ }
+
+ # Open session file
+ set file [open $session_file r]
+ while 1 {
+ # Break on EOF
+ if {[eof $file]} {
+ close $file
+ break
+ }
+
+ # Get and adjust line
+ set line [gets $file]
+ regsub {\s*#.*$} $line {} line
+ if {$line == {}} {continue}
+
+ # Determinate key and value
+ regexp {^\w+} $line key
+ regexp {\=.*$} $line value
+ set value [string replace $value 0 0]
+ set key [string trim $key]
+ set value [string trim $value "\" \t"]
+
+ # Check for valid key
+ set keyIndex [lsearch -exact -ascii $acceptable_keys $key]
+ if {$keyIndex == -1} {
+ puts stderr "Unrecognized key: '$key'"
+ continue
+ }
+ # Check for valid datatype
+ set dt [lindex $datatypes $keyIndex]
+ switch -- $dt {
+ B { ;# Boolean
+ if {![string is boolean -strict $value]} {
+ puts stderr "Invalid value '$value', expected boolean"
+ continue
+ }
+ }
+ I { ;# unsigned Integer
+ if {![string is integer -strict $value]} {
+ puts stderr "Invalid value '$value', expected integer"
+ continue
+ }
+ }
+ S { ;# String
+ }
+ G { ;# window Geometry
+ if {![regexp {=?\d+x\d+(\+\d+\+\d+)?} $value]} {
+ puts stderr "Invalid value '$value', expected win. geometry (key == $key)"
+ continue
+ }
+ }
+ }
+
+ # Parse key "OPENED_PROJECTS"
+ if {$key == {OPENED_PROJECTS}} {
+ set value [string trim $value {( )}]
+ }
+
+ # Set appropriate value of config array
+ set ::CONFIG($key) $value
+ }
+ }
+
+ # Validate some configuration values
+ if {![regexp {^\s*([01]\s+){45}[01]\s*$} $::CONFIG(CLEANUP_OPTIONS)]} {
+ puts stderr "Invalid record CLEANUP_OPTIONS -- setting to default value"
+ set ::CONFIG(CLEANUP_OPTIONS) $default_CLEANUP_OPTIONS
+ }
+ if {![regexp {^\s*[01]\s[01]\s[01]\s[01]\s[01]\s*$} $::CONFIG(FIND_OPTIONS)]} {
+ puts stderr "Invalid record FIND_OPTIONS -- setting to default value"
+ set ::CONFIG(FIND_OPTIONS) $default_FIND_OPTIONS
+ }
+ if {![regexp {^\s*[01]\s[01]\s[01]\s[01]\s*$} $::CONFIG(REPLACE_OPTIONS)]} {
+ puts stderr "Invalid record REPLACE_OPTIONS -- setting to default value"
+ set ::CONFIG(REPLACE_OPTIONS) $default_REPLACE_OPTIONS
+ }
+ if {![regexp {^\s*[01]\s+[01]\s*$} $::CONFIG(REGWATCHES_CONFIG)]} {
+ puts stderr "Invalid record REGWATCHES_CONFIG -- setting to default value"
+ set ::CONFIG(REGWATCHES_CONFIG) {1 1}
+ }
+
+ # Adjust some configuration values
+ set line2pc_jump $::CONFIG(LINE2PC_JUMP)
+
+ set find_option_CS [lindex $::CONFIG(FIND_OPTIONS) 0]
+ set find_option_back [lindex $::CONFIG(FIND_OPTIONS) 1]
+ set find_option_cur [lindex $::CONFIG(FIND_OPTIONS) 2]
+ set find_option_sel [lindex $::CONFIG(FIND_OPTIONS) 3]
+ set find_option_reg [lindex $::CONFIG(FIND_OPTIONS) 4]
+
+ set replace_option_CS [lindex $::CONFIG(REPLACE_OPTIONS) 0]
+ set replace_option_back [lindex $::CONFIG(REPLACE_OPTIONS) 1]
+ set replace_option_cur [lindex $::CONFIG(REPLACE_OPTIONS) 2]
+ set replace_option_reg [lindex $::CONFIG(REPLACE_OPTIONS) 3]
+
+ set file_recent_files $::CONFIG(FILE_RECENT_FILES)
+ set project_recent_files $::CONFIG(PROJECT_RECENT_FILES)
+ set vhw_recent_files $::CONFIG(VHW_RECENT_FILES)
+
+ for {set i 0} {$i < 21} {incr i} {
+ set val [lindex $::CONFIG(LETTER_CASE) $i]
+ if {$val != {U} && $val != {L} && $val != {-}} {
+ set val {-}
+ }
+ set change_letter_case_options($i) $val
+ }
+
+ if {!$::CLI_OPTION(defaults)} {
+ if {$::CLI_OPTION(ignore_last)} {
+ set ::CONFIG(OPENED_PROJECTS) {}
+ }
+ if {$::CLI_OPTION(open_project) != {}} {
+ set ::CONFIG(OPENED_PROJECTS) [list $::CLI_OPTION(open_project)]
+ }
+ }
+
+ # Return result
+ return $session_file_exists
+ }
+
+ ## Invoke dialog "Exit program"
+ # @return Int - result
+ # '0' == Save selected
+ # '1' == Save all
+ # '2' == Discard
+ # '3' == Cancel
+ proc shutdown_dialog {} {
+ variable unsaved_projects ;# List: List of project object marked as "unsaved"
+
+ catch {unset ::exit_dialog_result}
+
+ # Create dialog window
+ set dialog [toplevel .save_multiple_projects -class {Save multimple} -bg {#EEEEEE}]
+
+ # Create the top part of dialog (Header and some icon)
+ pack [frame $dialog.topframe] -fill x -expand 1
+ pack [label $dialog.topframe.image \
+ -image ::ICONS::32::fileclose \
+ ] -side left -padx 10
+ pack [label $dialog.topframe.message \
+ -text [mc "The following documents have been modified,\ndo you want to save them before closing ?"] \
+ ] -side right -fill x -expand 1
+
+ # Create the middle part of the dialog (list of unsaved files)
+ pack [ttk::labelframe $dialog.lf -text [mc "Unsaved files"] -labelanchor nw -padding 5] -fill both -expand 1 -pady 10 -padx 10
+ set last_project {}
+ set i 0
+ foreach unsaved $unsaved_projects {
+ # Project name
+ if {[lindex $unsaved 0] != $last_project} {
+ set last_project [lindex $unsaved 0]
+ pack [label $dialog.lf.chp$i \
+ -text [mc "Project: \"%s\"" [$last_project cget -projectName]] \
+ -image ::ICONS::16::kcmdevices \
+ -compound left \
+ ] -anchor w -padx 20 -pady 5
+ }
+ # Unsaved files
+ set ::unsavedfile$i 1
+ pack [checkbutton $dialog.lf.chb$i \
+ -text [[lindex $unsaved 1] cget -filename] \
+ -variable ::unsavedfile$i \
+ ] -anchor w -padx 60
+ incr i
+ }
+
+ # Create the bottom part of the dialog (buttons)
+ pack [ttk::separator $dialog.separator -orient horizontal] -fill x -expand 1 -padx 10
+ pack [frame $dialog.f] -pady 5 -padx 5
+ # button SAVESELECTED
+ pack [ttk::button $dialog.f.b_save_selected \
+ -text [mc "Save selected"] \
+ -underline 0 \
+ -compound left \
+ -image ::ICONS::16::filesave \
+ -command {set ::exit_dialog_result 0} \
+ ] -side left -padx 5
+ bind $dialog.f.b_save_selected <Return> {set ::exit_dialog_result 0}
+ bind $dialog.f.b_save_selected <KP_Enter> {set ::exit_dialog_result 0}
+ # button SAVEALL
+ pack [ttk::button $dialog.f.b_save_all \
+ -text [mc "Save all"] \
+ -underline 5 \
+ -compound left \
+ -image ::ICONS::16::save_all \
+ -command {set ::exit_dialog_result 1} \
+ ] -side left -padx 5
+ bind $dialog.f.b_save_all <Return> {set ::exit_dialog_result 1}
+ bind $dialog.f.b_save_all <KP_Enter> {set ::exit_dialog_result 1}
+ # button DESTROY
+ pack [ttk::button $dialog.f.b_discard \
+ -text [mc "Discard"] \
+ -underline 0 \
+ -compound left \
+ -image ::ICONS::16::editdelete \
+ -command {set ::exit_dialog_result 2} \
+ ] -side left -padx 5
+ bind $dialog.f.b_discard <Return> {set ::exit_dialog_result 2}
+ bind $dialog.f.b_discard <KP_Enter> {set ::exit_dialog_result 2}
+ # button CANCEL
+ pack [ttk::button $dialog.f.b_cancel \
+ -text [mc "Cancel"] \
+ -underline 0 \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {set ::exit_dialog_result 3} \
+ ] -side left -padx 5
+ bind $dialog.f.b_cancel <Return> {set ::exit_dialog_result 3}
+ bind $dialog.f.b_cancel <KP_Enter> {set ::exit_dialog_result 3}
+
+ # Set key-events bindings
+ bind $dialog <Alt-Key-s> {set ::exit_dialog_result 0}
+ bind $dialog <Alt-Key-a> {set ::exit_dialog_result 1}
+ bind $dialog <Alt-Key-d> {set ::exit_dialog_result 2}
+ bind $dialog <Alt-Key-c> {set ::exit_dialog_result 3}
+
+ # Window manager options -- modal window
+ wm iconphoto $dialog ::ICONS::16::exit
+ wm title $dialog [mc "Exit program - MCU 8051 IDE"]
+ wm state $dialog normal
+ wm minsize $dialog 350 200
+ grab $dialog
+ focus -force $dialog.f.b_save_all
+ wm transient $dialog .
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ set ::exit_dialog_result 3
+ "
+ vwait ::exit_dialog_result
+ grab release $dialog
+ destroy $dialog
+ return ${::exit_dialog_result}
+ }
+
+ ## Simulator: STEPBACK
+ # @return void
+ proc __stepback {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator is engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check if simulator isn't busy
+ if {[$actualProject sim_is_busy]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Perform program step
+ stepback_button_set_ena [$actualProject stepback]
+ set lineNum [$actualProject simulator_getCurrentLine]
+ if {$lineNum != {}} {
+ $actualProject move_simulator_line $lineNum
+ } {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ }
+ $actualProject Simulator_sync_PC_etc
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Simulator: STEP
+ # @return void
+ proc __step {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator is engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check if simulator isn't busy
+ if {[$actualProject sim_is_busy]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Perform program step
+ set lineNum [$actualProject step]
+ if {$lineNum != {}} {
+ $actualProject move_simulator_line $lineNum
+ } {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ }
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ $actualProject Simulator_sync_PC_etc
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Simulator: STEPOVER
+ # @return void
+ proc __stepover {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator is engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+ # Check if simulator isn't busy
+ if {[$actualProject sim_run_in_progress] || [$actualProject sim_anim_in_progress]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+
+
+ # Change button image (simulator control panel)
+ $actualProject invert_stepover_button
+
+ # Perform program step
+ set lineNum [$actualProject sim_stepover]
+ if {$lineNum != {}} {
+ $actualProject move_simulator_line $lineNum
+ } {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ }
+
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ $actualProject invert_stepover_button ;# Change button image (simulator control panel)
+ $actualProject Simulator_sync_PC_etc ;# Synchronize PC and Time
+ }
+
+ ## Simulator: ANIMATE
+ # @return void
+ proc __animate {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator is engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check if simulator isn't busy
+ if {[$actualProject sim_run_in_progress] || [$actualProject sim_stepover_in_progress]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ $actualProject invert_animate_button ;# Change button image (simulator control panel)
+ $actualProject sim_animate ;# Start simulator in mode "animate"
+ $actualProject invert_animate_button ;# Change button image (simulator control panel)
+ }
+
+ ## Simulator: RUN
+ # @return void
+ proc __run {} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if simulator isn't already engaged
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check if simulator isn't busy
+ if {[$actualProject sim_anim_in_progress] || [$actualProject sim_stepover_in_progress]} {
+ Sbar [mc "Simulator is busy"]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Change button image (simulator control panel)
+ $actualProject invert_run_button
+ ## Start simulator
+ # Remove simulator cursor from editor
+ $actualProject editor_procedure {} unset_simulator_line {}
+ # Engage mode "run"
+ set line_num [$actualProject sim_run]
+ if {$line_num != {}} {
+ $actualProject move_simulator_line $line_num
+ } {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ }
+ # Adjust simulator control panel
+ $actualProject invert_run_button
+ stepback_button_set_ena [$actualProject simulator_get_SBS_len]
+ # Synchronize
+ $actualProject Simulator_sync ;# Simulator GUI (registers)
+ $actualProject Simulator_sync_clock ;# Simulator GUI (time)
+ $actualProject Simulator_sync_PC_etc ;# Simulator GUI (PC, Watchdog, etc.)
+ refresh_xram_mem_window $actualProject ;# XDATA memory hexadecimal editor
+ refresh_eram_mem_window $actualProject ;# EDATA memory hexadecimal editor
+ refresh_eeprom_mem_window $actualProject ;# Data EEPROM hexadecimal editor
+ }
+
+ ## Simulator: RESET
+ # @parm Char arg - reset mode
+ # '-' == no change (IRAM and XRAM)
+ # '0' == all zeroes (IRAM and XRAM)
+ # '1' == all ones (IRAM and XRAM)
+ # 'r' == random values (IRAM and XRAM)
+ # @return void
+ proc __reset {arg} {
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical + simulator must be on
+ if {$critical_procedure_in_progress} {return}
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ Sbar [mc "Simulator is not started"]
+ return
+ }
+ set critical_procedure_in_progress 1
+
+ # Clear program time
+ $actualProject simulator_clear_overall_time
+ # Clear graph
+ $actualProject clear_graph
+ # Perform reset
+ $actualProject Simulator_reset $arg
+ $actualProject simulator_setWatchDogTimer 0
+ # Move simulator cursor in editor to the begining of the program
+ foreach editor [$actualProject cget -editors] {
+ $editor unset_simulator_line
+ }
+ $actualProject move_simulator_line [$actualProject simulator_getCurrentLine]
+
+ # Synchronize with Hex editor and Register watches on right panel
+ if {$arg != {-}} {
+ refresh_xram_mem_window $actualProject
+ refresh_eram_mem_window $actualProject
+ refresh_eeprom_mem_window $actualProject
+ $actualProject rightPanel_watch_sync_all
+ }
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Start/Shutdown simulator
+ # @parm Bool = 0 - Load debug file for the current file only (not the main file)
+ # @return void
+ proc __initiate_sim args {
+ variable actualProject ;# Object: Current project
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ if {[lindex $args 0] == 1} {
+ set current_file_only 1
+ } {
+ set current_file_only 0
+ }
+
+ # Clear program timer
+ $actualProject simulator_clear_overall_time
+
+ # Shutdown simulator
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ lset simulator_enabled $actualProjectIdx 0 ;# Simlulator disabled (set flag)
+ $actualProject Simulator_shutdown ;# Shutdown simulator engine
+ $actualProject sim_disable ;# Disable widgets of simulator GUI
+ $actualProject sfr_watches_disable ;# Disable SFR watches
+ $actualProject rightPanel_watch_disable ;# Disable widgets of register watches
+ $actualProject sfrmap_setEnabled 0 ;# Disable SFR map
+ $actualProject bitmap_setEnabled 0 ;# Disable map of bit area
+ $actualProject thaw ;# Unlock menus in file lists
+ line2pc_safely_close ;# Safely Close dialog "Line to address"
+ $actualProject subprograms_setEnabled 0 ;# Disable list of subprograms
+ $actualProject cvarsview_setEnabled 0 ;# Disable C vars view
+ $actualProject stack_monitor_set_enabled 0 ;# Disable stack monitor
+ update
+ Lock_simulator_menu ;# Lock simulator menu and toolbar
+ $actualProject interrupt_monitor_disable_buttons;# Disable interrupt monitor
+
+ # Remove simulator pointers
+ foreach editor [$actualProject cget -editors] {
+ $editor unset_simulator_line
+ }
+
+ # Inform code memory hexadecimal editor about that
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $actualProject {:}]]
+ if {$idx != -1} {
+ [lindex $code_mem_window_objects $idx] simulator_stared_stopped 0
+ }
+
+ # Start simulator
+ } else {
+ # Get ID of currently active page on bottom notebook
+ set bottom_page_ID [$actualProject getBottomPanelActivePage]
+
+ # Determinate name of simulator data file
+ set full_file_name [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ set relative_name [lindex $full_file_name 1]
+ if {$current_file_only || $relative_name == {}} {
+ set full_file_name [$actualProject editor_procedure {} getFileName {}]
+ set language [$actualProject editor_procedure {} get_language {}]
+ set relative_name [lindex $full_file_name 1]
+ } {
+ set ext [string trimleft [file extension $relative_name] {.}]
+ if {$ext == {c} || $ext == {h} || $ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set language 1
+ } elseif {$ext == {lst}} {
+ set language 2
+ } else {
+ set language 0
+ }
+ }
+ set full_file_name [file join [lindex $full_file_name 0] [lindex $full_file_name 1]]
+ set full_file_name [file rootname $full_file_name]
+ if {$language == 1} {
+ append full_file_name {.cdb}
+ } {
+ append full_file_name {.adf}
+ }
+
+ # Try to open the file and determinate expected MD5 hash
+ if {![catch {
+ # C language
+ if {$language == 1} {
+ set hashes_file [open "[file rootname $full_file_name].hashes" {r}]
+ set expected_md5s [read $hashes_file]
+ close $hashes_file
+
+ # Assembly language
+ } elseif {$language == 0} {
+ set expected_md5s {}
+ set simulator_file [open $full_file_name r]
+ while {![eof $simulator_file]} {
+ set line [gets $simulator_file]
+ if {$line == {} || [regexp {^\s*#} $line]} {
+ continue
+ }
+ set expected_md5s $line
+ break
+ }
+ close $simulator_file
+
+ # Invalid request!
+ } else {
+ error "Invalid request!"
+ }
+
+ }]} then {
+ # MD5 hash verification failed -> ask for recompilation
+ if {($language == 0 || $language == 1) && [verify_md5_hashes 1 $expected_md5s]} {
+ # Ask for recompilation
+ set response [
+ tk_messageBox \
+ -icon question \
+ -type yesno \
+ -default {yes} \
+ -title [mc "Recompile ?"] \
+ -message [mc "MD5 hashes verification failed. That probably means than some source files have been modified since last compilation.\n\nDo you want to recompile the code ?"] \
+ ]
+ if {$response != {yes}} {
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ ## Compile the source code
+ set compilation_result [__compile 1 1]
+ # (0) Compilation failed
+ if {!$compilation_result} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [mc "Compilation failed"] \
+ -message [mc "Compilation failed, see messages for details."]
+ set critical_procedure_in_progress 0
+ return
+ # (2) External compiler used
+ } elseif {$compilation_result == 2} {
+ return
+ }
+ }
+ # Unable to open the simulator data file -> ask for recompilation
+ } else {
+ # Ask for recompilation
+ set response [
+ tk_messageBox \
+ -icon question \
+ -type yesno \
+ -title [mc "File not found"] \
+ -message [mc "Simulator data file not found.\nDo you want create it ?"]
+ ]
+ if {$response == {no}} {
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ ## Compile the source code
+ set compilation_result [__compile 1 1]
+ # (0) Compilation failed
+ if {!$compilation_result} {
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [mc "Compilation failed"] \
+ -message [mc "Compilation failed, see messages for details."]
+ set critical_procedure_in_progress 0
+ return
+ # (2) External compiler used
+ } elseif {$compilation_result == 2} {
+ return
+ }
+
+ set full_file_name [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ if {[lindex $full_file_name 1] == {}} {
+ set full_file_name [$actualProject editor_procedure {} getFileName {}]
+ }
+ set full_file_name [file join [lindex $full_file_name 0] [lindex $full_file_name 1]]
+ regsub {\.[^\.]*$} $full_file_name {} full_file_name
+ append full_file_name {.adf}
+ }
+
+ # Open simulator data file
+ if {[catch {
+ set simulator_file [open $full_file_name r]
+ }]} then {
+ tk_messageBox \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to start simulator"] \
+ -message [mc "Unable to read simulator file. Possibly you have disabled generation of simulator file in compiler configuration dialog."]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Try to load IHX file if C language is used
+ if {$language == 1} {
+ if {[catch {
+ set hex_file [open "[file rootname $full_file_name].ihx" r]
+ } result]} then {
+ puts stderr $result
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to find hex file"] \
+ -message [mc "Unable to open:\n'%s'" "[file rootname $full_file_name].ihx"]
+ return
+ }
+ }
+
+ $actualProject freeze ;# Switch filelist to "Simulator mode"
+ update
+
+ # Raise tab "Simulator" on the bottom panel
+ if {[lsearch {Graph Simulator CVarsView} $bottom_page_ID] == -1} {
+ $actualProject bottomNB_show_up {Simulator}
+ } {
+ $actualProject bottomNB_show_up $bottom_page_ID
+ }
+
+ ## Engage simulator
+ lset simulator_enabled $actualProjectIdx 1 ;# Set simulator enabled flag to True
+ $actualProject sim_enable ;# Enable simulator GUI
+ $actualProject sfr_watches_enable ;# Enable SFR watches
+ $actualProject sfrmap_setEnabled 1 ;# Enable SFR map
+ $actualProject bitmap_setEnabled 1 ;# Enable map of bit area
+
+ # Load program into simulator engine
+ if {$language == 1} {
+ if {[$actualProject load_program_from_cdb \
+ [file rootname $full_file_name].c \
+ $simulator_file $hex_file \
+ ]} {
+ seek $simulator_file 0
+ $actualProject cvarsview_load_cdb $simulator_file
+ }
+ close $hex_file
+ } {
+ $actualProject load_program_from_adf $simulator_file
+ }
+
+ # Autoload list of defined symbolic name into register watches
+ $actualProject rightPanel_watch_autoload [file rootname $full_file_name].lst
+
+ # Some more initialization
+ close $simulator_file ;# Close simulator data file
+ $actualProject clear_graph ;# Clear graph
+ $actualProject Simulator_sync ;# Synchronize simulator (due to reset)
+ $actualProject rightPanel_watch_enable ;# Enable entry widgets in register watches
+ $actualProject subprograms_setEnabled 1 ;# Enable list of subprograms
+ $actualProject cvarsview_setEnabled 1 ;# Enable C vars view
+ $actualProject stack_monitor_set_enabled 1 ;# Enable stack monitor
+ $actualProject Simulator_initiate ;# Initialize simulator engine
+ $actualProject interrupt_monitor_enable_buttons ;# Enable interrupt monitor
+ __sim_clear_highlight ;# Clear all highlights
+
+ # Reset virtual MCU
+ set critical_procedure_in_progress 0
+ __reset -
+ set critical_procedure_in_progress 1
+
+ # Load breakpoints into simulator engine
+ set found 0
+ set editor {}
+ set editors [$actualProject cget -editors]
+ foreach filename [$actualProject simulator_get_list_of_filenames] {
+ set found 0
+ foreach editor $editors {
+ if {$filename == [$editor cget -fullFileName]} {
+ set found 1
+ break
+ }
+ }
+ if {$found} {
+ $actualProject Simulator_import_breakpoints \
+ $filename [$editor getBreakpoints]
+ } {
+ $actualProject Simulator_import_breakpoints $filename {}
+ }
+ }
+
+ $actualProject now_frozen
+
+ # Set simulator cursor in editor to the first OP code
+ $actualProject move_simulator_line [$actualProject simulator_getCurrentLine]
+ refresh_code_mem_window $actualProject ;# Synchronize CODE memory hex editor
+ update
+ Unlock_simulator_menu ;# Unlock simulator menu and toolbar
+ stepback_button_set_ena 0 ;# Disable StepBack controls
+
+ # Inform code memory hexadecimal editor about that
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $actualProject {:}]]
+ if {$idx != -1} {
+ [lindex $code_mem_window_objects $idx] simulator_stared_stopped 1
+ }
+ }
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Verify MD5 hashes for the given files (only for current project)
+ # @parm Bool save_files - Save modified files mentioned in the given list
+ # @parm List hashes - {hash filename hash filename ...}
+ # @return Int - Final result
+ # 0 == All correct
+ # 1 == Verification failed
+ # 2 == File access error
+ proc verify_md5_hashes {save_files hashes} {
+ variable actualProject ;# Object: Current project
+
+ # Local variables
+ set len [llength $hashes] ;# Length of the given list of hashes and files
+ set filenames {} ;# List of filenames only
+ set md5_hashes {} ;# List of md5 hashes only
+
+ set dir [$actualProject cget -projectPath]
+
+ # Separate filenames and hashes
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ lappend filenames [file join $dir [lindex $hashes $j]]
+ lappend md5_hashes [lindex $hashes $i]
+ }
+ set len [expr {int($len/2)}]
+
+ # Save mentioned files
+ if {$save_files} {
+ set idx 0
+ set e_filenames {}
+ set editors [$actualProject cget -editors]
+
+ # Determinate list of opened files
+ foreach editor $editors {
+ set filename [$editor cget -fullFileName]
+ if {$filename == {}} {
+ continue
+ }
+
+ lappend e_filenames $filename
+ }
+
+ # Save files
+ for {set i 0} {$i < $len} {incr i} {
+ set idx [lsearch $e_filenames [lindex $filenames $i]]
+
+ if {$idx == -1} {continue}
+
+ if {[[lindex $editors $idx] cget -modified]} {
+ [lindex $editors $idx] save
+ }
+ }
+ }
+
+ # Check MD5s
+ for {set i 0} {$i < $len} {incr i} {
+ set recorded_md5 [lindex $md5_hashes $i]
+ if {[catch {
+ set computed_md5 [::md5::md5 -hex -file [lindex $filenames $i]]
+ }]} {
+ return 2
+ }
+ if {$recorded_md5 != $computed_md5} {
+ return 1
+ }
+ }
+
+ return 0
+ }
+
+ ## Invoke file selection dialog to normalize IHEX8 file
+ # @return void
+ proc __normalize_hex {} {
+ variable input_file ;# Input file
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ if {$critical_procedure_in_progress} {return}
+
+ # Invoke dialog to select input file
+ set input_file {}
+ select_input_output 1 {hex} .
+ if {$input_file == {}} {return}
+
+ # File name is not valid -> invoke error message
+ if {
+ $input_file == {} ||
+ ![file exists $input_file] ||
+ ![file isfile $input_file] ||
+ (!$::MICROSOFT_WINDOWS && ![file writable $input_file]) ||
+ (!$::MICROSOFT_WINDOWS && ![file readable $input_file])
+ } {
+ tk_messageBox \
+ -parent . -icon warning \
+ -title [mc "Error - MCU 8051 IDE"] \
+ -message [mc "Unable to gain unlimited access to the given file"]
+ # File name is valid -> normalize its content
+ } else {
+ # Progress dialog
+ create_progress_bar .prgDl \
+ . \
+ {} \
+ "Parsing file: $input_file" \
+ ::IHexTools::progress \
+ 1 \
+ [mc "Parsing file ..."] \
+ ::ICONS::16::bottom1 \
+ [mc "Abort"] \
+ {set ::IHexTools::abort 1}
+
+ # Read file
+ set file [open $input_file r]
+ set data [read $file]
+ close $file
+
+ # Normalize content
+ set ::IHexTools::update 1
+ catch {.prgDl.f.progressbar configure -maximum [::IHexTools::get_number_of_iterations $data]}
+ ::IHexTools::load_hex_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ catch {.prgDl.f.progressbar configure -maximum 16}
+ set data [::IHexTools::get_hex_data]
+ }
+
+ # Destroy progress dialog
+ catch {destroy .prgDl}
+
+ # No errors occured -> rewrite file
+ if {!${::IHexTools::error_count}} {
+ if {[catch {
+ set file [open $input_file w 420]
+ }]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -parent . \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to open file:\n\"%s\"\nfor writing" $input_file]
+ return
+ } else {
+ puts -nonewline $file $data
+ close $file
+ }
+ # Errors occured -> Invoke error message dialog
+ } else {
+ # Create dialog window
+ set dialog [toplevel .error_message_dialog -class {Error dialog} -bg {#EEEEEE}]
+
+ # Create main frame (text widget and scrolbar)
+ set main_frame [frame $dialog.main_frame]
+
+ # Create text widget
+ set text [text $main_frame.text \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ -width 0 -height 0 \
+ ]
+ pack $text -side left -fill both -expand 1
+ # Create scrollbar
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$text yview" \
+ ] -side right -fill y
+
+ # Pack main frame and create button "Close"
+ pack $main_frame -fill both -expand 1
+ pack [ttk::button $dialog.ok_button \
+ -text [mc "Close"] \
+ -command "grab release $dialog; destroy $dialog" \
+ ]
+
+ # Show error string and disable the text widget
+ $text insert end ${::IHexTools::error_string}
+ $text configure -state disabled
+
+ # Set window attributes
+ wm iconphoto $dialog ::ICONS::16::status_unknown
+ wm title $dialog [mc "Error(s) occured while parsing IHEX file - %s" ${::APPNAME}]
+ wm minsize $dialog 500 250
+ wm protocol $dialog WM_DELETE_WINDOW [mc "grab release %s; destroy %s" $dialog $dialog]
+ wm transient $dialog .
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ # Free resources reserved during normalization
+ ::IHexTools::free_resources
+ }
+ }
+
+ ## Invkoke dialog for converting Binary files to Intel® HEX 8 files
+ # @return void
+ proc __bin2hex {} {
+ variable hex__bin ;# Type of conversion
+
+ set hex__bin 0
+ hex2bin2hex
+ }
+
+ ## Invkoke dialog for converting Intel® HEX 8 files to Binary files
+ # @return void
+ proc __hex2bin {} {
+ variable hex__bin ;# Type of conversion
+ set hex__bin 1
+ hex2bin2hex
+ }
+
+ ## Invkoke dialog for converting Simulator data files to Intel® HEX 8 files
+ # @return void
+ proc __sim2hex {} {
+ variable hex__bin ;# Type of conversion
+ set hex__bin 2
+ hex2bin2hex
+ }
+
+ ## Invkoke dialog for converting Simulator data files to Binary files
+ # @return void
+ proc __sim2bin {} {
+ variable hex__bin ;# Type of conversion
+ set hex__bin 3
+ hex2bin2hex
+ }
+
+ ## Invoke conversion dialog -- auxiliary procedure for '__bin2hex', '__hex2bin', '__sim2hex', '__sim2bin'
+ # @return void
+ proc hex2bin2hex {} {
+ variable hex__bin ;# Type of conversion
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ if {$critical_procedure_in_progress} {return}
+
+ # Create dialog window
+ set win [toplevel .hex2bin2hex_dialog -class {Conversion} -bg {#EEEEEE}]
+ set mainframe [frame $win.frame]
+
+ # Label, Entry and Button "Input file"
+ grid [Label $mainframe.lbl_input \
+ -text [mc "Input file"] \
+ -helptext {File to convert} \
+ ] -column 1 -row 1 -sticky w
+ grid [ttk::entry $mainframe.entry_input \
+ -textvariable X::input_file \
+ -width 50 \
+ ] -column 2 -row 1 -sticky we
+ DynamicHelp::add $mainframe.entry_input -text [mc "File to convert"]
+ grid [ttk::button $mainframe.button_select_input_file \
+ -image ::ICONS::16::fileopen \
+ -takefocus 0 \
+ -style Flat.TButton \
+ -command {
+ # Determinate file suffix
+ if {${::X::hex__bin} == 0} {
+ set mask {bin}
+ } elseif {${::X::hex__bin} == 1} {
+ set mask {{hex,ihx}}
+ } else {
+ set mask {adf}
+ }
+ # Invoke file selection dialog
+ X::select_input_output 1 $mask .hex2bin2hex_dialog
+ } \
+ ] -column 3 -row 1 -sticky e
+ DynamicHelp::add $mainframe.button_select_input_file \
+ -text [mc "Invoke dialog to select input file"]
+
+ # Label, Entry and Button "Output file"
+ grid [Label $mainframe.lbl_output \
+ -text [mc "Output file"] \
+ -helptext [mc "File where to save result"] \
+ ] -column 1 -row 2 -sticky w
+ grid [ttk::entry $mainframe.entry_output \
+ -textvariable X::output_file \
+ -width 50 \
+ ] -column 2 -row 2 -sticky we
+ DynamicHelp::add $mainframe.entry_output \
+ -text [mc "File where to save result"]
+ grid [ttk::button $mainframe.button_select_output_file \
+ -image ::ICONS::16::fileopen \
+ -style Flat.TButton \
+ -command {
+ # Determinate file suffix
+ if {${::X::hex__bin} == 0} {
+ set mask {{hex,ihx}}
+ } elseif {${::X::hex__bin} == 1} {
+ set mask {bin}
+ } elseif {${::X::hex__bin} == 2} {
+ set mask {{hex,ihx}}
+ } elseif {${::X::hex__bin} == 3} {
+ set mask {bin}
+ }
+ # Invoke file selection dialog
+ X::select_input_output 0 $mask .hex2bin2hex_dialog
+ } \
+ ] -column 3 -row 2 -sticky e
+ DynamicHelp::add $mainframe.button_select_output_file \
+ -text [mc "Invoke dialog to select output file"]
+
+ # Create separator
+ grid [ttk::separator $mainframe.separator \
+ -orient horizontal \
+ ] -column 1 -columnspan 3 -row 3 -sticky we -pady 10
+
+ # Create buttons "Ok" and "Cancel"
+ set button_frame [frame $mainframe.button_frame]
+ pack [ttk::button $button_frame.button_ok \
+ -text [mc "Ok"] \
+ -command {X::hex2bin2hex_OK} \
+ -compound left \
+ -image ::ICONS::16::ok \
+ ] -side left -padx 5
+ pack [ttk::button $button_frame.button_cancel \
+ -text [mc "Cancel"] \
+ -command {X::hex2bin2hex_CANCEL} \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ ] -side left -padx 5
+ grid $button_frame -column 1 -columnspan 3 -row 4
+
+ # Set window title
+ if {$hex__bin == 0} {
+ wm title $win [mc "Convert Binary file to Intel HEX 8 - MCU 8051 IDE"]
+ } elseif {$hex__bin == 1} {
+ wm title $win [mc "Convert Intel HEX 8 to binary file - MCU 8051 IDE"]
+ } elseif {$hex__bin == 2} {
+ wm title $win [mc "Convert sim file to Intel HEX 8 - MCU 8051 IDE"]
+ }
+
+ pack $mainframe -fill both -expand 1 -padx 5 -pady 5
+
+ # Event bindings (Enter == Ok; Escape == Cancel)
+ bind $win <KeyRelease-Return> {X::hex2bin2hex_OK; break}
+ bind $win <KeyRelease-KP_Enter> {X::hex2bin2hex_OK; break}
+ bind $win <KeyRelease-Escape> {X::hex2bin2hex_CANCEL; break}
+
+ # Set window attributes -- modal window
+ wm iconphoto $win ::ICONS::16::bottom1
+ wm minsize $win 450 100
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW {
+ X::hex2bin2hex_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Increment compilation progress variable and call update command
+ # @return void
+ proc update_progress {} {
+ variable compilation_progress ;# Variable for compilation progressbar
+
+ incr compilation_progress
+ update
+ }
+
+ ## Set maximum for progressbar in file conversion dialog
+ # -- internal auxiliary procedure for 'hex2bin2hex_OK'
+ # @parm Int max - value to set
+ # @return void
+ proc hex2bin2hex_set_progress_max {max} {
+ .hex2bin2hex_dialog.button_frame.progress_bar configure -maximum $max
+ }
+
+ ## Perform file conversion -- auxiliary procedure for 'hex2bin2hex'
+ # @return void
+ proc hex2bin2hex_OK {} {
+ variable input_file ;# Input file
+ variable output_file ;# Output file
+ variable hex__bin ;# Type of conversion
+
+ # Check if input and output file names are not empty strings
+ if {$input_file == {} || $output_file == {}} {
+ tk_messageBox \
+ -parent .hex2bin2hex_dialog \
+ -icon warning -type ok \
+ -title "MCU 8051 IDE" \
+ -message [mc "Both entries must be filled"]
+ return
+ }
+
+ # Normalize name of input file
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $input_file]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$input_file"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $input_file]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $input_file]
+ }
+ }
+ set input_file [file normalize $input_file]
+
+ # Normalize name of output file
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $output_file]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$output_file"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $output_file]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $output_file]
+ }
+ }
+ set output_file [file normalize $output_file]
+
+ set win .hex2bin2hex_dialog
+
+ # Diable entry widgets in file selection dialog
+ foreach wdg [subst {
+ $win.frame.entry_input
+ $win.frame.entry_output
+ $win.frame.button_select_input_file
+ $win.frame.button_select_output_file
+ }] {
+ $wdg configure -state disabled
+ }
+
+ # Destroy buttons "Ok" and "Cancel"
+ destroy $win.frame.button_frame.button_ok
+ destroy $win.frame.button_frame.button_cancel
+
+ # Change window size
+ wm minsize $win 450 170
+
+ # Create staus label, progressbar and Abort button
+ set status_label [label $win.frame.button_frame.status_label -justify left]
+ set progressbar [ttk::progressbar \
+ $win.frame.button_frame.progress_bar \
+ -variable ::IHexTools::progress \
+ -mode determinate \
+ -length 440 \
+ ]
+ pack $status_label -anchor w -padx 10
+ pack $progressbar -pady 15
+ pack [ttk::button $win.frame.button_frame.button_ok \
+ -text [mc "Abort"] \
+ -image ::ICONS::16::cancel \
+ -compound left \
+ -command {X::hex2bin2hex_ABORT} \
+ ] -pady 5
+
+ # Create backup copy for output file
+ if {[file exists $output_file] && [file isfile $output_file]} {
+ if {![file writable $output_file]} {
+ tk_messageBox \
+ -type ok -icon error -parent $win \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to access file: %s" $output_file]
+ hex2bin2hex_CANCEL
+ return
+ }
+ # Ask user for overwrite existing file
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent $win \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $output_file]]
+ ] != {yes}
+ } {
+ hex2bin2hex_CANCEL
+ return
+ }
+ # Create a backup file
+ catch {
+ file rename -force $output_file "$output_file~"
+ }
+ }
+
+ # Read input file
+ if {[catch {
+ set file [open $input_file r]
+ fconfigure $file -translation binary
+ set data [read $file]
+ close $file
+ }]} then {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -title [mc "File not found - MCU 8051 IDE"] \
+ -message [mc "Unable to open file '%s'" $input_file]
+
+ } else {
+ # Update progress variable
+ set ::IHexTools::update 1
+
+ # Perform cnversion
+ switch -- $hex__bin {
+ 0 { ;# Bin -> Hex
+ $status_label configure -text [mc "Loading file ..."]
+ ::IHexTools::load_bin_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ $status_label configure -text [mc "Saving file ..."]
+ $progressbar configure -maximum 16
+ set data [::IHexTools::get_hex_data]
+ }
+ }
+ 1 { ;# Hex -> Bin
+ $status_label configure -text [mc "Loading file ..."]
+ $progressbar configure -maximum [::IHexTools::get_number_of_iterations $data]
+ ::IHexTools::load_hex_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ $status_label configure -text [mc "Saving file ..."]
+ $progressbar configure -maximum 16
+ set data [::IHexTools::get_bin_data]
+ }
+ }
+ 2 { ;# Sim -> Hex
+ $status_label configure -text [mc "Loading file ..."]
+ $progressbar configure -maximum [::IHexTools::get_number_of_iterations $data]
+ ::IHexTools::load_sim_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ $status_label configure -text [mc "Saving file ..."]
+ $progressbar configure -maximum 16
+ set data [::IHexTools::get_hex_data]
+ }
+ }
+ 3 { ;# Sim -> Bin
+ $status_label configure -text [mc "Loading file ..."]
+ $progressbar configure -maximum [::IHexTools::get_number_of_iterations $data]
+ ::IHexTools::load_sim_data $data
+ if {!${::IHexTools::abort} && !${::IHexTools::error_count}} {
+ $status_label configure -text [mc "Saving file ..."]
+ $progressbar configure -maximum 16
+ set data [::IHexTools::get_bin_data]
+ }
+ }
+ }
+
+ # Write output file
+ if {$data != {}} {
+ if {[catch {
+ set file [open $output_file w 420]
+ }]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -parent . \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to open file:\n\"%s\"\nfor writing" $output_file]
+ hex2bin2hex_CANCEL
+ return
+ } else {
+ fconfigure $file -translation binary
+ puts -nonewline $file $data
+ close $file
+ }
+ }
+ }
+
+ # If errors occured -> Invoke error message dialog
+ if {${::IHexTools::error_count}} {
+ # Destroy previous dialog
+ hex2bin2hex_CANCEL
+
+ # Create dialog window
+ set dialog [toplevel .error_message_dialog -class {Error dialog} -bg {#EEEEEE}]
+
+ # Create main frame (text and scrollbar)
+ set main_frame [frame $dialog.main_frame]
+ set text [text $main_frame.text \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ -width 0 -height 0 \
+ ]
+ pack $text -side left -fill both -expand 1
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$text yview" \
+ ] -side right -fill y
+ pack $main_frame -fill both -expand 1
+
+ # Create button "Close"
+ pack [ttk::button $dialog.ok_button \
+ -text [mc "Close"] \
+ -command "grab release $dialog; destroy $dialog" \
+ ]
+
+ $text insert end ${::IHexTools::error_string}
+ $text configure -state disabled
+
+ # Set window attributes -- modal window
+ wm iconphoto $dialog ::ICONS::16::no
+ wm title $dialog [mc "Corrupted file - MCU 8051 IDE"]
+ wm minsize $dialog 520 250
+ wm protocol $dialog WM_DELETE_WINDOW "grab release $dialog; destroy $dialog"
+ wm transient $dialog .
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ # Close original dialog
+ hex2bin2hex_CANCEL
+ }
+
+ ## Abort file conversion -- auxiliary procedure for 'hex2bin2hex'
+ # @return void
+ proc hex2bin2hex_ABORT {} {
+ set ::IHexTools::abort 1
+ }
+
+ ## Close file conversion dialog -- auxiliary procedure for 'hex2bin2hex'
+ # @return void
+ proc hex2bin2hex_CANCEL {} {
+ ::IHexTools::free_resources
+ grab release .hex2bin2hex_dialog
+ destroy .hex2bin2hex_dialog
+ }
+
+ ## Invoke file selection dialog to select input or output file
+ # Result is stored in variable '::X::input_file' or '::X::output_file'
+ # @parm Bool io - 1 == Input; 0 == Output
+ # @parm String mask - File suffix
+ # @parm Widget master - GUI parent
+ # @return void
+ proc select_input_output {io mask master} {
+ variable IO ;# Bool: 1 == choose input file; 0 == choose output file
+ variable actualProject ;# Object: Current project
+ set IO $io
+
+ # Invoke the dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Open file - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 0 -filetypes [list \
+ [list [mc "Input file"] "*.$mask"] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Ok button
+ fsd setokcmd {
+ set filename [X::fsd get]
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+ if {${X::IO}} {
+ set X::input_file $filename
+ } {
+ set X::output_file $filename
+ }
+ }
+
+ fsd activate ;# Activate the dialog
+ }
+
+ ## Invoke dialog "Disassemble"
+ # @return void
+ proc __disasm {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Invoke the file selection dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Open file - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 0 -filetypes [list \
+ [list [mc "IHEX 8"] {*.{hex,ihx}}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ fsd setokcmd {
+ X::fsd deactivate
+
+ set filename [X::fsd get]
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+
+ if {
+ ![file exists $filename] ||
+ ![file isfile $filename] ||
+ (!$::MICROSOFT_WINDOWS && ![file readable $filename])
+ } {
+ tk_messageBox -type ok -icon warning \
+ -parent [X::fsd get_window_name] \
+ -title [mc "File not found - MCU 8051 IDE"] \
+ -message [mc "The selected file %s does not exist." $filename]
+ } else {
+ set data [X::decompile $filename]
+
+ if {$data != {}} {
+ ${X::actualProject} background_open $data
+ if {[lindex ${X::simulator_enabled} ${X::actualProjectIdx}] == 0} {
+ ${X::actualProject} switch_to_last
+ }
+ } {
+ tk_messageBox \
+ -type ok -icon warning \
+ -title [mc "Decompilation failed"] \
+ -message [mc "Decompilation failed -- see messages for details"]
+ }
+ }
+ }
+ # activate the dialog
+ fsd activate
+
+ set critical_procedure_in_progress 0
+ }
+
+ ## Disaaemble the given file -- auxiliary procedure for '__disasm'
+ # @parm String filename - name of IHEX8 file to disassemble
+ # @return String - resulting source code
+ proc decompile {filename} {
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable compilation_mess_project ;# Object: Project related to running compilation
+ variable actualProject ;# Object: Current project
+
+ set compilation_in_progress 1
+ set compilation_mess_project $actualProject
+ messages_text_append [mc "\nLoading IHEX file ..."]
+
+ # Open the specified file
+ if {[catch {
+ set file [open $filename r]
+ }]} then {
+ tk_messageBox -parent . \
+ -icon warning -type ok \
+ -title [mc "Unable to open file"] \
+ -message [mc "Unable to read file '%s'" $filename]
+ return {}
+ }
+
+ # Adjust GUI
+ make_progressBar_on_Sbar ;# Create compilation progress bar on status bar
+ compilation_progress ;# Initialize compilation progress bar
+ $actualProject bottomNB_show_up {Messages} ;# Raise tab "Messages" on bottom panel
+
+ # Setup compiler
+ set Compiler::Settings::ABORT_VARIABLE 0
+ set Compiler::Settings::TEXT_OUPUT_COMMAND X::messages_text_append
+ set Compiler::Settings::UPDATE_COMMAND {update}
+
+ # Perform decompilation
+ set data {}
+ set ::IHexTools::update 1
+ ::IHexTools::load_hex_data [read $file]
+ if {!${::IHexTools::error_count} && !${::IHexTools::abort}} {
+ messages_text_append [mc "Successful"]
+ set data [::disassembler::compile [::IHexTools::get_hex_data]]
+ set ::disassembler::asm {}
+ }
+ close $file
+
+ # Finalize
+ set Compiler::Settings::ABORT_VARIABLE 0
+ destroy_progressBar_on_Sbar
+ set compilation_in_progress 0
+
+ # Write error messages
+ if {${::IHexTools::error_count}} {
+ messages_text_append ${::IHexTools::error_string}
+ messages_text_append [mc "FAILED"]
+ }
+
+ # Free resources reserved during decompilation
+ ::IHexTools::free_resources
+
+ return $data
+ }
+
+ ## Show/Hide Line numbers (in Editor)
+ # @return void
+ proc __show_hine_LineN {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Show/Hide line numbers
+ $actualProject show_hide_lineNumbers
+ }
+
+ ## Show/Hide Icon border (in Editor)
+ # @return void
+ proc __show_hine_IconB {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Show/Hide Icon border
+ $actualProject show_hide_IconBorder
+ }
+
+ ## Redraw pane windows -- binding for event <Configure>
+ # @return void
+ proc redraw_panes {} {
+ variable last_WIN_GEOMETRY ;# Last window geometry (main window)
+ variable openedProjects ;# List of opened projects (Object references)
+
+ # Window geometry unchanged -> return
+ if {$last_WIN_GEOMETRY == [wm geometry .]} {
+ return
+ # Refresh last window geometry variable
+ } {
+ set last_WIN_GEOMETRY [wm geometry .]
+ }
+
+ # Gain window height and width
+ evaluate_new_window_geometry
+
+ # Bottom NoteBook
+ if {${::last_WIN_GEOMETRY_width} != ${::WIN_GEOMETRY_width}} {
+ set ::last_WIN_GEOMETRY_width ${::WIN_GEOMETRY_width}
+ foreach project $openedProjects {
+ catch {
+ $project bottomNB_redraw_pane
+ }
+ catch {
+ $project leftpanel_redraw_pane
+ }
+ }
+ }
+ # Right panel & File notes
+ if {${::last_WIN_GEOMETRY_height} != ${::WIN_GEOMETRY_height}} {
+ set ::last_WIN_GEOMETRY_height ${::WIN_GEOMETRY_height}
+ foreach project $openedProjects {
+ catch {
+ $project right_panel_redraw_pane
+ $project todo_panel_redraw_pane
+ }
+ }
+ }
+ }
+
+ ## Invoke dialog "About"
+ # @return void
+ proc __about {} {
+ # Create dialog window
+ set win [toplevel .about -class [mc "About dialog"] -bg {#EEEEEE}]
+
+ # Create dialog header
+ pack [label $win.header \
+ -compound left \
+ -image ::ICONS::32::mcu8051ide \
+ -text " ${::APPNAME}" \
+ -font [font create \
+ -size -20 \
+ -family {helvetica}]
+ ] -side top -pady 5
+
+ # Create notebook
+ set nb [ttk::notebook $win.nb]
+
+ # Create tab "About"
+ set about_tab [frame $nb.about_tab]
+ $nb add $about_tab -text [mc "About"]
+ pack [text $about_tab.text \
+ -width 0 -height 0 -cursor left_ptr \
+ -yscrollcommand "$about_tab.scrollbar set" \
+ -font [font create \
+ -size -12 \
+ -family {helvetica}] \
+ ] -fill both -expand 1 -side left
+ pack [ttk::scrollbar $about_tab.scrollbar \
+ -orient vertical \
+ -command "$about_tab.text yview" \
+ ] -fill y -side right
+ # fill in the about tab
+ $about_tab.text insert end "${::APPNAME}\n"
+ $about_tab.text insert end [mc "\tComplete IDE for MCS-51 based microconrollers.\n"]
+ $about_tab.text insert end [mc "\tThis program is witten for POSIX Systems\n"]
+ if {$::MICROSOFT_WINDOWS} {
+ $about_tab.text insert end [mc "\tYOU ARE CURRENTLY USING VERSION FOR Microsoft® Windows®\n"]
+ }
+ $about_tab.text insert end "\n(c) Martin Ošmera <martin.osmera@gmail.com>\n"
+ $about_tab.text insert end [mc "Web: http://mcu8051ide.sourceforge.net\n"]
+ $about_tab.text insert end [mc "Please post suggestions and comments at http://mcu8051ide.sf.net\n"]
+ $about_tab.text insert end [mc "\n\nThanks to Kostya V. Ivanov for bug fixes.\n"]
+ $about_tab.text insert end [mc "Thanks to SDCC development team for their great work !\n"]
+ $about_tab.text insert end [mc "Thanks to %s for their help during development\n" "Fabricio Alcalde, Shakthi Kannan, Miroslav Hradílek, Kostya V. Ivanov"]
+
+ # Finalize text widget creation
+ $about_tab.text configure -state disabled
+
+ # Create tab "Thanks to"
+ set thanks_tab [frame $nb.thanks_tab]
+ $nb add $thanks_tab -text [mc "Thanks to"]
+ pack [text $thanks_tab.text \
+ -width 0 -height 0 -cursor left_ptr \
+ -yscrollcommand "$thanks_tab.scrollbar set" \
+ ] -fill both -expand 1 -side left
+ pack [ttk::scrollbar $thanks_tab.scrollbar \
+ -orient vertical \
+ -command "$thanks_tab.text yview" \
+ ] -fill y -side right
+
+
+ $thanks_tab.text insert end [mc "Thanks to Fabricio Alcalde for bug reports and suggestions\n"]
+ $thanks_tab.text insert end [mc "Thanks to Miroslav Hradílek for bug reports\n"]
+ $thanks_tab.text insert end [mc "Thanks to Kostya V. Ivanov for significant bug fixes.\n"]
+ $thanks_tab.text insert end [mc "Thanks to Shakthi Kannan for including this IDE in FEL\n\n"]
+ $thanks_tab.text insert end [mc "SDCC developers:\n"]
+ $thanks_tab.text insert end "\tBela Torok\n"
+ $thanks_tab.text insert end "\tBernhard Held\n"
+ $thanks_tab.text insert end "\tBorut Ražem\n"
+ $thanks_tab.text insert end "\tDave Helton\n"
+ $thanks_tab.text insert end "\tDaniel Drotos\n"
+ $thanks_tab.text insert end "\tErik Petrich\n"
+ $thanks_tab.text insert end "\tFrieder Ferlemann\n"
+ $thanks_tab.text insert end "\tHans Dorn\n"
+ $thanks_tab.text insert end "\tJerome Bessiere\n"
+ $thanks_tab.text insert end "\tJesus Calvino-Fraga\n"
+ $thanks_tab.text insert end "\tJohan Knol\n"
+ $thanks_tab.text insert end "\tAlex Karahalios\n"
+ $thanks_tab.text insert end "\tKarl Bongers\n"
+ $thanks_tab.text insert end "\tKlaus Flittner\n"
+ $thanks_tab.text insert end "\tKlaus Martin Hennemann\n"
+ $thanks_tab.text insert end "\tKevin Vigor\n"
+ $thanks_tab.text insert end "\tMaarten Brock\n"
+ $thanks_tab.text insert end "\tMartin Dubuc\n"
+ $thanks_tab.text insert end "\tMartin Helmling\n"
+ $thanks_tab.text insert end "\tMichael Hope\n"
+ $thanks_tab.text insert end "\tMichael Schmitt\n"
+ $thanks_tab.text insert end "\tPaul Stoffregen\n"
+ $thanks_tab.text insert end "\tSandeep Dutta\n"
+ $thanks_tab.text insert end "\tScott Dattalo\n"
+ $thanks_tab.text insert end "\tErik Petrich\n"
+ $thanks_tab.text insert end "\tStephen M. Kenton\n"
+ $thanks_tab.text insert end "\tSlade Rich\n"
+ $thanks_tab.text insert end "\tShawn Masters\n"
+ $thanks_tab.text insert end "\tPhilipp Krause\n"
+ $thanks_tab.text insert end "\tStephen Williams\n"
+ $thanks_tab.text insert end "\tRaphael Neider\n"
+ $thanks_tab.text insert end "\tAnton Voloshin\n"
+ $thanks_tab.text insert end "\tVangelis Rokas\n"
+ $thanks_tab.text insert end "\tWim Lewis\n"
+ $thanks_tab.text insert end [mc "\n(Please post suggestions to %s)\n" "martin.osmera@gmail.com"]
+ $thanks_tab.text configure -state disabled
+
+ # Create tab "Licence"
+ set licence_tab [frame $nb.licence_tab]
+ $nb add $licence_tab -text [mc "Licence"]
+ pack [text $licence_tab.text \
+ -width 0 -height 0 \
+ -yscrollcommand "$licence_tab.scrollbar set" \
+ ] -fill both -expand 1 -side left
+ pack [ttk::scrollbar $licence_tab.scrollbar \
+ -orient vertical \
+ -command "$licence_tab.text yview" \
+ ] -fill y -side right
+ # Fill in the licence tab
+ if {[file exists "${::LIB_DIRNAME}/../data/licence.txt"]} {
+ $licence_tab.text insert end [read [open "${::LIB_DIRNAME}/../data/licence.txt" {r}]]
+ } {
+ $licence_tab.text insert end [mc "FILE \"licence.txt\" WAS NOT FOUND\n\n"]
+ $licence_tab.text insert end [mc "Text of the licence agreement is not availble,\n"]
+ $licence_tab.text insert end [mc "please check your instalation."]
+ }
+ $licence_tab.text configure -state disabled
+
+ # Pack NoteBook
+ pack $nb -fill both -expand 1 -side top -padx 10
+ $nb select $about_tab
+ # Create button "Close"
+ pack [ttk::button $win.close \
+ -text [mc "Close"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::about_CLOSE} \
+ ] -side bottom -pady 5
+
+ # Events binding (Enter, Escape == Close)
+ bind $win <KeyRelease-Return> {X::about_CLOSE; break}
+ bind $win <KeyRelease-KP_Enter> {X::about_CLOSE; break}
+ bind $win <KeyRelease-Escape> {X::about_CLOSE; break}
+
+ # Focus on button "Close"
+ focus $win.close
+
+ # Window manager options -- modal window
+ wm iconphoto $win ::ICONS::16::mcu8051ide
+ wm title $win [mc "About - MCU 8051 IDE"]
+ wm minsize $win 620 320
+ wm protocol $win WM_DELETE_WINDOW {
+ X::about_CLOSE
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Close dialog "About" -- auxiliary procedure for '__about'
+ # @return void
+ proc about_CLOSE {} {
+ grab release .about
+ destroy .about
+ }
+
+ ## Auto indent source code in the current editor
+ # @return void
+ proc __reformat_code {} {
+ variable actualProject ;# Object: Current project
+ variable editor_lines ;# Number of lines in the current editor
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable reformat_code_abort ;# Bool: Abort function 'reformat_code'
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # C language
+ if {[$actualProject editor_procedure {} get_language {}] == 1} {
+ if {$::MICROSOFT_WINDOWS} { ;# Not implemented yet on Microsoft Windows
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Sorry, unable to compile"] \
+ -message [mc "Unable to indent C source without program indent, MCU 8051 IDE is unable to localize this program on Microsoft Windows operating system. So this feature is not available in version for MS Windows. Correction of this limitation is planed but right now it's not available."]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Check for program "indent"
+ if {!${::PROGRAM_AVALIABLE(indent)}} {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to compile"] \
+ -message [mc "Unable to indent C source without program indent, please install indent and restart MCU 8051 IDE."]
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Save file
+ if {![$actualProject editor_procedure {} save {}]} {
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Perform indention and refresh editor
+ set filename [$actualProject editor_procedure {} getFileName {}]
+ set filename [file join [lindex $filename 0] [lindex $filename 1]]
+ if {[catch {exec -- indent -kr -npro $filename} result]} {
+ puts stderr $result
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to compile"] \
+ -message [mc "Unable to indent C source code.\n\n%s" $result]
+ } {
+ $actualProject filelist_reload_file
+ }
+
+ # Assembly language
+ } {
+ # Prepare
+ set reformat_code_abort 0 ;# Reset auto indention abort flag
+ set editor_lines [$actualProject editor_linescount] ;# Number of lines in the editor
+ set compilation_progress 0 ;# Reset compilation progress variable
+ set editor [$actualProject editor_procedure {} cget -editor] ;# Editor widget
+ set lastLine [$actualProject editor_actLineNumber] ;# Current line
+ set new_content {} ;# Initialize new content string
+
+ set max [expr {$editor_lines / 10}]
+ if {!$max} {
+ set max 1
+ }
+
+ # Create progress dialog
+ create_progress_bar .prgDl \
+ . \
+ {} \
+ "Reformating code" \
+ ::X::compilation_progress \
+ $max \
+ [mc "Reformating code"] \
+ ::ICONS::16::filter \
+ [mc "Abort"] \
+ {::X::reformat_code_stop}
+
+ $editor configure -autoseparators 0
+
+ # Perform auto indention
+ set new_content [reformat_code_core [$editor get 1.0 end]]
+ $editor delete 1.0 end
+
+ # Insert new content in the editor
+ $editor insert end [string replace $new_content {end-1} end]
+ $actualProject editor_procedure {} parseAll {}
+ $actualProject editor_procedure {} goto $lastLine
+
+ $editor edit separator
+ $editor configure -autoseparators 1
+
+ # Finalize
+ catch {destroy .prgDl ;# Destroy progress dialog}
+ }
+ set critical_procedure_in_progress 0
+ }
+
+ ## Abort auto indention -- auxiliary procedure for '__reformat_code'
+ # @return void
+ proc reformat_code_stop {} {
+ variable reformat_code_abort ;# Bool: Abort function 'reformat_code'
+ set reformat_code_abort 1
+ }
+
+ ## Perform auto indention -- auxiliary procedure for '__reformat_code'
+ # @parm String data - data to parse
+ # @return String - result
+ proc reformat_code_core {data} {
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable reformat_code_abort ;# Bool: Abort function 'reformat_code'
+
+ set idx 1 ;# Line number
+ set new_content {} ;# Resulting string
+
+ # Parse input data (line by line)
+ foreach line [split $data "\n"] {
+ if {$reformat_code_abort} {break} ;# Conditional abort
+ incr idx ;# Increment line number
+
+ # Replace lines containg only white space with empty lines
+ if {[regexp {^\s*$} $line]} {
+ append new_content "\n"
+ if {![expr {$idx % 10}]} {
+ incr compilation_progress
+ }
+ continue
+ }
+
+ # Line fields
+ set field_0 {} ;# 1st field (labels, constants, etc.)
+ set field_1 {} ;# 2nd field (instructins, directives, macros, etc.)
+ set field_2 {} ;# 3rd field (operands, arguments, etc.)
+ set field_3 {} ;# 4th field (comments only)
+
+ # Determinate line with replaced strings and chars with underscores
+ set line_tmp $line
+ while 1 {
+ if {![regexp {'[^']+'} $line_tmp str]} {break}
+ set len [string length $str]
+ regsub {'[^']+'} $line_tmp [string repeat {_} $len] line_tmp
+ }
+
+ # Determinate comment field (field_3)
+ set commentBegin [string first {;} $line_tmp]
+ if {$commentBegin != -1} {
+ set field_3 [string range $line $commentBegin end]
+ regsub {\s*;.*$} $line_tmp {} line_tmp
+ set line [string range $line 0 [expr {$commentBegin - 1}]]
+ }
+
+ # Determinate fields 0..2
+ set pos 0
+ for {set j 0} {$j < 2} {incr j} {
+ if {![regexp {^\s*[^\s]+} $line_tmp str]} {break}
+ set len [string length $str]
+ set i [expr {$len - 1}]
+ set space [string repeat { } $len]
+ regsub {^\s*[^\s]+} $line_tmp $space line_tmp
+ set field_$j [regsub {^\s+} [string range $line $pos $i] {}]
+ set line [string replace $line $pos $i $space]
+ incr pos $len
+ }
+
+ # Remove leading white space from Field 2
+ set field_2 [regsub {^\s+} $line {}]
+
+ # Field 1 >> Field 2; Field 0 -> Field 1; "" -> Field 0;
+ if {
+ [regexp {^\w+$} $field_0] &&
+ ![regexp {^\d} $field_0] &&
+ [lsearch -exact -ascii ${::ASMsyntaxHighlight::directive_type2} \
+ [string toupper $field_1]] == -1
+ } {
+ append field_1 $field_2
+ set field_2 $field_1
+ set field_1 {}
+ if {[string toupper $field_0] != {ENDM}} {
+ set field_1 $field_0
+ set field_0 {}
+ }
+ }
+
+ # If line contains only comment then Field 3 -> Field 1
+ if {
+ $field_3 != {} &&
+ $field_0 == {} &&
+ $field_1 == {} &&
+ $field_2 == {} &&
+ $commentBegin != 0
+ } {
+ set field_1 $field_3
+ set field_3 {}
+ }
+
+ # Adjust space between operans/arguments
+ set field_2_new {}
+ if {$field_2 != {}} {
+ # Strings/Chars to underscores
+ set field_2_tmp $field_2
+ while 1 {
+ if {![regexp {'[^']+'} $field_2_tmp str]} {break}
+ set len [string length $str]
+ regsub {'[^']+'} $field_2_tmp [string repeat {_} $len] field_2_tmp
+ }
+ # Recomposite Field 2
+ while 1 {
+ set i [string first {,} $field_2_tmp]
+ if {$i == -1} {
+ append field_2_new {, }
+ append field_2_new [string trim $field_2]
+ break
+ }
+ append field_2_new {, }
+ append field_2_new [string trim [string range $field_2 0 [expr {$i - 1}]]]
+ set field_2 [string range $field_2 [expr {$i + 1}] end]
+ set field_2_tmp [string range $field_2_tmp [expr {$i + 1}] end]
+ }
+ set field_2 [string trimleft $field_2_new {, }]
+ }
+
+ # Recomposite line
+ set line $field_0
+ if {$field_1 != {}} {
+ append line "\t"
+ append line $field_1
+ }
+ if {$field_2 != {}} {
+ append line "\t"
+ append line $field_2
+ }
+ if {$field_3 != {}} {
+ # Adjust field 3 (insure appropriate number of leading tabs)
+ if {$line != {}} {
+ set i -1
+ set spaces 0
+ set correction 0
+ set falseLength [string length $line]
+
+ while 1 {
+ set i [string first "\t" $line [expr {$i + 1}]]
+ if {$i == -1} {break}
+
+ set spaces [expr {8 - (($i + $correction) % 8)}]
+ set spaces_1 [expr {$spaces - 1}]
+ incr correction $spaces_1
+ incr falseLength $spaces_1
+ }
+
+ set spaces [expr {4 - ($falseLength / 8)}]
+ if {$spaces < 1} {
+ set spaces 1
+ }
+
+ append line [string repeat "\t" $spaces]
+ }
+ append line $field_3
+ }
+
+ # Append new line to the result
+ append new_content $line
+ append new_content "\n"
+ if {![expr {$idx % 10}]} {
+ incr compilation_progress
+ }
+ }
+
+ # Return result
+ return $new_content
+ }
+
+ ## Invoke dialog "Clean up project folder"
+ # @return void
+ proc __cleanup {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Create dialog window
+ set win [toplevel .cleanup -class [mc "Options dialog"] -bg {#EEEEEE}]
+ set bottom_frame [frame $win.buttonFrame]
+ set status_bar_lbl [label $bottom_frame.status_bar \
+ -justify left -anchor w \
+ ]
+
+ # Create label frames
+ set backup_labelframe [ttk::labelframe $win.backup_labelframe\
+ -text [mc "Backup files"] \
+ ]
+ set other_labelframe [ttk::labelframe $win.other_labelframe \
+ -text [mc "Other files"] \
+ ]
+
+ set i 0 ;# Checkbutton index
+
+ # Fill in top labelframe
+ set row 0 ;# Row in the grid
+ set col 0 ;# Column in the grid
+ foreach text {
+ *.asm~ *.lst~ *.sim~ *.hex~ *.bin~ *.html~
+ *.tex~ *.wtc~ *.mcu8051ide~ *.m5ihib~ *.cdb~
+ *.ihx~ *.adf~ *.omf~ *.map~ *.c~ *.h~
+ *.vhc~ *.vhw~ *.txt~ *~
+ } ID {
+ asm lst sim hex bin html
+ tex wtc mcu8051ide m5ihib cdb
+ ihx adf omf map c h
+ vhc vhw txt all_bc
+ } helptext {
+ {Assembly language sources}
+ {Code listing files}
+ {Assembly debug files (before v1.0.5)}
+ {IHEX object code files}
+ {Binary object code files}
+ {HTML files}
+ {TeX sources}
+ {Register watches definition files}
+ {MCU 8051 IDE Project}
+ {Hibernated programs}
+ {SDCC debug files}
+ {SDCC IHEX8 object files}
+ {MCU 8051 IDE Assembler debug files}
+ {OMF-51 object files}
+ {SDCC: The memory map for the load module}
+ {C sources}
+ {C headers}
+ {Virtual Hardware Component}
+ {Virtual HardWare}
+ {Text files}
+ {All backup files}
+ } \
+ {
+ set helptext [mc $helptext]
+ set button [checkbutton $backup_labelframe.$ID \
+ -text $text -anchor w \
+ -command "::X::cleanup_option $i" \
+ -variable __cleanup_$ID \
+ ]
+ grid $button -row $row -column $col -sticky w -padx 5
+ if {[lindex $::CONFIG(CLEANUP_OPTIONS) $i] != {0}} {$button select} {$button deselect}
+ bind $button <Enter> "$status_bar_lbl configure -text {$helptext}"
+ bind $button <Leave> "$status_bar_lbl configure -text {}"
+
+ incr i
+ incr col
+ if {$col == 4} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Fill in bottom labelframe
+ set row 0 ;# Row in the grid
+ set col 0 ;# Column in the grid
+ foreach text {
+ *.lst *.sim *.hex *.bin *.html *.tex *.m5ihib
+ *.noi *.obj *.map *.p *.mac *.i *.ihx
+ *.adf *.adb *.rel *.cdb *.mem *.lnk *.sym
+ *.omf *.rst *.hashes *.bak
+ } ID {
+ lst sim hex bin html tex m5ihib
+ noi obj map p mac i ihx
+ adf adb rel cdb mem lnk sym
+ omf rst hashes bak
+ } helptext {
+ {Code listing files}
+ {Assembly debug files (before v1.0.5)}
+ {IHEX object code files}
+ {Binary object code files}
+ {HTML files}
+ {TeX sources}
+ {Hibernated programs}
+ {ASL: NoICE-compatible command file}
+ {ASL: Atmel debub file used by the AVR tools}
+ {SDCC: The memory map for the load module}
+ {ASL object files}
+ {Macro definition file}
+ {Macro output files}
+ {SDCC IHEX8 object files}
+ {MCU 8051 IDE Assembler debug files}
+ {SDCC Assembler debug files}
+ {SDCC: Object file created by the assembler}
+ {SDCC debug files}
+ {SDCC: A file with a summary of the memory usage}
+ {SDCC: Linker script}
+ {SDCC: Symbol listing for the sourcefile}
+ {OMF-51 object files}
+ {SDCC: Listing file updated with linkedit information}
+ {MD5 hashes for C source files}
+ {Doxygen backup file}
+ } \
+ {
+ set helptext [mc $helptext]
+ set button [checkbutton $other_labelframe.$ID \
+ -text $text -anchor w \
+ -command "::X::cleanup_option $i" \
+ -variable __cleanup__$ID \
+ ]
+ grid $button -row $row -column $col -sticky w -padx 5
+ if {[lindex $::CONFIG(CLEANUP_OPTIONS) $i] != {0}} {$button select} {$button deselect}
+ bind $button <Enter> "$status_bar_lbl configure -text {$helptext}"
+ bind $button <Leave> "$status_bar_lbl configure -text {}"
+
+ incr i
+ incr col
+ if {$col == 4} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Set column sizes
+ grid columnconfigure $backup_labelframe 0 -minsize 130
+ grid columnconfigure $backup_labelframe 1 -minsize 130
+ grid columnconfigure $backup_labelframe 2 -minsize 130
+ grid columnconfigure $backup_labelframe 3 -minsize 130
+ grid columnconfigure $other_labelframe 0 -minsize 130
+ grid columnconfigure $other_labelframe 1 -minsize 130
+ grid columnconfigure $other_labelframe 2 -minsize 130
+ grid columnconfigure $other_labelframe 3 -minsize 130
+
+ # Pack label frames
+ pack $backup_labelframe -fill both -expand 1 -padx 10 -pady 5
+ pack $other_labelframe -fill both -expand 1 -padx 10 -pady 5
+
+ # Create 'OK' and 'CANCEL' buttons
+ pack $status_bar_lbl -side left -fill x -expand 1
+ pack [ttk::button $win.buttonFrame.ok \
+ -text [mc "Remove files"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::cleanup_OK} \
+ ] -side left
+ pack [ttk::button $win.buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::cleanup_CANCEL} \
+ ] -side left
+ pack $bottom_frame -pady 5 -fill x -padx 5
+
+ # Events binding (Enter == Ok; Esc == Cancel)
+ bind $win <KeyRelease-Return> {X::cleanup_OK; break}
+ bind $win <KeyRelease-KP_Enter> {X::cleanup_OK; break}
+ bind $win <KeyRelease-Escape> {X::cleanup_CANCEL; break}
+
+ # Set window attributes -- modal window
+ wm iconphoto .cleanup ::ICONS::16::emptytrash
+ wm title .cleanup [mc "Cleanup project folder - MCU 8051 IDE"]
+ wm minsize .cleanup 360 310
+ wm resizable .cleanup 0 0
+ wm protocol .cleanup WM_DELETE_WINDOW {
+ X::cleanup_CANCEL
+ }
+ wm transient .cleanup .
+ grab .cleanup
+ raise .cleanup
+ tkwait window .cleanup
+ }
+
+ ## Change cleanup option -- auxiliary procedure for '__cleanup'
+ # @parm Int idx - checkbutton index
+ # @return void
+ proc cleanup_option {idx} {
+ lset ::CONFIG(CLEANUP_OPTIONS) $idx \
+ [expr {[lindex $::CONFIG(CLEANUP_OPTIONS) $idx] == {0}}]
+ }
+
+ ## Start cleanup -- auxiliary procedure for '__cleanup'
+ # @return void
+ proc cleanup_OK {} {
+ variable cleanup_masks ;# GLOB patterns
+ variable actualProject ;# Object: Current project
+
+ # Invoke confirmation dialog
+ if {
+ ![tk_messageBox \
+ -parent . \
+ -icon question \
+ -type yesno \
+ -title [mc "Cleanup project folder"] \
+ -message [mc "Are you sure ?"]
+ ]
+ } {
+ return
+ }
+
+ # Determinate list of GLOB expressions of selected for removal
+ set dir [$actualProject cget -projectPath]
+ set files [list]
+ foreach mask $cleanup_masks bool $::CONFIG(CLEANUP_OPTIONS) {
+ if {$bool} {
+ lappend files $mask
+ }
+ }
+
+ # Determinate list of files selected for removal
+ set files_n [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach f $files {
+ append files_n { } [glob -directory $dir -nocomplain -type f $f]
+ }
+ }
+ set files $files_n
+
+ # Remove the specified files
+ set result {}
+ foreach file $files {
+ if {![catch {
+ file delete -force -- $file
+ }]} {
+ lappend result $file
+ }
+ }
+
+ # Finalize
+ cleanup_CANCEL ;# Close dialog window
+ cleanup_finish $result ;# Invoke results dialog
+ }
+
+ ## Close dialog "Clean up project folder" -- auxiliary procedure for 'cleanup_OK'
+ # @return void
+ proc cleanup_CANCEL {} {
+ destroy .cleanup
+ }
+
+ ## Show results of files removal -- auxiliary procedure for 'cleanup_OK'
+ # @parm List files - list of removed files
+ # @return void
+ proc cleanup_finish {files} {
+ # Create dialog window
+ set win [toplevel .cleanup_finish -class {Results} -bg {#EEEEEE}]
+
+ # Create window header
+ pack [label $win.header_label \
+ -text [mc "These files were removed"] \
+ -font [font create \
+ -size -20 \
+ -family {helvetica}]
+ ] -anchor center
+
+ # Create top frame (text widget and scrollbar)
+ set frame [frame $win.top_frame]
+
+ # Create text widget and its scrollbar
+ set scrollbar [ttk::scrollbar $frame.scrollbar \
+ -command "$frame.text yview" \
+ -orient vertical \
+ ]
+ set text [text $frame.text \
+ -yscrollcommand "$frame.scrollbar set" \
+ -width 1 -height 1 \
+ -cursor left_ptr \
+ ]
+
+ # Fill in the text widget
+ foreach txt $files {
+ $text insert end $txt
+ $text insert end "\n"
+ }
+ $text configure -state disabled
+
+ # Pack scrollbar and the text widget
+ pack $scrollbar -side right -fill y
+ pack $text -side left -fill both -expand 1
+
+ # Pack the top frame and create button "Ok"
+ pack $frame -fill both -expand 1
+ pack [ttk::button $win.ok_button \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "destroy $win" \
+ ] -anchor center -side bottom
+
+ # Events binding (Enter/Escape == Ok)
+ bind $win <KeyRelease-Return> "destroy $win; break"
+ bind $win <KeyRelease-KP_Enter> "destroy $win; break"
+ bind $win <KeyRelease-Escape> "destroy $win; break"
+
+ # Set window attributes -- modal window
+ wm iconphoto $win ::ICONS::16::emptytrash
+ wm title $win [mc "Cleanup project folder - MCU 8051 IDE"]
+ wm minsize $win 520 300
+ wm protocol $win WM_DELETE_WINDOW "grab release $win; destroy $win"
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Execute custom command
+ # @parm Int cmd_num - command number
+ # @return void
+ proc __exec_custom_cmd {cmd_num} {
+ variable custom_command_cmd ;# Array of custom commands (shell scripts)
+ variable custom_command_options ;# Array of Lists of custom command options
+ variable custom_command_PID ;# Array of custom command TIDs (Thread IDentifiers)
+ variable custom_command_NUM ;# Array of custom command numbers
+ variable custom_command_counter ;# Counter of custom command invocations
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if the command is not already running
+ if {$custom_command_PID($cmd_num) != {}} {
+ if {[tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type yesno \
+ -title [mc "Confirm termination - MCU 8051 IDE"] \
+ -message [mc "This process is alredy in progress. Do you want to terminate it ?"]
+ ] == {yes}} {
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no kill command on Microsoft Windows
+ if {$custom_command_PID($cmd_num) != {}} {
+ catch {
+ exec -- kill -9 $custom_command_PID($cmd_num) &
+ }
+ }
+ }
+ custom_cmd_icon_reset $custom_command_NUM($cmd_num)
+ }
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Invoke confiramation dialog (if requested)
+ if {[lindex $custom_command_options($cmd_num) 0]} {
+ if {
+ ![tk_messageBox \
+ -parent . \
+ -icon question \
+ -type yesno \
+ -title [mc "Confirmation required"] \
+ -message [mc "Do you really want to execute\ncustom command %s ?" $cmd_num]]
+ } {
+ set critical_procedure_in_progress 0
+ return
+ }
+ }
+
+ # Adjust button icon on main toolbar
+ if {[winfo exists .mainIconBar.custom$cmd_num]} {
+ .mainIconBar.custom$cmd_num configure \
+ -image ::ICONS::22::gear${cmd_num}_play
+ }
+
+ # Perform variables substitution in the command string
+ set cmd $custom_command_cmd($cmd_num)
+ regsub -all {%%} $cmd "\a" cmd
+ if {[regexp {%} $cmd]} {
+ # Determinate editor object reference
+ set editor [$actualProject get_current_editor_object]
+
+ if {[regexp {%URLS} $cmd]} {
+ set URLS {}
+ foreach e [$actualProject cget -editors] {
+ set url [$e cget -fullFileName]
+ if {[regexp {\s} $url]} {
+ append URLS "\"" $url "\"" { }
+ } {
+ append URLS $url { }
+ }
+ }
+ regsub -all {%URLS} $cmd [string replace $URLS end end] cmd
+ }
+ if {[regexp {%URL} $cmd]} {
+ regsub -all {%URL} $cmd [$editor cget -fullFileName] cmd
+ }
+ if {[regexp {%directory} $cmd]} {
+ regsub -all {%directory} $cmd [$actualProject cget -projectPath] cmd
+ }
+ if {[regexp {%filename} $cmd]} {
+ regsub -all {%filename} $cmd [$editor cget -filename] cmd
+ }
+ if {[regexp {%basename} $cmd]} {
+ regsub -all {%basename} $cmd [file tail [file rootname [$editor cget -filename]]] cmd
+ }
+ if {[regexp {%mainfile} $cmd]} {
+ regsub -all {%mainfile} $cmd [$actualProject cget -P_option_main_file] cmd
+ }
+ if {!${::Editor::editor_to_use}} {
+ if {[regexp {%line} $cmd]} {
+ regsub -all {%line} $cmd [$editor get_current_line_number] cmd
+ }
+ if {[regexp {%column} $cmd]} {
+ regexp {\d+$} [[$editor cget -editor] index insert] col
+ regsub -all {%column} $cmd $col cmd
+ }
+ if {[regexp {%selection} $cmd]} {
+ regsub -all {%selection} $cmd [$editor getselection] cmd
+ }
+ if {[regexp {%text} $cmd]} {
+ regsub -all {%text} $cmd [$editor getdata] cmd
+ }
+ } {
+ if {[regsub -all {%(line|column|selection|text)} $cmd {} cmd]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Warning - Custom command"] \
+ -message [mc "Some variables in user command could not be resolved."]
+ }
+ }
+ }
+ regsub -all "\a" $cmd {%} cmd
+
+ # Execute specified command in a separate thread
+ set custom_command_NUM($cmd_num) $custom_command_counter
+ set custom_command_PID($cmd_num) [exec -- tclsh \
+ ${::LIB_DIRNAME}/custom_command.tcl [tk appname] \
+ $custom_command_NUM($cmd_num) << $cmd & \
+ ]
+ incr custom_command_counter
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Invoke dialog "Custom command finished"
+ # -- auxiliary procedure for '__exec_custom_cmd'
+ # @parm Int num - Command number
+ # @parm String result - Result string
+ # @return void
+ proc custom_cmd_finish {num result} {
+ variable custom_command_options ;# Array of Lists of custom command options
+
+ # Set toolbar button icon to default and determinate command index
+ set i [custom_cmd_icon_reset $num]
+ if {$i == {}} {return}
+
+ # Check if result dialogs are allowed
+ if {![lindex $custom_command_options($i) 1]} {return}
+ # Invoke results dialog
+ invoke_custom_cmd_dialog $i {#00DD00} [mc "Custom command finished"] $result
+ }
+
+ ## Invoke dialog "Custom command failed"
+ # -- auxiliary procedure for '__exec_custom_cmd'
+ # @parm Int num - Command number
+ # @parm String result - Result string
+ # @return void
+ proc custom_cmd_error {num result} {
+ variable custom_command_options ;# Array of Lists of custom command options
+
+ # Set toolbar button icon to default and determinate command index
+ set i [custom_cmd_icon_reset $num]
+ if {$i == {}} {return}
+
+ # Check if error dialogs are allowed
+ if {[lindex $custom_command_options($i) 2]} {return}
+ # Invoke error dialog
+ invoke_custom_cmd_dialog $i {#DD0000} [mc "Custom command failed"] $result
+ }
+
+ ## Invoke dialog window showing results of some custom command
+ # -- auxiliary procedure for 'custom_cmd_error' and 'custom_cmd_finish'
+ # @parm Int i - Index of the custom command (0..2)
+ # @parm RGB color - Color for dialog header (24-bit RGB color code)
+ # @parm String label - Text of the dialog header
+ # @parm String result - Text of the messages area
+ # @return void
+ proc invoke_custom_cmd_dialog {i color label result} {
+ variable custom_cmd_dialog_index ;# Index of results dialog (to keep win IDs unique)
+
+ incr custom_cmd_dialog_index
+
+ # Create dialog window
+ set win [toplevel .custom_cmd_dialog${custom_cmd_dialog_index} -class {Custom command finished} -bg {#EEEEEE}]
+
+ # Create dialog header
+ pack [label $win.header_label \
+ -compound left \
+ -fg $color \
+ -text $label \
+ -image ::ICONS::22::gear$i \
+ -font [font create \
+ -family {helvetica} \
+ -size -20 \
+ -weight bold \
+ ] \
+ ] -pady 5
+
+ # Create main frame (text widget and scrollbar)
+ set main_frame [frame $win.main_frame]
+ set text [text $main_frame.text \
+ -width 1 -height 1 \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ ]
+ pack $text -side left -fill both -expand 1
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -command "$text yview" \
+ -orient vertical \
+ ] -fill y -side right
+ pack $main_frame -fill both -expand 1 -pady 5
+
+ # Create button "Ok"
+ pack [ttk::button $win.ok_button \
+ -text [mc "Ok"] \
+ -command "destroy $win" \
+ -compound left \
+ -image ::ICONS::16::ok \
+ ] -pady 5
+
+ # Fill in the text widget and disable it
+ $text insert end [string replace [regsub -all {\\\{} [regsub -all {\\\}} $result "\}"] "\{"] 0 0]
+ $text configure -state disabled
+
+ # Events binding (Enter/Escape == Ok)
+ bind $win <KeyRelease-Return> "destroy $win; break"
+ bind $win <KeyRelease-KP_Enter> "destroy $win; break"
+ bind $win <KeyRelease-Escape> "destroy $win; break"
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::gear
+ wm title $win [mc "Custom command %s - MCU 8051 IDE" $i]
+ wm minsize $win 550 300
+ wm protocol $win WM_DELETE_WINDOW "destroy $win"
+ wm transient $win .
+ }
+
+ ## Set toolbar button icon to default and determinate index of cutom command
+ # -- auxiliary procedure for 'custom_cmd_error' and 'custom_cmd_finish'
+ # @parm Int num - Command number
+ # @return Int - index of the specified cutom command (by TID) or {} (means 'not found')
+ proc custom_cmd_icon_reset {num} {
+ variable custom_command_NUM ;# Array of custom command numbers
+ variable custom_command_PID ;# Array of custom command TIDs (Thread IDentifiers)
+
+ # Search for command index
+ set found 0 ;# Bool: Coresponding index found
+ for {set i 0} {$i < 3} {incr i} {
+ if {[string equal $custom_command_NUM($i) $num]} {
+ set found 1
+ break
+ }
+ }
+ # If index not found -> return {}
+ if {!$found} {return {}}
+
+ # Reset toolbar button icon
+ if {[winfo exists .mainIconBar.custom$i]} {
+ .mainIconBar.custom$i configure -image ::ICONS::22::gear${i}
+ }
+ # Reset command PID and return result
+ set custom_command_PID($i) {}
+ return $i
+ }
+
+ ## Invoke welcome dialog
+ # @return void
+ proc __welcome_dialog {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ if {$critical_procedure_in_progress} {return}
+ if {[winfo exists .welcome]} {
+ return
+ }
+
+ # Create dialog window
+ set win [toplevel .welcome -class [mc "Welcome dialog"] -bg {#EEEEEE}]
+
+ # Create header label
+ pack [label $win.header_label \
+ -compound left -fg {#0000DD} \
+ -text [mc "Welcome to MCU 8051 IDE !"] \
+ -font [font create \
+ -family {helvetica} \
+ -size -20 \
+ -weight {bold} \
+ -slant {italic} \
+ ] \
+ ] -pady 10
+
+ # Create text widget showing the dialog message
+ set text [text $win.text \
+ -bg {#EEEEEE} -takefocus 0 \
+ -width 0 -heigh 0 -bd 0 \
+ -cursor left_ptr \
+ -wrap word \
+ -font [font create \
+ -family {helvetica} \
+ -size -12 \
+ ] \
+ ]
+ pack $text -fill both -expand 1 -padx 15
+
+ # Create button "Ok"
+ pack [ttk::button $win.ok_button \
+ -text [mc "Ok"] \
+ -command "grab release $win; destroy $win" \
+ ] -pady 5
+
+ # Create label for opening demostration project
+ set open_demo_label [label $text.open_demo_label \
+ -text [mc "Click here to open demonstration project."] \
+ -justify left -fg {#00DD00} -cursor hand1 \
+ ]
+ bind $open_demo_label <Enter> {%W configure -fg {#0000DD}}
+ bind $open_demo_label <Leave> {%W configure -fg {#00DD00}}
+ bind $open_demo_label <Button-1> "
+ grab release $win
+ destroy $win
+ ::X::open_demo_project
+ break
+ "
+
+ # Load images
+ set image_new [image create photo -format png \
+ -file "${::LIB_DIRNAME}/../icons/16x16/filenew.png"]
+ set image_start [image create photo -format png \
+ -file "${::LIB_DIRNAME}/../icons/16x16/launch.png"]
+ set image_step [image create photo -format png \
+ -file "${::LIB_DIRNAME}/../icons/16x16/goto.png"]
+
+ # Create text tags
+ $text tag configure bold -font [font create \
+ -family {times} \
+ -size -12 \
+ -weight bold \
+ ]
+ $text tag configure header -font [font create \
+ -family {times} \
+ -size -12 \
+ -weight bold \
+ -underline 1 \
+ ] -foreground {#0000FF}
+
+ # Fill in the text widget
+ $text insert end [mc "MCU 8051 IDE is fully featured Integrated Development Enviroment"]
+ $text insert end [mc " for MCS-51 based microcontollers. It's written for POSIX Operating Systems (GNU/Linux, etc.) "]
+ if {$::MICROSOFT_WINDOWS} {
+ $text insert end [mc "and since version 1.3.5 it is also available for Microsoft® Windows® operating system."]
+ }
+ $text insert end "\n\n"
+ $text insert end [mc "Main features:"]
+ $text tag add header {insert linestart} insert
+ $text insert end [mc "\n\t- Editor with syntax highlight, validation and popup-based completion"]
+ $text insert end [mc "\n\t- MCS-51 Assembler and Disassembler"]
+ $text insert end [mc "\n\t- MCS-51 Simulator (not all MCUs are fully supported !)"]
+ $text insert end [mc "\n\t- Support for C language (using C compiler SDCC)"]
+ $text insert end [mc "\n\t- Partial support for some HW tools"]
+ $text insert end [mc "\n\t- Project management"]
+ $text insert end [mc "\n\t- Custom editable commands (using shell scripts)"]
+ $text insert end [mc "\n\t- Dynamic help for instruction at the current line"]
+ $text insert end [mc "\n\t- Hexadecimal editor for eXternal RAM, Expanded RAM, Code memory, etc."]
+ $text insert end [mc "\n\t- Scientific calculator"]
+ $text insert end [mc "\n\t- Simple hardware simulation (LED's, etc.)"]
+ $text insert end [mc "\n\t- Graph showing voltage levels on ports\n\n"]
+
+ $text insert end [mc "Where to start:"]
+ $text tag add header {insert linestart} insert
+ $text insert end [mc "\n\t1. Create a new project"]
+ $text image create end -image $image_new -padx 5
+ $text insert end [mc "\n\t\t- Enter project name\n"]
+ $text insert end [mc "\t\t- Choose project directory\n"]
+ $text insert end [mc "\t\t- Choose microcontroller (e.g. AT89S52)\n"]
+ $text insert end [mc "\t2. Write your code in the opened editor and click on "]
+ $text image create end -image $image_start -padx 5
+ $text insert end [mc " to start simulator\n"]
+ $text insert end [mc "\t3. Step your program by clicking on "]
+ $text image create end -image $image_step -padx 5
+ $text insert end "\n\t----\n\t"
+ $text window create end -window $open_demo_label
+ $text insert end ""
+
+ $text insert end "\n\n"
+ $text insert end [mc "Web site:"]
+ $text tag add bold {insert linestart} insert
+ $text insert end "\thttp://mcu8051ide.sourceforge.net\n"
+ $text insert end [mc "Author:"]
+ $text tag add bold {insert linestart} insert
+ $text insert end "\tMartin Ošmera <martin.osmera@gmail.com>\n\n"
+
+ $text insert end [mc "Thank you for using/trying MCU 8051 IDE."]
+ $text tag add bold {insert linestart} insert
+
+ $text configure -state disabled
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::info
+ wm title $win [mc "Welcome to MCU 8051 IDE"]
+ wm minsize $win 580 600
+ wm protocol $win WM_DELETE_WINDOW "grab release $win; destroy $win"
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ }
+
+ ## Open demostration project -- auxiliary procedure for '__welcome_dialog'
+ # @return void
+ proc open_demo_project {} {
+ Project::open_project_file "${::LIB_DIRNAME}/../demo/Demo project.mcu8051ide"
+ }
+
+ ## Invoke dialog "Change letter case"
+ # @return void
+ proc __change_letter_case {} {
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 1]} {return}
+
+ if {$critical_procedure_in_progress} {return}
+
+ # Create dialog window
+ set win [toplevel .change_letter_case -class [mc "Options dialog"] -bg {#EEEEEE}]
+
+ # Create dialog header
+ pack [label $win.header \
+ -compound left \
+ -image ::ICONS::22::change_case \
+ -text [mc "Change letter case"] \
+ -font [font create \
+ -size -20 \
+ -family {times}]
+ ] -side top -pady 5
+
+ # Create main frame (contains labels and radio buttons)
+ set main_frame [frame $win.main_frame]
+
+ # Create header
+ foreach column {1 2 3 5 6 7 } \
+ image {up0 down0 button_cancel up0 down0 button_cancel } \
+ helptext {
+ {Uppercase} {Lowercase} {Keep case}
+ {Uppercase} {Lowercase} {Keep case}
+ } \
+ {
+ grid [Label $main_frame.header_label$column \
+ -pady 0 -bd 0 -helptext [mc $helptext] \
+ -image ::ICONS::16::$image \
+ ] -row 0 -column $column -sticky w
+ }
+
+ # Create matrix of radiobuttons and labels
+ set i 0
+ set row 1
+ set col 0
+ foreach text {
+ {Hexadecimal number} {Octal number}
+ {Decimal number} {Binary number}
+ {Constant} {Generic number}
+ {Comment} {Control sequentce}
+ {Symbol} {Directive}
+ {Label} {Instruction}
+ {SFR register} {Indirect adress}
+ {Immediate hex} {Immediate oct}
+ {Immediate dec} {Immediate bin}
+ {Immediate const} {Immediate generic}
+ {Macro instruction}
+ } {
+ # Create label
+ grid [label $main_frame.label$i \
+ -text [mc $text] -justify left \
+ -highlightthickness 0 \
+ -pady 0 -bd 0 \
+ ] -row $row -column [expr {$col * 4}] -sticky w
+
+ # Radiobutton "Uppercase"
+ grid [radiobutton $main_frame.upper$i \
+ -value [mc "U"] -highlightthickness 0 -pady 0 \
+ -variable ::X::change_letter_case_options($i) \
+ ] -row $row -column [expr {$col * 4 + 1}] -sticky w
+ # Radiobutton "Lowercase"
+ grid [radiobutton $main_frame.lower$i \
+ -value [mc "L"] -highlightthickness 0 -pady 0 \
+ -variable ::X::change_letter_case_options($i) \
+ ] -row $row -column [expr {$col * 4 + 2}] -sticky w
+ # Radiobutton "Keep"
+ grid [radiobutton $main_frame.keep$i \
+ -value [mc "-"] -highlightthickness 0 -pady 0 \
+ -variable ::X::change_letter_case_options($i) \
+ ] -row $row -column [expr {$col * 4 + 3}] -sticky w
+
+ incr col
+ incr i
+ if {$col > 1} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Set column sizes
+ grid columnconfigure $main_frame 0 -minsize 140
+ grid columnconfigure $main_frame 3 -minsize 50
+ grid columnconfigure $main_frame 4 -minsize 140
+
+ # Create button frame
+ set button_frame [frame $win.button_frame]
+ # Create buttons "All up", "All down" and "All keep"
+ foreach image {up0 down0 button_cancel} \
+ state {U L -} \
+ {
+ pack [ttk::button $button_frame.${image}_but \
+ -compound right \
+ -text [mc "All "] \
+ -image ::ICONS::16::$image \
+ -command "::X::change_letter_case_all_to $state" \
+ ] -side left
+ }
+ # Create and pack buttons "OK" and "CANCEL"
+ pack [ttk::button $button_frame.ok_button \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::change_letter_case_OK} \
+ ] -side right
+ pack [ttk::button $button_frame.cancel_button \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::change_letter_case_CANCEL} \
+ ] -side right
+
+ # Events binding (Enter == Ok; Escape == Cancel)
+ bind $win <KeyRelease-Return> {::X::change_letter_case_OK; break}
+ bind $win <KeyRelease-KP_Enter> {::X::change_letter_case_OK; break}
+ bind $win <KeyRelease-Escape> {::X::change_letter_case_CANCEL; break}
+
+ # Pack frames
+ pack $main_frame -fill both -expand 1 -padx 10 -pady 10
+ pack $button_frame -side bottom -fill x
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::change_case
+ wm title $win [mc "Change letter case - MCU 8051 IDE"]
+ wm minsize $win 450 70
+ wm protocol $win WM_DELETE_WINDOW {
+ ::X::change_letter_case_CANCEL
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Perform letter case change -- auxiliary procedure for '__change_letter_case'
+ # @return void
+ proc change_letter_case_OK {} {
+ change_letter_case_CANCEL ;# Close dialog window
+ change_letter_case_start ;# Perform change
+ }
+
+ ## Close "Change letter case" dialog window
+ # -- auxiliary procedure for '__change_letter_case'
+ # @return void
+ proc change_letter_case_CANCEL {} {
+ grab release .change_letter_case
+ destroy .change_letter_case
+ }
+
+ ## Set all options to the specified state
+ # -- auxiliary procedure for '__change_letter_case'
+ # @parm Char state - new state
+ # 'U' == Uppercase
+ # 'L' == Lowercase
+ # '-' == Keep
+ # @return void
+ proc change_letter_case_all_to {state} {
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ for {set i 0} {$i < 21} {incr i} {
+ set change_letter_case_options($i) $state
+ }
+ }
+
+ ## Perform letter case change -- auxiliary procedure for 'change_letter_case_OK'
+ # @return void
+ proc change_letter_case_start {} {
+ variable actualProject ;# Object: Current project
+ variable compilation_progress ;# Variable for compilation progressbar
+ variable change_letter_case_options ;# Options (which fields should be adjusted)
+
+ # Check if the current editor is not empty
+ if {
+ [$actualProject editor_procedure {} getLinesCount {}] == 1
+ &&
+ [$actualProject editor_procedure {} getLineContent 1] == {}
+ } {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "Unable to compile"] \
+ -message [mc "This editor seems to be empty"]
+ return
+ }
+
+ set compilation_progress 1 ;# Reset compilation progress variable
+
+ # Set maximum for 1st progress bar ("Finishing highlight")
+ set max [$actualProject editor_procedure {} highlight_all_count_of_iterations {}]
+ incr max
+
+ # Create progress dialog window
+ set win [toplevel .change_letter_case_dialog -class {Progress dialog} -bg {#EEEEEE}]
+
+ # Create label and progress bar
+ set main_frame [frame $win.main_frame]
+ pack [label $main_frame.header -text [mc "Finishing highlight ..."]] \
+ -pady 10 -padx 20 -anchor w
+ pack [ttk::progressbar $main_frame.progress_bar \
+ -maximum $max \
+ -mode determinate \
+ -variable {X::compilation_progress} \
+ -length 430 \
+ ] -fill y
+ pack $main_frame -fill x -expand 1
+ pack [ttk::button $win.abort_button \
+ -text [mc "Abort"] \
+ -image ::ICONS::16::cancel \
+ -compound left \
+ -command {X::change_letter_case_abort} \
+ ]
+
+ # Create options list
+ for {set i 0} {$i < 21} {incr i} {
+ lappend options $change_letter_case_options($i)
+ }
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::change_case
+ wm title $win [mc "Change letter case - MCU 8051 IDE"]
+ wm minsize $win 450 70
+ wm protocol $win WM_DELETE_WINDOW {
+ exportToX_abort
+ }
+ wm transient $win .
+ catch {grab $win}
+ raise $win
+ update
+
+ # Finish highlight
+ $actualProject editor_procedure {} highlight_all {}
+ if {![winfo exists $win]} {return}
+
+ # Determinate maximum value for the 2nd progress bar ("Formating")
+ set max [$actualProject editor_procedure {} change_letter_case_get_count_of_iterations "{$options}"]
+ incr max
+ # Change progress bar header label
+ $main_frame.header configure -text [mc "Formating ..."]
+ $main_frame.progress_bar configure -maximum $max
+
+ set compilation_progress 1 ;# Reset compilation progress variable
+ update
+
+ # Finaly perform letter case change
+ $actualProject editor_procedure {} change_letter_case [list $options]
+
+ # Close the window
+ catch {
+ grab release .change_letter_case_dialog
+ destroy .change_letter_case_dialog
+ }
+ }
+
+ ## Abort letter case change-- auxiliary procedure for 'change_letter_case_start'
+ # @return void
+ proc change_letter_case_abort {} {
+ variable actualProject ;# Object: Current project
+
+ # Abort the procedure in editor
+ $actualProject editor_procedure {} change_letter_case_abort_now {}
+
+ # Close progress dialog
+ grab release .change_letter_case_dialog
+ destroy .change_letter_case_dialog
+ }
+
+ ## Switch to the previous editor in the current project
+ # @return void
+ proc __prev_editor {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Switch editor
+ $actualProject prev_editor
+
+ # Finalize
+ set critical_procedure_in_progress 0
+
+ }
+
+ ## Switch to the next editor in the current project
+ # @return void
+ proc __next_editor {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Switch editor
+ $actualProject next_editor
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Change EOL character in the current editor
+ # @return void
+ proc change_EOL {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Change EOL
+ $actualProject change_EOL
+ }
+
+ ## Change character encoding in the current editor
+ # @return void
+ proc change_encoding {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[simulator_must_be_disabled 0]} {return}
+ if {$critical_procedure_in_progress} {return}
+
+ # Change encoding
+ $actualProject change_encoding
+ }
+
+ ## Switch between RO and RW modes in the current editor
+ # @return void
+ proc switch_editor_RO_MODE {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject switch_editor_RO_MODE
+ }
+
+ ## Prepare window "Project details"
+ # @parm Object project - project object descriptor
+ # @return void
+ proc create_project_details {project} {
+ variable openedProjects ;# List of opened projects (Object references)
+ variable PROJECTDETAILSWIN ;# ID of project details window
+ variable projectdetails_last_project ;# Project object of the last project details window
+
+ # Check if the given project is a valid object reference
+ if {[lsearch -ascii -exact $openedProjects $project] == -1} {
+ return
+ }
+
+ if {$projectdetails_last_project == $project} {
+ project_details_move
+ return
+ } {
+ set projectdetails_last_project $project
+ }
+
+ # Destroy previous window
+ catch {destroy $PROJECTDETAILSWIN}
+
+ set authors [$project cget -G_information_authors]
+ set authors [join [split $authors "\n"] {, }]
+ if {[string length $authors] > 40} {
+ set authors [string range $authors 0 36]
+ append authors {...}
+ }
+
+ # Create window
+ set PROJECTDETAILSWIN [frame .project_details_win -bg {#BBBBFF}]
+ set project_details_win [frame $PROJECTDETAILSWIN.frm -bg {#FFFFFF}]
+ bind $PROJECTDETAILSWIN <Button-1> "catch {destroy $PROJECTDETAILSWIN}"
+
+ # Create header
+ pack [label $project_details_win.header \
+ -text [$project cget -projectName] \
+ -justify left -pady 0 -padx 15 \
+ -compound left -anchor w -bg {#BBBBFF} \
+ -image ::ICONS::16::kcmdevices \
+ ] -fill x
+
+ # Create main frame (containing everything except the header)
+ set main_frame [frame $project_details_win.main_frame -bg {#FFFFFF}]
+
+ # File name
+ grid [label $main_frame.filename_label \
+ -text [mc "File name:"] \
+ -fg {#880033} -bg {#FFFFFF} \
+ -anchor w -pady 0 \
+ ] -row 0 -column 0 -sticky w -pady 0
+ grid [label $main_frame.filename_value \
+ -text [$project cget -projectFile] \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 0 -column 1 -sticky w -pady 0
+ # Path
+ grid [label $main_frame.path_label \
+ -text [mc "Path:"] -fg {#880033} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 1 -column 0 -sticky w -pady 0
+ grid [label $main_frame.path_value \
+ -text [$project cget -projectPath] \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 1 -column 1 -sticky w -pady 0
+
+ # Separator
+ grid [ttk::separator $main_frame.sep0 -orient horizontal \
+ ] -row 2 -column 0 -columnspan 2 -sticky we -pady 5
+
+ # MCU:
+ grid [label $main_frame.family_label \
+ -text [mc "MCU:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 3 -column 0 -sticky w -pady 0
+ grid [label $main_frame.family_value \
+ -text [$project cget -P_option_mcu_type]\
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 3 -column 1 -sticky w -pady 0
+ # XDATA:
+ grid [label $main_frame.xdata_label \
+ -text [mc "XDATA:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 4 -column 0 -sticky w -pady 0
+ grid [label $main_frame.xdata_value \
+ -text "[$project cget -P_option_mcu_xdata] B" \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 4 -column 1 -sticky w -pady 0
+ # XCODE:
+ grid [label $main_frame.xcode_label \
+ -text [mc "XCODE:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 5 -column 0 -sticky w -pady 0
+ grid [label $main_frame.xcode_value \
+ -text "[$project cget -P_option_mcu_xcode] B" \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 5 -column 1 -sticky w -pady 0
+ # Clock:
+ grid [label $main_frame.clock_label \
+ -text [mc "Clock:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 6 -column 0 -sticky w -pady 0
+ grid [label $main_frame.clock_value \
+ -text "[$project cget -P_option_clock] kHz" \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 6 -column 1 -sticky w -pady 0
+
+ set more_details_avaliable 0
+ # Version
+ if {[string length [$project cget -P_information_version]]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.ver_label \
+ -text [mc "Version:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 8 -column 0 -sticky w -pady 0
+ grid [label $main_frame.ver_value \
+ -text [$project cget -P_information_version] \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 8 -column 1 -sticky w -pady 0
+ }
+ # Date
+ if {[string length [$project cget -P_information_date]]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.date_label \
+ -text [mc "Date:"] -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 9 -column 0 -sticky w -pady 0
+ grid [label $main_frame.date_value \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ -text [$project cget -P_information_date] \
+ ] -row 9 -column 1 -sticky w -pady 0
+ }
+ # Licence
+ if {[string length [$project cget -G_information_licence]]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.licence_label \
+ -text [mc "Licence:"] \
+ -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 10 -column 0 -sticky w -pady 0
+ grid [label $main_frame.licence_value \
+ -text [$project cget -G_information_licence] \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 10 -column 1 -sticky w -pady 0
+ }
+ # Copyright
+ if {[string length [$project cget -G_information_copyright]]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.copyright_label \
+ -text [mc "Copyright:"] \
+ -fg {#0000AA} -bg {#FFFFFF} \
+ -anchor w -pady 0 \
+ ] -row 11 -column 0 -sticky w -pady 0
+ grid [label $main_frame.copyright_value \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ -text [$project cget -G_information_copyright] \
+ ] -row 11 -column 1 -sticky w -pady 0
+ }
+ # Authors
+ if {[string length $authors]} {
+ set more_details_avaliable 1
+ grid [label $main_frame.authors_label \
+ -text [mc "Authors:"] \
+ -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 12 -column 0 -sticky w -pady 0
+ grid [label $main_frame.authors_value \
+ -text $authors -anchor w \
+ -pady 0 -bg {#FFFFFF} \
+ ] -row 12 -column 1 -sticky w -pady 0
+ }
+ # Separator
+ if {$more_details_avaliable} {
+ grid [ttk::separator $main_frame.sep1 -orient horizontal \
+ ] -row 7 -column 0 -columnspan 2 -sticky we -pady 5
+ }
+
+ # Pack main frame
+ grid columnconfigure $main_frame 0 -minsize 80
+ pack $main_frame -fill both -expand 1 -padx 8 -pady 3
+ pack $project_details_win -fill both -expand 1 -padx 2 -pady 2
+
+ # Show window "Project details"
+ project_details_move
+ }
+
+ ## Move window "Project details"
+ # @return void
+ proc project_details_move args {
+ variable PROJECTDETAILSWIN ;# ID of project details window
+
+ # Show the window
+ catch {
+ place $PROJECTDETAILSWIN -anchor nw \
+ -x [expr {[winfo pointerx .] - [winfo rootx .] + 20}] \
+ -y [expr {[winfo pointery .] - [winfo rooty .] + 20}]
+ update
+ raise $PROJECTDETAILSWIN
+ }
+ }
+
+ ## Hide window "Project details"
+ # @return void
+ proc close_project_details args {
+ variable PROJECTDETAILSWIN ;# ID of project details window
+ variable projectdetails_last_project ;# Project object of the last project details window
+
+ # Hide the window
+ catch {place forget $PROJECTDETAILSWIN}
+ }
+
+ ## Invokes menu for manipulating project tab
+ # @parm Int x - Absolute X coordinate of mouse pointer
+ # @parm Int y - Absolute Y coordinate of mouse pointer
+ # Object project - project object descriptor
+ proc invoke_project_menu {x y project} {
+ variable projectmenu ;# ID of Popup menu for project tabs
+ variable projectmenu_project ;# Object: project selected by project popup menu
+ variable openedProjects ;# List of opened projects (Object references)
+
+ # Check if the given project exists (due to a bug in BWidget-1.7)
+ if {[lsearch -ascii -exact $openedProjects $project] == -1} {
+ puts stderr "Internal error detected: Please install BWidget-1.8 or higher"
+ return
+ }
+
+ # Enable/Disable menu entries
+ set tabindex [.mainFrame.mainNB index $project]
+ if {!$tabindex} {
+ $projectmenu entryconfigure [::mc "Move to beginning"] -state disabled
+ $projectmenu entryconfigure [::mc "Move left"] -state disabled
+ } {
+ $projectmenu entryconfigure [::mc "Move to beginning"] -state normal
+ $projectmenu entryconfigure [::mc "Move left"] -state normal
+ }
+ if {$tabindex == ([llength [.mainFrame.mainNB pages]] - 1)} {
+ $projectmenu entryconfigure [::mc "Move right"] -state disabled
+ $projectmenu entryconfigure [::mc "Move to end"] -state disabled
+ } {
+ $projectmenu entryconfigure [::mc "Move right"] -state normal
+ $projectmenu entryconfigure [::mc "Move to end"] -state normal
+ }
+
+ # Invoke the menu and set project identifier
+ set projectmenu_project $project
+ tk_popup $projectmenu $x $y
+ }
+
+ ## Function for project popup menu
+ # -- Save this project
+ # @return void
+ proc __project_pmenu_save {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set tmp $actualProject
+ set actualProject $projectmenu_project
+ set tmp_idx $actualProjectIdx
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+
+ __proj_save
+
+ set actualProject $tmp
+ set actualProjectIdx $tmp_idx
+ }
+
+ ## Function for project popup menu
+ # -- Edit this project
+ # @return void
+ proc __project_pmenu_edit {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set tmp $actualProject
+ set actualProject $projectmenu_project
+ set tmp_idx $actualProjectIdx
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+
+ __proj_edit
+
+ set actualProject $tmp
+ set ctualProjectIdx $tmp_idx
+ }
+
+ ## Function for project popup menu
+ # -- Close this project
+ # @return void
+ proc __project_pmenu_close {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ # Adjust variables identifing current project
+ set tmp $actualProject
+ set tmp_idx $actualProjectIdx
+ set actualProject $projectmenu_project
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+ if {$actualProjectIdx == $tmp_idx} {
+ set this_closed 1
+ } {
+ set this_closed 0
+ }
+
+ # Close project
+ __proj_close
+ }
+
+ ## Function for project popup menu
+ # -- Close this project without saving
+ # @return void
+ proc __project_pmenu_close_imm {} {
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ # Adjust variables identifing current project
+ set tmp $actualProject
+ set tmp_idx $actualProjectIdx
+ set actualProject $projectmenu_project
+ set actualProjectIdx [lsearch -exact -ascii $openedProjects $actualProject]
+ if {$actualProjectIdx == $tmp_idx} {
+ set this_closed 1
+ } {
+ set this_closed 0
+ }
+
+ # Close project and restore variables identifing current project
+ if {[__proj_close_imm] && !$this_closed} {
+ if {$tmp_idx > $actualProjectIdx} {
+ incr tmp_idx -1
+ }
+ set actualProjectIdx $tmp_idx
+ set actualProject $tmp
+ }
+ }
+
+ ## Function for project popup menu
+ # -- Move this tab left
+ # @return void
+ proc __project_move_to_left {} {
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set index [.mainFrame.mainNB index $projectmenu_project]
+ if {!$index} {
+ return
+ }
+
+ incr index -1
+ .mainFrame.mainNB move $projectmenu_project $index
+ }
+
+ ## Function for project popup menu
+ # -- Move this tab right
+ # @return void
+ proc __project_move_to_right {} {
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set index [.mainFrame.mainNB index $projectmenu_project]
+ if {$index == ([llength [.mainFrame.mainNB index pages]] - 1)} {
+ return
+ }
+
+ incr index
+ .mainFrame.mainNB move $projectmenu_project $index
+ }
+
+ ## Function for project popup menu
+ # -- Move this tab to the beginning
+ # @return void
+ proc __project_move_to_beginning {} {
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ if {![.mainFrame.mainNB index $projectmenu_project]} {
+ return
+ }
+ .mainFrame.mainNB move $projectmenu_project 0
+ }
+
+ ## Function for project popup menu
+ # -- Move this tab to the end
+ # @return void
+ proc __project_move_to_end {} {
+ variable projectmenu_project ;# Object: project selected by project popup menu
+
+ set end [expr {[llength [.mainFrame.mainNB pages]] - 1}]
+ if {[.mainFrame.mainNB index $projectmenu_project] == $end} {
+ return
+ }
+
+ .mainFrame.mainNB move $projectmenu_project $end
+ }
+
+ ## Invert flag "allow breakpoints"
+ # @return void
+ proc __invert_allow_breakpoints {} {
+ set ::CONFIG(BREAKPOINTS_ALLOWED) [expr {!$::CONFIG(BREAKPOINTS_ALLOWED)}]
+ }
+
+ ## Refresh bookmarks in filesystem browser in all projects
+ # @return void
+ proc refresh_bookmarks_in_fs_browsers {} {
+ variable openedProjects ;# List of opened projects (Object references)
+
+ foreach project $openedProjects {
+ $project filelist_fsb_refresh_bookmarks
+ }
+ }
+
+ ## Invoke dialog "Tip of the day"
+ # @return void
+ proc __tip_of_the_day {} {
+ ::Tips::show_tip_of_the_day_win
+ }
+
+ ## Refresh program pointer in CODE memory hexadecimal editor
+ # @parm Object project - Project object
+ # @parm Int new_PC - New value of PC (-1 after reset)
+ # @return void
+ proc program_counter_changed {project new_PC} {
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ set opcode [$project getCode $new_PC]
+ if {[lsearch ${CompilerConsts::defined_OPCODE} $opcode] == -1} {
+ set ins_length 1
+ } {
+ set ins_length [lindex $CompilerConsts::Opcode($opcode) 2]
+ }
+ [lindex $code_mem_window_objects $idx] move_program_pointer $new_PC $ins_length
+ }
+ }
+
+ ## Refresh program pointer in CODE memory hexadecimal editor
+ # @parm Object project - Project object
+ # @parm Int new_PC - New value of PC (-1 after reset)
+ # @return void
+ proc code_hex_editor_directly_move_program_pointer {project new_PC} {
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ if {$new_PC != -1} {
+ set opcode [$project getCode $new_PC]
+ if {[lsearch ${CompilerConsts::defined_OPCODE} $opcode] == -1} {
+ set ins_length 1
+ } {
+ set ins_length [lindex $CompilerConsts::Opcode($opcode) 2]
+ }
+ } {
+ set ins_length 0
+ }
+ [lindex $code_mem_window_objects $idx] move_program_pointer_directly $new_PC $ins_length
+ }
+ }
+
+ ## Refresh the current page in CODE memory hexadecimal editor
+ # @parm Object project - Project object
+ # @return void
+ proc refresh_code_mem_window {project} {
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_code_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $code_mem_window_objects $idx] refresh
+ }
+ }
+
+ ## Refresh the current page in XDATA memory hexadecimal editor
+ # @parm Object project - Project object
+ # @return void
+ proc refresh_xram_mem_window {project} {
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_xdata_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $xdata_mem_window_objects $idx] refresh
+ }
+ }
+
+ ## Refresh the current page in EDATA memory hexadecimal editor
+ # @parm Object project - Project object
+ # @return void
+ proc refresh_eram_mem_window {project} {
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_eram_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $eram_window_objects $idx] refresh
+ }
+ }
+
+ ## Refresh the current page in data EEPROM hexadecimal editor
+ # @parm Object project - Project object
+ # @return void
+ proc refresh_eeprom_mem_window {project} {
+ variable opended_eeprom_mem_windows ;# List of project object with opened ERAM hex editor
+ variable eeprom_mem_window_objects ;# List of ERAM hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $eeprom_mem_window_objects $idx] refresh
+ }
+ }
+
+ ## Clear background highlight for certain cell in hexeditor of data EEPROM
+ # @parm Int addr - Register address (absolute)
+ # @parm Object project - Project object
+ # @return void
+ proc sync_eeprom_clear_bg_hg {addr project} {
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ [lindex $eeprom_mem_window_objects $idx] set_bg_hg_clr $addr 0
+ }
+ }
+
+ ## Synchronize the specified cell in data EEPROM hexadecimal editor
+ # @parm String addr - Hexadecimal address (0 - FFFF)
+ # @parm Int hg -
+ # 1 == highlight background
+ # 0 == do not affect bg. highlight
+ # @parm Object project - Project object
+ # @return void
+ proc sync_eeprom_mem_window {addr hg project} {
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows [string trimleft $project {:}]]
+ if {$idx != -1} {
+ set obj [lindex $eeprom_mem_window_objects $idx]
+ $obj reg_sync $addr
+ if {$hg} {
+ $obj set_bg_hg_clr [expr "0x$addr"] 1
+ }
+ }
+ }
+
+ ## Synchronize the specified cell in XDATA/ERAM hexadecimal editor
+ # @parm String addr - Hexadecimal address (0 - FFFF)
+ # @parm Object project - Project object
+ # @return void
+ proc sync_xram_mem_window {addr project} {
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+
+ set project [string trimleft $project {:}]
+
+ # Syncronize XDATA
+ set idx [lsearch -exact -ascii $opended_xdata_mem_windows $project]
+ if {$idx != -1} {
+ [lindex $xdata_mem_window_objects $idx] reg_sync $addr
+ }
+ # Syncronize ERAM
+ set idx [lsearch -exact -ascii $opended_eram_windows $project]
+ if {$idx != -1} {
+ [lindex $eram_window_objects $idx] reg_sync $addr
+ }
+ }
+
+ ## Show/Close CODE memory hexadecimal editor
+ # @return void
+ proc __show_code_mem {} {
+ show_X_memory code
+ }
+
+ ## Show/Close XDATA memory hexadecimal editor
+ # @return void
+ proc __show_ext_mem {} {
+ show_X_memory xdata
+ }
+
+ ## Show/Close ERAM hexadecimal editor
+ # @return void
+ proc __show_exp_mem {} {
+ show_X_memory eram
+ }
+
+ ## Show/Close ERAM hexadecimal editor
+ # @return void
+ proc __show_eeprom {} {
+ show_X_memory eeprom
+ }
+
+ ## Invoke hexeditor dialog
+ # @see __show_exp_mem, __show_ext_mem, __show_code_mem, __show_eeprom
+ # @parm String type - memory type (one of {eeprom xdata code eram})
+ # @return void
+ proc show_X_memory {type} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+
+ if {$project_menu_locked} {return}
+
+ # Determinate index of the currently opened hex editor for the current project
+ switch -- $type {
+ {xdata} {
+ if {![$actualProject cget -P_option_mcu_xdata]} {
+ return
+ }
+ set idx [lsearch -exact -ascii $opended_xdata_mem_windows $actualProject]
+ set list_of_opened {opended_xdata_mem_windows}
+ set window_objects {xdata_mem_window_objects}
+ }
+ {eram} {
+ if {![lindex [$actualProject cget -procData] 8]} {
+ return
+ }
+ set idx [lsearch -exact -ascii $opended_eram_windows $actualProject]
+ set list_of_opened {opended_eram_windows}
+ set window_objects {eram_window_objects}
+ }
+ {code} {
+ set idx [lsearch -exact -ascii $opended_code_mem_windows $actualProject]
+ set list_of_opened {opended_code_mem_windows}
+ set window_objects {code_mem_window_objects}
+ }
+ {eeprom} {
+ if {![lindex [$actualProject cget -procData] 32]} {
+ return
+ }
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows $actualProject]
+ set list_of_opened {opended_eeprom_mem_windows}
+ set window_objects {eeprom_mem_window_objects}
+ }
+ }
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Close
+ if {$idx != -1} {
+ close_hexedit $type $actualProject
+ set critical_procedure_in_progress 0
+ return
+ # Show
+ } {
+ set object "hexedit_${type}_${actualProject}"
+ HexEditDlg ::$object $actualProject $type
+ lappend $list_of_opened $actualProject
+ lappend $window_objects $object
+ }
+
+ # Set filename for code memory and program pointer
+ if {$type == {code}} {
+ set filename [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ if {[lindex $filename 1] == {}} {
+ set filename [$actualProject editor_procedure {} getFileName {}]
+ }
+ set filename [file join [lindex $filename 0] [lindex $filename 1]]
+
+ set ext [file extension $filename]
+ set filename [file rootname $filename]
+ if {$ext == {.c} || $ext == {.h} || $ext == {.cxx} || $ext == {.cpp} || $ext == {.cc}} {
+ append filename {.ihx}
+ } {
+ append filename {.hex}
+ }
+
+ ::$object set_filename $filename
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ program_counter_changed $actualProject [$actualProject getPC]
+ }
+
+ # Highlight cells which are beeing written (EEPROM only)
+ } elseif {$type == {eeprom}} {
+ foreach addr [$actualProject simulator_get_eeprom_beeing_written] {
+ ::$object set_bg_hg_clr $addr 1
+ }
+ }
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Synchronize cell in data EEPROM write buffer with simulator engine
+ # @parm Int addr - Cell address (0..31)
+ # @parm Object project - Project object
+ # @return void
+ proc sync_eeprom_write_buffer {addr project} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+
+ if {$project_menu_locked} {return}
+ set idx [lsearch -exact -ascii $opended_eeprom_wr_bf_windows [string trimleft $project {:}]]
+ if {$idx == -1} {return}
+ [string replace [lindex $eeprom_wr_bf_window_objects $idx] 0 0] \
+ setValue $addr [$project getEepromWrBufDEC $addr]
+ }
+
+ ## Clear data EEPROM write buffer
+ # @parm Object project - Project object
+ # @return void
+ proc clear_eeprom_write_buffer {project} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+
+ if {$project_menu_locked} {return}
+ set idx [lsearch -exact -ascii $opended_eeprom_wr_bf_windows [string trimleft $project {:}]]
+ if {$idx == -1} {return}
+ set hexeditor [string replace [lindex $eeprom_wr_bf_window_objects $idx] 0 0]
+ for {set addr 0} {$addr < 32} {incr addr} {
+ $hexeditor setValue $addr {}
+ }
+ }
+
+ ## Set offset for data EEPROM write buffer window
+ # @parm String offset - New offset (format: 0xXXXX or {})
+ # @parm Object project - Project object
+ # @return void
+ proc eeprom_write_buffer_set_offset {offset project} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+
+ if {$project_menu_locked} {return}
+ set idx [lsearch -exact -ascii $opended_eeprom_wr_bf_windows [string trimleft $project {:}]]
+ if {$idx == -1} {return}
+ if {$offset == {}} {
+ set offset [mc "< Undefined >"]
+ }
+ [lindex $eeprom_wr_bf_window_objects $idx].offset_frame.val configure -text $offset
+ }
+
+ ## Binding for pseudo-events <cell_enter> and <cell_leave> in data EEPROM write buffer hexeditor
+ # Set value of curosor label at the bottom of the window
+ # This function takes list of attributes with any length gerater
+ #+ than one but only first two are significant
+ # @parm Widget - Data EEPROM write buffer window
+ # @parm Int - Cell address
+ # @return void
+ proc eeprom_write_buffer_change_cursor_addr args {
+ variable foo_procedure_in_progress ;# Bool: Disables some non-critical procedures
+
+ if {$foo_procedure_in_progress} {return}
+ set foo_procedure_in_progress 1
+
+ # Parse input arguments
+ set win [lindex $args 0]
+ set addr [lindex $args 1]
+
+ # Increment the given address by offset
+ set offset [$win.offset_frame.val cget -text]
+ if {$addr != {} && [regexp {^0x[0-9a-fA-F]{4}$} $offset]} {
+ incr addr [expr "$offset"]
+ }
+
+ # Modify content of cursor label
+ if {$addr == {}} {
+ $win.bottom_frame.cur_val configure -text { }
+ } {
+ set addr [format %X $addr]
+ set len [string length $addr]
+ if {$len < 4} {
+ set addr "[string repeat {0} [expr {4 - $len}]]$addr"
+ }
+ $win.bottom_frame.cur_val configure -text "0x$addr"
+ }
+
+ set foo_procedure_in_progress 0
+ }
+
+ ## Invoke hexeditor with data EEPROM write buffer
+ # @return void
+ proc __show_eeprom_write_buffer {} {
+ variable actualProject ;# Object: Current project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+ variable eeprom_wr_buf_counter ;# Counter of EEPROM write buffer hex editor objects
+
+ # Check if this function call is valid
+ if {$project_menu_locked} {return}
+ if {![lindex [$actualProject cget -procData] 32]} {
+ return
+ }
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Check if the dialog is not already opened
+ if {[lsearch -exact -ascii $opended_eeprom_wr_bf_windows $actualProject] != -1} {
+ close_hexedit eeprom_wr_bf $actualProject
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Create dialog window
+ incr eeprom_wr_buf_counter
+ set win [toplevel .eeprom_write_buffer_${eeprom_wr_buf_counter} -class {EEPROM} -bg {#EEEEEE}]
+
+ # Adjust NS variables
+ lappend eeprom_wr_bf_window_objects $win
+ lappend opended_eeprom_wr_bf_windows $actualProject
+
+ # Create window header
+ pack [label $win.header \
+ -text [mc "%s - EEPROM write buffer" $actualProject] \
+ ] -fill x -pady 10
+
+ # Create offset label
+ set offset_frame [frame $win.offset_frame]
+ pack [label $offset_frame.lbl \
+ -text [mc "OFFSET = "] \
+ -font [font create \
+ -size -17 -weight bold \
+ -family {helvetica}] \
+ ] -side left
+ pack [label $offset_frame.val \
+ -fg {#0000FF} \
+ -font [font create \
+ -size -17 -weight bold \
+ -family {helvetica}] \
+ ] -side left
+ pack $offset_frame -anchor w
+
+ # Create middle frame (hexeditor)
+ set hexeditor [HexEditor ::eeprom_write_buffer_${eeprom_wr_buf_counter} \
+ $win.mainframe 8 4 2 hex 1 0 4 32 \
+ ]
+ $hexeditor showHideScrollbar 0
+ $hexeditor bindCellValueChanged "$actualProject setEepromWrBufDEC"
+ $hexeditor bindCellEnter "::X::eeprom_write_buffer_change_cursor_addr $win"
+ $hexeditor bindCellLeave "::X::eeprom_write_buffer_change_cursor_addr $win {}"
+ for {set i 0} {$i < 32} {incr i} {
+ $hexeditor setValue $i [$actualProject getEepromWrBufDEC $i]
+ }
+ eeprom_write_buffer_set_offset [$actualProject getEepromWrOffsetDEC] $actualProject
+ $hexeditor focus_left_view
+ pack $win.mainframe
+
+ # Create bottom frame
+ set bottom_frame [frame $win.bottom_frame]
+ pack [ttk::button $bottom_frame.close_but \
+ -text [mc "Close"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "X::close_hexedit eeprom_wr_bf $actualProject" \
+ ] -side left -anchor w
+ pack [label $bottom_frame.cur_val \
+ -text { } -fg {#0000FF} \
+ -font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ ] \
+ ] -side right -anchor e -padx 5
+ pack [label $bottom_frame.cur_lbl \
+ -text [mc "Cursor: "] \
+ ] -side right -anchor e
+ pack $bottom_frame -side bottom -fill x
+
+ # Configure dialog window
+ wm iconphoto $win ::ICONS::16::kcmmemory
+ wm title $win [mc "EEPROM write buffer - %s - MCU 8051 IDE" $actualProject]
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW \
+ "X::close_hexedit eeprom_wr_bf $actualProject"
+
+ # Finalize
+ set critical_procedure_in_progress 0
+
+ }
+
+ ## Close hexadecimal editor window
+ # -- auxiliary procedure for '__show_ext_mem' and '__show_code_mem'
+ # @parm String type - Editor type ('eeprom', 'eeprom_wr_bf' 'eram', 'code' or 'xdata')
+ # @parm Object project - Project object descriptor
+ # @return void
+ proc close_hexedit {type project} {
+ variable opended_code_mem_windows ;# List of project object with opened CODE memory hex editor
+ variable code_mem_window_objects ;# List of CODE memory hex editor objects
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+ variable opended_eeprom_wr_bf_windows ;# List of project objects with opened data EEPROM write buffer editor
+ variable eeprom_wr_bf_window_objects ;# List of data EEPROM write buffer hex editor objects
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # Close CODE memory editor
+ if {$type == {code}} {
+ set opended_windows_var {opended_code_mem_windows}
+ set window_objects_var {code_mem_window_objects}
+ set opended_windows $opended_code_mem_windows
+ set window_objects $code_mem_window_objects
+
+ # Close ERAM editor
+ } elseif {$type == {eram}} {
+ set opended_windows_var {opended_eram_windows}
+ set window_objects_var {eram_window_objects}
+ set opended_windows $opended_eram_windows
+ set window_objects $eram_window_objects
+
+ # Close XDATA memory editor
+ } elseif {$type == {xdata}} {
+ set opended_windows_var {opended_xdata_mem_windows}
+ set window_objects_var {xdata_mem_window_objects}
+ set opended_windows $opended_xdata_mem_windows
+ set window_objects $xdata_mem_window_objects
+
+ # Close data EEPROM editor
+ } elseif {$type == {eeprom}} {
+ set opended_windows_var {opended_eeprom_mem_windows}
+ set window_objects_var {eeprom_mem_window_objects}
+ set opended_windows $opended_eeprom_mem_windows
+ set window_objects $eeprom_mem_window_objects
+
+ # Close EEPROM write buffer
+ } elseif {$type == {eeprom_wr_bf}} {
+ set opended_windows_var {opended_eeprom_wr_bf_windows}
+ set window_objects_var {eeprom_wr_bf_window_objects}
+ set opended_windows $opended_eeprom_wr_bf_windows
+ set window_objects $eeprom_wr_bf_window_objects
+
+ # Close project independent hexadecimal editor
+ } elseif {$type == {uni}} {
+ return
+
+ # Invalid request
+ } else {
+ return
+ }
+
+
+ # Determinate editor index
+ set idx [lsearch -exact -ascii $opended_windows $project]
+ if {$idx == -1} {return}
+ # Destroy editor object
+ if {$type == {eeprom_wr_bf}} {
+ destroy [lindex $window_objects $idx]
+ } {
+ delete object [lindex $window_objects $idx]
+ }
+ # Delete references
+ set $opended_windows_var [lreplace $opended_windows $idx $idx]
+ set $window_objects_var [lreplace $window_objects $idx $idx]
+ }
+
+ ## Adjust main window title to current project and file
+ # @return void
+ proc adjust_title {} {
+ variable actualProject ;# Object: Current project
+ set title {} ;# New title
+
+ # Project opened
+ if {$actualProject != {}} {
+ # Gain data from the project
+ if {[catch {
+ if {[$actualProject editor_procedure {} cget -modified]} {
+ append title {[modified] }
+ }
+ append title $actualProject
+ append title { : }
+ append title [$actualProject editor_procedure {} cget -filename]
+ append title { - MCU 8051 IDE}
+ wm title . $title
+
+ # Error -- default title
+ }]} {
+ wm title . ${::APPNAME}
+ }
+
+ # No project opened -- default title
+ } {
+ wm title . ${::APPNAME}
+ }
+ }
+
+ ## Clear highlight for changed registers in simulator panels
+ # @return void
+ proc __sim_clear_highlight {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+ variable opended_xdata_mem_windows ;# List of project object with opened XDATA memory hex editor
+ variable xdata_mem_window_objects ;# List of XDATA memory hex editor objects
+ variable opended_eram_windows ;# List of project object with opened ERAM hex editor
+ variable eram_window_objects ;# List of ERAM hex editor objects
+ variable opended_eeprom_mem_windows ;# List of project object with opened data EEPROM hex editor
+ variable eeprom_mem_window_objects ;# List of data EEPROM hex editor objects
+
+ if {$project_menu_locked} {return}
+ $actualProject simulator_clear_highlight
+ $actualProject rightPanel_watch_clear_highlight
+ $actualProject bitmap_clear_hg
+ $actualProject sfrmap_clear_hg
+
+ set idx [lsearch -exact -ascii $opended_xdata_mem_windows $actualProject]
+ if {$idx != -1} {
+ [lindex $xdata_mem_window_objects $idx] clear_highlight
+ }
+ set idx [lsearch -exact -ascii $opended_eram_windows $actualProject]
+ if {$idx != -1} {
+ [lindex $eram_window_objects $idx] clear_highlight
+ }
+ set idx [lsearch -exact -ascii $opended_eeprom_mem_windows $actualProject]
+ if {$idx != -1} {
+ [lindex $eeprom_mem_window_objects $idx] clear_highlight
+ }
+ }
+
+ ## Insure than simulator cursor is in editor visible area
+ # @return void
+ proc __see_sim_cursor {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[lindex $simulator_enabled $actualProjectIdx] == 1} {
+ $actualProject editor_procedure {} see_sim_cursor {}
+ }
+ }
+
+ ## Load value to PC in simulator control panel; line -> address
+ # @return void
+ proc __simulator_set_PC_by_line {} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ variable line2pc ;# Int: Selected line in source code
+ variable line2pc_jump ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable line2pc_value_lbl ;# Widget: Label containing PC value
+ variable line2pc_new_value ;# Int: Resolved address or {}
+ variable line2pc_org_line ;# Int: Original line
+ variable line2pc_line_max ;# Int: Number of lines in the source code
+ variable line2pc_ok_button ;# Widget: Button "OK"
+ variable line2pc_file_number ;# Int: File number
+
+ if {$project_menu_locked} {return}
+
+ # Check if simulator is started
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ return
+ }
+ set filename [$actualProject editor_procedure {} cget -fullFileName]
+ if {[lindex $filename 0] == {}} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "This operation cannot be performed on an untitled file"]
+ return
+ }
+ set line2pc_file_number [$actualProject simulator_get_filenumber $filename]
+ if {$line2pc_file_number == -1} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "This file does not contain any part of the running program"]
+ return
+ }
+
+ # Load some NS variables
+ set line2pc_line_max [$actualProject editor_linescount]
+ set line2pc_org_line [lindex [$actualProject simulator_getCurrentLine] 0]
+ set line2pc_new_value [$actualProject simulator_line2address $line2pc_org_line $line2pc_file_number]
+ set line2pc $line2pc_org_line
+
+ # Create dialog window
+ set win [toplevel .goto_line2pc -class [mc "Goto dialog"] -bg {#EEEEEE}]
+
+ # Create window label frame
+ label $win.header \
+ -text [mc "Line to address"] \
+ -image ::ICONS::16::goto \
+ -compound left
+
+ # Create middle frame
+ set middle_frame [frame $win.middle_frame]
+ pack [label $middle_frame.left_lbl \
+ -text [mc "PC = "] \
+ -font [font create \
+ -size -16 -weight bold \
+ -family {helvetica}] \
+ ] -side left
+ set line2pc_value_lbl [label $middle_frame.right_lbl \
+ -font [font create \
+ -size -16 -weight bold \
+ -family {helvetica}] \
+ ]
+ pack $line2pc_value_lbl -side left
+ set middle_right_frame [frame $middle_frame.right_frame]
+ pack [radiobutton $middle_right_frame.jump_rabut \
+ -variable ::X::line2pc_jump \
+ -value 1 -text [mc "Program jump"] \
+ ] -anchor w
+ pack [radiobutton $middle_right_frame.call_rabut \
+ -variable ::X::line2pc_jump \
+ -value 0 -text [mc "Subprogram call"] \
+ ] -anchor w
+ pack $middle_right_frame -side right
+ pack $middle_frame -padx 5 -fill x -pady 5
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $win.buttonFrame]
+ set line2pc_ok_button [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {X::line2pc_OK} \
+ ]
+ pack $line2pc_ok_button -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {X::line2pc_CANCEL} \
+ ] -side left
+ pack $buttonFrame -after $middle_frame -pady 5
+
+ ## Create top frame
+ set topFrame [ttk::labelframe $win.topFrame -labelwidget $win.header -relief flat]
+ pack $topFrame -expand 1 -fill x -before $middle_frame -padx 5 -pady 5
+ # Create scale widget
+ pack [ttk::scale $topFrame.scale \
+ -from 1 \
+ -to $line2pc_line_max \
+ -orient horizontal \
+ -variable ::X::line2pc \
+ -command "
+ set ::X::line2pc \[expr {int(\${::X::line2pc})}\]
+ $topFrame.spinbox selection range 0 end
+ #" \
+ ] -side left -expand 1 -fill x -padx 2
+ DynamicHelp::add $topFrame.scale \
+ -text [mc "Graphical representation of the line where to go"]
+ # Create spinbox widget
+ pack [spinbox $topFrame.spinbox \
+ -from 1 -to $line2pc_line_max \
+ -textvariable X::line2pc \
+ -validate all \
+ -vcmd {X::line2pc_validate [expr {int(%P)}] %W} \
+ -width 4 \
+ -command "$topFrame.spinbox selection range 0 end ;#" \
+ ] -side left
+ DynamicHelp::add $topFrame.spinbox -text [mc "Line where to go"]
+
+ # Events binding (Enter == Ok, Esc == CANCEL)
+ bind $win <KeyRelease-Return> {X::line2pc_OK; break}
+ bind $win <KeyRelease-KP_Enter> {X::line2pc_OK; break}
+ bind $win <KeyRelease-Escape> {X::line2pc_CANCEL; break}
+
+ # Focus on the Spinbox
+ focus $topFrame.spinbox
+ $topFrame.spinbox selection range 0 end
+
+ # Nessesary window manager options -- modal window
+ wm iconphoto $win ::ICONS::16::exec
+ wm title $win [mc "Line to address"]
+ wm minsize $win 350 100
+ wm protocol $win WM_DELETE_WINDOW {
+ X::line2pc_CANCEL
+ }
+ catch {grab $win}
+ raise $win
+ tkwait window $win
+ }
+
+ ## Validate content od spinbox in dialog "Line to address"
+ # @parm String content - String to validate
+ # @return Bool - result
+ proc line2pc_validate {content line2pc_spinbox} {
+ variable actualProject ;# Object: Current project
+
+ variable line2pc ;# Int: Selected line in source code
+ variable line2pc_value_lbl ;# Widget: Label containing PC value
+ variable line2pc_new_value ;# Int: Resolved address or {}
+ variable line2pc_org_line ;# Int: Original line
+ variable line2pc_line_max ;# Int: Number of lines in the source code
+ variable line2pc_ok_button ;# Widget: Button "OK"
+ variable line2pc_file_number ;# Int: File number
+
+ # Validate the given string
+ if {![string is digit $content] || $content > $line2pc_line_max || $content < 0} {
+ $line2pc_spinbox configure -bg {#FFFFFF}
+ return 0
+ }
+
+ # Try to determinate address in program memory
+ set content [expr $content]
+ set line2pc_new_value [$actualProject simulator_line2address $content $line2pc_file_number]
+
+ # Fail
+ if {$line2pc_new_value == {}} {
+ # Adjust PC value label
+ $line2pc_value_lbl configure \
+ -fg {#DD0000} \
+ -text [mc "Unable to resolve"]
+
+ code_hex_editor_directly_move_program_pointer $actualProject -1
+ $actualProject editor_procedure {} unset_simulator_line {} ;# Adjust editor
+ $line2pc_ok_button configure -state disabled ;# Adjust Ok button
+ $line2pc_spinbox configure -bg {#FFCCCC} ;# Adjust SpinBox
+
+ # Success
+ } {
+ # Translate address to hexadecimal system
+ set addr_in_hex [format %X $line2pc_new_value]
+ set len [string length $addr_in_hex]
+ if {$len < 4} {
+ set addr_in_hex "[string repeat {0} [expr {4 - $len}]]$addr_in_hex"
+ }
+ $line2pc_value_lbl configure \
+ -fg {#00DD00} \
+ -text "0x$addr_in_hex"
+
+ # Adjust editor
+ code_hex_editor_directly_move_program_pointer $actualProject $line2pc_new_value
+ $actualProject move_simulator_line [list $content $line2pc_file_number]
+ $line2pc_ok_button configure -state normal ;# Adjust Ok button
+ $line2pc_spinbox configure -bg {#CCFFCC} ;# Adjust SpinBox
+ }
+ return 1
+ }
+
+ ## Safely close dialog "Line to address"
+ # @return void
+ proc line2pc_safely_close {} {
+ if {[winfo exists .goto_line2pc]} {
+ grab release .goto_line2pc
+ destroy .goto_line2pc
+ }
+ }
+
+ ## Cancel dialog "Line to address"
+ # @return void
+ proc line2pc_CANCEL {} {
+ variable line2pc_org_line ;# Int: Original line
+ variable actualProject ;# Object: Current project
+
+ if {$line2pc_org_line == {}} {
+ $actualProject editor_procedure {} unset_simulator_line {}
+ } {
+ $actualProject move_simulator_line $line2pc_org_line
+ }
+ code_hex_editor_directly_move_program_pointer $actualProject -1
+
+ grab release .goto_line2pc
+ destroy .goto_line2pc
+ }
+
+ ## Confirm dialog "Line to address"
+ # @return void
+ proc line2pc_OK {} {
+ variable line2pc_new_value ;# Int: Resolved address or {}
+ variable actualProject ;# Object: Current project
+ variable line2pc_jump ;# Bool: Perform program jump (1) or subprogram call (0)
+ variable line2pc ;# Int: Selected line in source code
+
+ if {$line2pc_new_value == {}} {
+ line2pc_CANCEL
+ return
+ }
+
+ $actualProject move_simulator_line $line2pc
+ if {$line2pc_jump} {
+ $actualProject setPC $line2pc_new_value
+ } {
+ $actualProject simulator_subprog_call $line2pc_new_value
+ }
+ code_hex_editor_directly_move_program_pointer $actualProject -1
+ $actualProject Simulator_sync_PC_etc
+
+ grab release .goto_line2pc
+ destroy .goto_line2pc
+ }
+
+ ## Switch to the previous editor in the current project (from editor statusbar popup menu)
+ # @return void
+ proc __prev_editor_from_pmenu {} {
+ variable actualProject ;# Object: Current project
+ variable selectedView ;# Int: Selected editor view
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Switch editor
+ $actualProject filelist_editor_selected $selectedView
+ $actualProject prev_editor
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Switch to the next editor in the current project (from editor statusbar popup menu)
+ # @return void
+ proc __next_editor_from_pmenu {} {
+ variable actualProject ;# Object: Current project
+ variable selectedView ;# Int: Selected editor view
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Switch editor
+ $actualProject filelist_editor_selected $selectedView
+ $actualProject next_editor
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Switch to editor command line
+ # @return void
+ proc __switch_to_cmd_line {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject cmd_line_on
+ }
+
+ ## Split editor vertical
+ # @return void
+ proc __split_vertical {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject split_vertical
+ }
+
+ ## Split editor horizontal
+ # @return void
+ proc __split_horizontal {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject split_horizontal
+ }
+
+ ## Close current view (editor) from editor statusbar popup menu
+ # @return void
+ proc __close_current_view_from_pmenu {} {
+ variable selectedView ;# Int: Selected editor view
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject close_current_view $selectedView
+ }
+
+ ## Close current view (editor)
+ # @return void
+ proc __close_current_view {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject close_current_view {}
+ }
+
+ ## Enable / Disable stepback controls
+ # @parm Bool bool - 1 == enable; 0 == disable
+ # @return void
+ proc stepback_button_set_ena {bool} {
+ variable actualProject ;# Object: Current project
+
+ if {$bool != 0} {
+ set boot 1
+ }
+ $actualProject stepback_button_set_ena $bool
+ ena_dis_menu_buttons $bool {{{.mainMenu.simulator} {{Step back}}}}
+ ena_dis_iconBar_buttons $bool .mainIconBar. {stepback}
+ }
+
+ ## Hibernate running program to a file
+ # This function also invokes file selection dialog to select target file.
+ # @return void
+ proc __hibernate {} {
+ hibernate_or_resume 1
+ }
+
+ ## Resume hibernated program
+ # This function also invokes file selection dialog to select source file.
+ # @return void
+ proc __resume {} {
+ hibernate_or_resume 0
+ }
+
+ ## Hibernate running program // Resume hibernated program
+ # @parm Bool hib_res - 1 == Hiberanate; 0 == Resume
+ # @return void
+ proc hibernate_or_resume {hib_res} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable critical_procedure_in_progress ;# Bool: Disables procedures which takes a long time
+
+ # Simulator must be engaged for this function
+ if {$project_menu_locked} {return}
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ return
+ }
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ set sourcefile [list \
+ [$actualProject cget -projectPath] \
+ [$actualProject cget -P_option_main_file] \
+ ]
+ if {[lindex $sourcefile 1] == {}} {
+ set sourcefile [$actualProject editor_procedure {} getFileName {}]
+ }
+ set sourcefile [file join [lindex $sourcefile 0] [lindex $sourcefile 1]]
+ set initialfile [file rootname [file tail $sourcefile]]
+ if {$hib_res} {
+ set title [mc "Hibernate running program - MCU 8051 IDE"]
+ set cmd {__hibernate_to}
+ } {
+ set title [mc "Resume hibernated program - MCU 8051 IDE"]
+ set cmd {__resume_from}
+ }
+
+ # Invoke file selection dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title $title -initialfile $initialfile \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{MCU 8051 IDE Hibernated program} {*.m5ihib} }
+ {{All files} {*} }
+ }
+
+ # Open file after press of OK button
+ fsd setokcmd "
+ ::X::fsd deactivate
+ ::X::$cmd \[X::fsd get\] {$sourcefile}
+ "
+
+ # Activate FSD
+ fsd activate
+
+ # Finalize
+ set critical_procedure_in_progress 0
+ }
+
+ ## Hibernate running program to the given file
+ # @parm String filename - Target file
+ # @parm String sourcefile - Source file
+ # @return void
+ proc __hibernate_to {filename sourcefile} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ # Simulator must be engaged for this function
+ if {$project_menu_locked} {return}
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ return
+ }
+
+ # Adjust the given name of the target file
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ if {[file extension $filename] == {}} {
+ append filename {.m5ihib}
+ }
+ set filename [file normalize $filename]
+
+ # Create backup copy the target file
+ if {[file exists $filename] && [file isfile $filename]} {
+ # Ask user for overwrite existing file
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent . \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $filename]]
+ ] != {yes}
+ } {
+ return
+ }
+ # Create a backup file
+ catch {
+ file rename -force $filename "$filename~"
+ }
+ }
+
+ # Hibernate running program
+ set sourcefile_md5 {}
+ catch {
+ set sourcefile_md5 [::md5::md5 -hex -file $sourcefile]
+ }
+ if {![$actualProject hibernate_hibernate \
+ $filename [file tail $sourcefile] $sourcefile_md5 0 \
+ ]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Hibernation failed"] \
+ -message [mc "Unable to write to file:\n%s\nCheck your permissions." $filename]
+ }
+ }
+
+ ## Resume hibernated program
+ # @parm String filename - Hibernation file
+ # @parm String sourcefile - Name of file from which the hibernation file was generated
+ # @return void
+ proc __resume_from {filename sourcefile} {
+ variable actualProject ;# Object: Current project
+ variable actualProjectIdx ;# Index of the current project in $openedProjects
+ variable simulator_enabled ;# List of booleans: Simulator engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ # Simulator must be engaged for this function
+ if {$project_menu_locked} {return}
+ if {![lindex $simulator_enabled $actualProjectIdx]} {
+ return
+ }
+
+ # Adjust the given name of the target file
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${X::actualProject} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${X::actualProject} cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+
+ # Resume hibernated program
+ set result [$actualProject hibernate_resume $filename 0]
+
+ # ERROR: Cannot open the specified file
+ if {$result == 1} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Resumption failed"] \
+ -message [mc "Unable to read file:\n%s\nCheck your permissions." $filename]
+
+ # ERROR: Cannot parse the specified file
+ } elseif {$result == 2} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Resumption failed"] \
+ -message [mc "This hibernation is corrupted or it is not MCU 8051 IDE M5IHIB file."]
+ }
+ }
+
+ ## Invoke interrupt monitor window
+ # @parm Object project_object = actualProject - Project
+ # @return void
+ proc __interrupt_monitor args {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[string length $args]} {
+ $args interrupt_monitor_invoke_dialog
+ } {
+ $actualProject interrupt_monitor_invoke_dialog
+ }
+ }
+
+ ## Invoke stack monitor window
+ # @parm Object project_object = actualProject - Project
+ # @return void
+ proc __stack_monitor args {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {[string length $args]} {
+ $args stack_monitor_invoke_dialog
+ } {
+ $actualProject stack_monitor_invoke_dialog
+ }
+ }
+
+ ## Invoke SFR map window
+ # @return void
+ proc __sfr_map {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject sfrmap_invoke_dialog
+ }
+
+ ## Show bit adrea
+ # @return void
+ proc __bitmap {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject bitmap_invoke_dialog
+ }
+
+ ## Adjust application language to variable ::GLOBAL_CONFIG(language)
+ # @return void
+ proc switch_language {} {
+ # ${::GLOBAL_CONFIG(language)}
+ }
+
+ ## Set syntax highlight for current editor
+ # @param Int highlight_num - -1 == None; 0 == Assembler; 1 == ISO C; 2 == Assembler code listing
+ # @return void
+ proc __set_highlight {highlight_num} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject editor_procedure {} force_language $highlight_num
+ }
+
+ ## Highlight parrern for the current editor has been changed
+ # @return void
+ proc highlight_pattern_changed {} {
+ __set_highlight $::editor_SH
+ }
+
+ ## Invoke independent hexadecimal editor
+ # @return Object - Hexeditor object reference
+ proc __hexeditor {} {
+ variable independent_hexeditor_count ;# Counter of intances of independent hexadecimal editor
+ incr independent_hexeditor_count
+
+ return [HexEditDlg ::independent_hexeditor_$independent_hexeditor_count {} uni]
+ }
+
+ ## Document current function in editor
+ # @return void
+ proc __document_current_func {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ $actualProject editor_procedure {} document_current_func {}
+ }
+
+ ## Create doxygen configguration file if it does not already exist
+ # @return void
+ proc create_doxyfile {} {
+ variable doxygen_pid ;# Int: Doxygen PID
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable actualProject ;# Object: Current project
+
+ if {$compilation_in_progress} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "Something is already running in background."]
+ return
+ }
+
+ set compilation_in_progress 1
+ make_progressBar_on_Sbar
+
+ if {[catch {
+ cd [$actualProject cget -projectPath]
+ }]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to change diectory to '%s'." [$actualProject cget -projectPath]]
+ return
+ }
+ if {![file exists Doxyfile]} {
+ $actualProject messages_text_append "\ndoxygen -g Doxyfile\n"
+ set doxygen_pid [exec -- \
+ doxygen -g Doxyfile && doxygen -u Doxyfile |& \
+ tclsh ${::LIB_DIRNAME}/external_command.tcl [tk appname] \
+ ::X::doxygen_finish ::X::doxygen_message & \
+ ]
+ } {
+ $actualProject messages_text_append "\ndoxygen -u Doxyfile\n"
+ set doxygen_pid [exec -- \
+ doxygen -u Doxyfile |& tclsh \
+ ${::LIB_DIRNAME}/external_command.tcl [tk appname] \
+ ::X::doxygen_finish ::X::doxygen_message & \
+ ]
+ }
+ }
+
+ ## Handle end of doxygen text output
+ # @return void
+ proc doxygen_finish {} {
+ variable actualProject ;# Object: Current project
+ variable doxygen_run_doxywizard ;# Bool: Run doxywizard
+ variable doxygen_build_api_doc ;# Bool: Build API documentation
+ variable doxygen_pid ;# Int: Doxygen PID
+ variable compilation_in_progress ;# Bool: Compiler engaged
+
+ if {$doxygen_run_doxywizard} {
+ exec -- doxywizard Doxyfile &
+ } elseif {$doxygen_build_api_doc} {
+ set doxygen_build_api_doc 0
+ if {[catch {
+ cd [$actualProject cget -projectPath]
+ }]} {
+ $actualProject messages_text_append [mc "\nUnable to change diectory to '%s'\n" [$actualProject cget -projectPath]]
+ destroy_progressBar_on_Sbar
+ set compilation_in_progress 0
+ set doxygen_pid 0
+ return
+ }
+
+ $actualProject messages_text_append "\ndoxygen Doxyfile\n"
+ set doxygen_pid [exec -- \
+ doxygen Doxyfile |& tclsh \
+ ${::LIB_DIRNAME}/external_command.tcl [tk appname] \
+ ::X::doxygen_finish ::X::doxygen_message & \
+ ]
+ }
+
+ destroy_progressBar_on_Sbar
+ set compilation_in_progress 0
+ set doxygen_pid 0
+ }
+
+ ## Handle text output doxygen
+ # @parm String text - Output from external compiler
+ # @return void
+ proc doxygen_message args {
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+ $doxygen_mess_project messages_text_append \
+ [string replace [regsub -all "\\\{" [regsub -all "\\\}" [lindex $args 0] "\}"] "\{"] 0 0]
+ }
+
+ ## Build C API documentation
+ # @return void
+ proc __generate_documentation {} {
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+ variable doxygen_build_api_doc ;# Bool: Build API documentation
+ variable doxygen_pid ;# Int: Doxygen PID
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {$compilation_in_progress} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to compile"] \
+ -message [mc "Something is already running in background."]
+ return
+ }
+ set doxygen_mess_project $actualProject
+ set doxygen_build_api_doc 1
+ if {!$::PROGRAM_AVALIABLE(doxygen)} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to find Doxygen"] \
+ -message [mc "Unable to find Doxygen. Please install doxygen and restart MCU 8051 IDE."]
+ return
+ }
+ $actualProject bottomNB_show_up {Messages}
+ create_doxyfile
+ }
+
+ ## Run doxygen graphical frontend
+ # @return void
+ proc __run_doxywizard {} {
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+ variable doxygen_run_doxywizard ;# Bool: Run doxywizard
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ if {!$::PROGRAM_AVALIABLE(doxywizard)} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to find doxywizard"] \
+ -message [mc "Unable to find doxywizard. Please install doxygen and restart MCU 8051 IDE."]
+ return
+ }
+ set doxygen_run_doxywizard 1
+ set doxygen_mess_project $actualProject
+ create_doxyfile
+ }
+
+ ## Remove doxygen documentation
+ # @return void
+ proc __clear_documentation {} {
+ variable actualProject ;# Object: Current project
+ variable doxygen_mess_project ;# Object: Project related to running doxygen compilation
+ variable compilation_in_progress ;# Bool: Compiler engaged
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+ set doxygen_mess_project $actualProject
+ if {[catch {
+ cd [$actualProject cget -projectPath]
+ }]} {
+ $actualProject messages_text_append [mc "\nError: Unable to change diectory to '%s'\n" [$actualProject cget -projectPath]]
+ return
+ }
+
+ $actualProject bottomNB_show_up {Messages}
+ $actualProject messages_text_append "\nrm -rfv html/* && rm -rfv latex/* && rm -rfv xml/*\n"
+ catch {exec -- /bin/sh << \
+ "rm -rfv html/* && rm -rfv latex/* && rm -rfv xml/*" |& \
+ tclsh ${::LIB_DIRNAME}/external_command.tcl [tk appname] \
+ ::X::doxygen_message ::X::doxygen_message & \
+ }
+ }
+
+ ## Display file statistic for the current file
+ # @return void
+ proc __statistics {} {
+ variable actualProject ;# Object: Current project
+ variable statistics_counter ;# Int: Counter of invocations of this dialog
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ # Check if this procedure can be run
+ if {$project_menu_locked} {return}
+ if {${::Editor::editor_to_use}} {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to compile"] \
+ -message [mc "Unable to gain file statistics while external editor is used"]
+ return
+ }
+
+ # Create dialog window (not modal)
+ incr statistics_counter
+ set win [toplevel .statistics$statistics_counter -class {File statistics} -bg {#EEEEEE}]
+
+ # Local variables
+ set bold_font [font create -family {helvetica} -size -12 -weight bold]
+ set normal_font [font create -family {helvetica} -size -12 -weight normal]
+ set header_font [font create -family {helvetica} -size -20 -weight normal]
+ set statistics [$actualProject editor_procedure {} getFileStatistics {}]
+
+ # Create window header
+ set dialog_header [label $win.dialog_header \
+ -width 25 -font $header_font \
+ -text [lindex [$actualProject editor_procedure {} getFileName {}] 1] \
+ ]
+
+ set main_frame [frame $win.main_frame]
+ # Header: "Characters"
+ grid [label $main_frame.characters_lbl -pady 0 \
+ -text [mc "Characters"] -font $bold_font \
+ ] -row 0 -column 0 -columnspan 3 -sticky w
+ # - Words and numbers
+ grid [Label $main_frame.c_words_name_lbl \
+ -text [mc "Words and numbers:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Alphanumeric characters and connector punctuation characters"] \
+ ] -row 1 -column 1 -sticky w
+ grid [label $main_frame.c_words_value_lbl \
+ -text [lindex $statistics 0] \
+ -font $normal_font -pady 0 \
+ ] -row 1 -column 2 -sticky e
+ # - Comments
+ grid [Label $main_frame.c_comments_name_lbl \
+ -text [mc "Comments:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Characters highlighted as comments"] \
+ ] -row 2 -column 1 -sticky w
+ grid [label $main_frame.c_comments_value_lbl \
+ -text [lindex $statistics 1] \
+ -font $normal_font -pady 0 \
+ ] -row 2 -column 2 -sticky e
+ # - Other characters
+ grid [Label $main_frame.c_other_name_lbl \
+ -text [mc "Other characters:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "All other charactes without EOLs (e.g. spaces and brackets)"] \
+ ] -row 3 -column 1 -sticky w
+ grid [label $main_frame.c_other_value_lbl \
+ -text [lindex $statistics 2] \
+ -font $normal_font -pady 0 \
+ ] -row 3 -column 2 -sticky e
+ # Separator
+ grid [ttk::separator $main_frame.sep_0 \
+ -orient horizontal \
+ ] -row 4 -column 2 -sticky we
+ # - Total characters
+ grid [Label $main_frame.c_total_name_lbl \
+ -text [mc "Total characters:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "All charactes in the text without EOLs"] \
+ ] -row 5 -column 1 -sticky w
+ grid [label $main_frame.c_total_value_lbl \
+ -text [lindex $statistics 3] \
+ -font $normal_font -pady 0 \
+ ] -row 5 -column 2 -sticky e
+ # Header: "Strings"
+ grid [label $main_frame.strings_lbl -pady 0 \
+ -text [mc "Strings"] -font $bold_font \
+ ] -row 7 -column 0 -columnspan 3 -sticky w
+ # - Words
+ grid [Label $main_frame.s_words_name_lbl \
+ -text [mc "Words:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Just normal words (not keywords and not comments)"] \
+ ] -row 8 -column 1 -sticky w
+ grid [label $main_frame.s_words_value_lbl \
+ -text [lindex $statistics 4] \
+ -font $normal_font -pady 0 \
+ ] -row 8 -column 2 -sticky e
+ # - Keywords
+ grid [Label $main_frame.s_keywords_name_lbl \
+ -text [mc "Keywords:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Instructions, Assembler directives, C directives, C keywords"] \
+ ] -row 9 -column 1 -sticky w
+ grid [label $main_frame.s_keywords_value_lbl \
+ -text [lindex $statistics 5] \
+ -font $normal_font -pady 0 \
+ ] -row 9 -column 2 -sticky e
+ # - Comments
+ grid [Label $main_frame.s_comments_name_lbl \
+ -text [mc "Comments:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Words in comments"] \
+ ] -row 10 -column 1 -sticky w
+ grid [label $main_frame.s_comments_value_lbl \
+ -text [lindex $statistics 6] \
+ -font $normal_font -pady 0 \
+ ] -row 10 -column 2 -sticky e
+ # Separator
+ grid [ttk::separator $main_frame.sep_1 \
+ -orient horizontal \
+ ] -row 11 -column 2 -sticky we
+ # - Total strings
+ grid [Label $main_frame.s_total_name_lbl \
+ -text [mc "Total strings:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Total number of words in the text"] \
+ ] -row 12 -column 1 -sticky w
+ grid [label $main_frame.s_total_value_lbl \
+ -text [lindex $statistics 7] \
+ -font $normal_font -pady 0 \
+ ] -row 12 -column 2 -sticky e
+ # Header: "Lines"
+ grid [label $main_frame.lines_lbl \
+ -text [mc "Lines"] \
+ -font $bold_font -pady 0 \
+ ] -row 14 -column 0 -columnspan 3 -sticky w
+ # - Empty lines
+ grid [Label $main_frame.l_empty_name_lbl \
+ -text [mc "Empty lines:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Totaly empty lines (without even spaces)"] \
+ ] -row 15 -column 1 -sticky w
+ grid [label $main_frame.l_empty_value_lbl \
+ -text [lindex $statistics 8] \
+ -font $normal_font -pady 0 \
+ ] -row 15 -column 2 -sticky e
+ # - Commented lines
+ grid [Label $main_frame.l_commented_name_lbl \
+ -text [mc "Commented lines:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Lines which are all commented"] \
+ ] -row 16 -column 1 -sticky w
+ grid [label $main_frame.l_commented_value_lbl \
+ -text [lindex $statistics 9] \
+ -font $normal_font -pady 0 \
+ ] -row 16 -column 2 -sticky e
+ # - Normal lines
+ grid [Label $main_frame.l_normal_name_lbl \
+ -text [mc "Normal lines:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Just normal code lines"] \
+ ] -row 17 -column 1 -sticky w
+ grid [label $main_frame.l_normal_value_lbl \
+ -text [lindex $statistics 10] \
+ -font $normal_font -pady 0 \
+ ] -row 17 -column 2 -sticky e
+ # Separator
+ grid [ttk::separator $main_frame.sep_2 \
+ -orient horizontal \
+ ] -row 18 -column 2 -sticky we
+ # - Total lines
+ grid [Label $main_frame.l_total_name_lbl \
+ -text [mc "Total lines:"] \
+ -font $normal_font -pady 0 \
+ -helptext [mc "Total number of lines in the text"] \
+ ] -row 19 -column 1 -sticky w
+ grid [label $main_frame.l_total_value_lbl \
+ -text [lindex $statistics 11] \
+ -font $normal_font -pady 0 \
+ ] -row 19 -column 2 -sticky e
+
+ # Configure main frame
+ grid columnconfigure $main_frame 0 -minsize 25
+ grid columnconfigure $main_frame 1 -weight 1
+ grid rowconfigure $main_frame 6 -minsize 10
+ grid rowconfigure $main_frame 13 -minsize 10
+
+ # Create and pack 'COPY' and 'OK' buttons
+ set button_frame [frame $win.button_frame]
+ pack [ttk::button $button_frame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "X::statistics_close $statistics_counter" \
+ ] -side right
+ pack [ttk::button $button_frame.copy \
+ -text [mc "Copy"] \
+ -compound left \
+ -image ::ICONS::16::editcopy \
+ -command "X::statistics_copy $statistics_counter" \
+ ] -side left
+
+ # Pack dialog frames
+ pack $dialog_header -side top -fill x -pady 5
+ pack $main_frame -side top -anchor nw -fill x -pady 15 -padx 10
+ pack $button_frame -side bottom -anchor se
+
+ # Set window manager options
+ wm iconphoto $win ::ICONS::16::graph
+ wm title $win [mc "File statistics - MCU 8051 IDE"]
+ wm minsize $win 250 400
+ wm transient $win .
+ wm protocol $win WM_DELETE_WINDOW "X::statistics_close $statistics_counter"
+ update
+ focus $button_frame.ok
+ raise $win
+ }
+
+ ## Close dialog "File statistics"
+ # @parm Int dialog_number -
+ # @return void
+ proc statistics_close {dialog_number} {
+ variable statistics_counter ;# Int: Counter of invocations of this dialog
+ if {![winfo exists .statistics$statistics_counter]} {return}
+ destroy .statistics$statistics_counter
+ }
+
+ ## Copy contents of file statistics dialog to the clipboard
+ # @parm Int dialog_number -
+ # @return void
+ proc statistics_copy {dialog_number} {
+ variable statistics_counter ;# Int: Counter of invocations of this dialog
+ if {![winfo exists .statistics$statistics_counter]} {return}
+
+ set win .statistics$statistics_counter
+ set main_frame $win.main_frame
+
+ clipboard clear
+ clipboard append [mc "Statistics for: %s\n\n" [$win.dialog_header cget -text]]
+ clipboard append [mc "Characters:\n"]
+ clipboard append [mc " Words and numbers:\t\t%s\n" [$main_frame.c_words_value_lbl cget -text]]
+ clipboard append [mc " Comments:\t\t\t%s\n" [$main_frame.c_comments_value_lbl cget -text]]
+ clipboard append [mc " Other characters:\t\t%s\n" [$main_frame.c_other_value_lbl cget -text]]
+ clipboard append [mc " ------\n"]
+ clipboard append [mc " Total characters:\t\t%s\n\n" [$main_frame.c_total_value_lbl cget -text]]
+ clipboard append [mc "Strings:\n"]
+ clipboard append [mc " Words:\t\t\t%s\n" [$main_frame.s_words_value_lbl cget -text]]
+ clipboard append [mc " Keywords:\t\t\t%s\n" [$main_frame.s_keywords_value_lbl cget -text]]
+ clipboard append [mc " Comments:\t\t\t%s\n" [$main_frame.s_comments_value_lbl cget -text]]
+ clipboard append [mc " ------\n"]
+ clipboard append [mc " Total strings:\t\t%s\n" [$main_frame.s_total_value_lbl cget -text]]
+ clipboard append [mc "Lines:\n"]
+ clipboard append [mc " Empty lines:\t\t\t%s\n" [$main_frame.l_empty_value_lbl cget -text]]
+ clipboard append [mc " Commented lines:\t\t%s\n" [$main_frame.l_commented_value_lbl cget -text]]
+ clipboard append [mc " Normal lines:\t\t\t%s\n" [$main_frame.l_normal_value_lbl cget -text]]
+ clipboard append [mc " ------\n"]
+ clipboard append [mc " Total lines:\t\t\t%s\n" [$main_frame.l_total_value_lbl cget -text]]
+ }
+
+ ## Modify main menu and main toolbar acording to configuration of the current editor
+ # @parm Bool read_only - 1 == Read only; 0 == Normal mode; {} == Do not change
+ # @parm Bool c_language - 1 == Uses C language; 0 == Uses Assembler; {} == Do not change
+ # @return void
+ proc adjust_mainmenu_and_toolbar_to_editor {read_only c_language} {
+ variable mainmenu_editor_readonly ;# Menu bar items which are not avaliable when editor is in read only mode
+ variable toolbar_editor_readonly ;# Tool bar items which are not avaliable when editor is in read only mode
+ variable mainmenu_editor_c_only ;# Menu bar items which are not avaliable only for C language
+ variable toolbar_editor_c_only ;# Toolbar items which are not avaliable only for C language
+
+ # Read only flag
+ if {$read_only != {}} {
+ set read_only [expr {!$read_only}]
+ ena_dis_menu_buttons $read_only $mainmenu_editor_readonly
+ ena_dis_iconBar_buttons $read_only .mainIconBar. $toolbar_editor_readonly
+ }
+
+ # C language
+ if {$c_language != {}} {
+ ena_dis_menu_buttons $c_language $mainmenu_editor_c_only
+ ena_dis_iconBar_buttons $c_language .mainIconBar. $toolbar_editor_c_only
+ }
+ }
+
+ ## Conditionaly disable menu and toolbar items which
+ #+ are not avaliable when external editor used
+ # @return void
+ proc adjust_mm_and_tb_ext_editor {} {
+ variable mainmenu_editor_external_na ;# Menu bar items which are not avaliable when external embedded editor is used
+ variable toolbar_editor_external_na ;# Toolbar items which are not avaliable when external embedded editor is used
+
+ if {!${::Editor::editor_to_use}} {
+ return
+ }
+
+ ena_dis_menu_buttons 0 $mainmenu_editor_external_na
+ ena_dis_iconBar_buttons 0 .mainIconBar. $toolbar_editor_external_na
+ }
+
+ ## Invoke assembly language symbols viewer
+ # @return void
+ proc __symb_view {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+
+ # Open dialog window
+ set obj [SymbolViewer #auto]
+
+ # Try to load some file into the viewer
+ if {!$project_menu_locked} {
+ set file [$actualProject cget -P_option_main_file]
+ if {$file == {}} {
+ set file [$actualProject editor_procedure {} getFileName {}]
+ set file [file join [lindex $file 0] [lindex $file 1]]
+ }
+ if {$file != {}} {
+ $obj open_file 1 [file rootname $file].lst
+ }
+ }
+ }
+
+ ## Invoke 8-segment LED display editor
+ # @return void
+ proc __eightsegment {} {
+ variable eightsegment_editors ;# List: All 8-segment LED display editors invoked
+
+ lappend eightsegment_editors [EightSegment #auto]
+ }
+
+ ## Invoke ASCII chart
+ # @return void
+ proc __ascii_chart {} {
+ variable ascii_chart_win_object ;# Object: ASCII chart window object
+ if {$ascii_chart_win_object != {}} {
+ if {[$ascii_chart_win_object is_visible]} {
+ $ascii_chart_win_object raise_window
+ } {
+ $ascii_chart_win_object restore_window
+ }
+ } {
+ set ascii_chart_win_object [AsciiChart #this]
+ }
+ }
+
+ ## Switch editor to block selection mode
+ # @return void
+ proc __block_selection_mode {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+
+ if {$project_menu_locked} {return}
+ $actualProject editor_procedure {} switch_sel_mode {}
+ }
+
+ ## Invoke stopwatch timer window
+ # @return void
+ proc __stopwatch_timer {} {
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+ variable actualProject ;# Object: Current project
+
+ if {$project_menu_locked} {return}
+ $actualProject stopwatch_invoke_dialog
+ }
+
+ ## Referesh contents of menu "Open recent"
+ # @param Int what
+ # 0 - Recent project files
+ # 1 - Recent source code files
+ # 2 - Recent Virtual HW files
+ # @return void
+ proc refresh_recent_files {what} {
+ variable file_recent_files ;# List: recently opened files
+ variable project_recent_files ;# List: recently opened projects
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ # Refresh "Recent Virtual HW files"
+ if {$what == 2} {
+ # Clean up the menu
+ .mainMenu.virtual_hw.open_recent delete 0 end
+ .mainMenu.virtual_hw.load_recent delete 0 end
+ # Interate over recently opened files and add them to the menu
+ foreach file $vhw_recent_files {
+ .mainMenu.virtual_hw.open_recent add command \
+ -label $file -command [list ::X::open_recent 2 $file]
+ .mainMenu.virtual_hw.load_recent add command \
+ -label $file -command [list ::X::open_recent -2 $file]
+ }
+
+ # Refresh "Recent source code file"
+ } elseif {$what == 1} {
+ # Clean up the menu
+ .mainMenu.file.open_recent delete 0 end
+
+ # Interate over recently opened files and add them to the menu
+ foreach file $file_recent_files {
+
+ # Determinate file type and appropriate icon
+ set ext [string trimleft [file extension $file] {.}]
+ if {$ext == {c}} {
+ set img {source_c}
+ } elseif {$ext == {h}} {
+ set img {source_h}
+ } elseif {$ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set img {source_cpp}
+ } elseif {$ext == {lst}} {
+ set img {ascii}
+ } elseif {$ext == {asm}} {
+ set img {asm}
+ } else {
+ set img {ascii}
+ }
+
+ # Create a new menu entry
+ .mainMenu.file.open_recent add command \
+ -label $file -compound left -image ::ICONS::16::$img \
+ -command [list ::X::open_recent $what $file]
+ }
+
+ # Refresh "Recent project file"
+ } elseif {$what == 0} {
+ # Clean up the menu
+ .mainMenu.project.open_recent delete 0 end
+ # Interate over recently opened files and add them to the menu
+ foreach file $project_recent_files {
+ .mainMenu.project.open_recent add command \
+ -label $file -command [list ::X::open_recent $what $file]
+ }
+ }
+
+
+ }
+
+ ## Open recent file
+ # @param Int what
+ # 0 - Recent project files
+ # 1 - Recent source code files
+ # 2 - Recent Virtual HW files (OPEN)
+ # -2 - Recent Virtual HW files (LOAD)
+ # @param String filename - Name of file to open
+ # @return void
+ proc open_recent {what filename} {
+ variable critical_procedure_in_progress ;# Bool: Disable critical procedures (like compilation, start simulator, etc.)
+ variable actualProject ;# Object: Current project
+ variable openedProjects ;# List of opened projects (Object references)
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ # This function is critical
+ if {$critical_procedure_in_progress} {return}
+ set critical_procedure_in_progress 1
+
+ # Open "Recent Virtual HW file"
+ if {$what == 2} {
+ if {[$actualProject pale_open_scenario $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to read file:\n\"%s\"" $filename]
+ }
+
+ # Load "Recent Virtual HW file"
+ } elseif {$what == -2} {
+ if {[$actualProject pale_load_scenarion $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to read file:\n\"%s\"" $filename]
+ }
+
+ # Open "Recent source code file"
+ } elseif {$what == 1} {
+ # If there is no project opened -> invalid function call -> abort
+ if {![llength $openedProjects]} {
+ set critical_procedure_in_progress 0
+ return
+ }
+
+ # Open the specified file
+ if {[$actualProject openfile $filename 1 . def def 0 0 {}] != {}} {
+ $actualProject switch_to_last
+ update
+ $actualProject editor_procedure {} parseAll {}
+
+ # Make LST read only
+ if {[file extension $filename] == {.lst}} {
+ set ::editor_RO_MODE 1
+ $actualProject switch_editor_RO_MODE
+ }
+ }
+
+ # Open "Recent project file"
+ } elseif {$what == 0} {
+ # Try to open he specified project file
+ if {![Project::open_project_file $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent . \
+ -title [mc "Error - MCU 8051 IDE"] \
+ -message [mc "Unable to load file: %s" $filename]
+ } {
+ $actualProject editor_procedure {} highlight_visible_area {}
+ }
+
+ adjust_title
+ disaena_menu_toolbar_for_current_project
+ }
+
+ # Unlock critical procedures
+ set critical_procedure_in_progress 0
+ }
+
+ ## Add item into list of recent files
+ # @param Int what
+ # 0 - Recent project files
+ # 1 - Recent source code files
+ # 2 - Recent Virtual HW files
+ # @param String filename - Name of file to add
+ # @return void
+ proc recent_files_add {what filename} {
+ variable file_recent_files ;# List: recently opened files
+ variable project_recent_files ;# List: recently opened projects
+ variable vhw_recent_files ;# List: recently opened Virtual HW files
+
+ # Add "Recent Virtual HW file"
+ if {$what == 2} {
+ # Check wheather the specified file is already in the list
+ set tmp [lsearch -ascii -exact $vhw_recent_files $filename]
+ if {$tmp != -1} {
+ set vhw_recent_files [linsert [lreplace $vhw_recent_files $tmp $tmp] 0 $filename]
+ refresh_recent_files $what
+ return
+ }
+
+ # Trim list length to 10
+ if {[llength $vhw_recent_files] >= 10} {
+ set vhw_recent_files [lreplace $vhw_recent_files end end]
+ }
+
+ # Add new item and refersh menu
+ set vhw_recent_files [linsert $vhw_recent_files 0 $filename]
+ refresh_recent_files $what
+
+ # Add "Recent source code file"
+ } elseif {$what == 1} {
+ # Check wheather the specified file is already in the list
+ set tmp [lsearch -ascii -exact $file_recent_files $filename]
+ if {$tmp != -1} {
+ set file_recent_files [linsert [lreplace $file_recent_files $tmp $tmp] 0 $filename]
+ refresh_recent_files $what
+ return
+ }
+
+ # Trim list length to 10
+ if {[llength $file_recent_files] >= 10} {
+ set file_recent_files [lreplace $file_recent_files end end]
+ }
+
+ # Add new item and refersh menu
+ set file_recent_files [linsert $file_recent_files 0 $filename]
+ refresh_recent_files $what
+
+ # Add "Recent project file"
+ } elseif {$what == 0} {
+ # Check wheather the specified file is already in the list
+ set tmp [lsearch -ascii -exact $project_recent_files $filename]
+ if {$tmp != -1} {
+ set project_recent_files [linsert [lreplace $project_recent_files $tmp $tmp] 0 $filename]
+ refresh_recent_files $what
+ return
+ }
+
+ # Trim list length to 10
+ if {[llength $project_recent_files] >= 10} {
+ set project_recent_files [lreplace $project_recent_files end end]
+ }
+
+ # Add new item and refersh menu
+ set project_recent_files [linsert $project_recent_files 0 $filename]
+ refresh_recent_files $what
+
+ }
+ }
+
+ ## Invoke "scribble notepad"
+ # @return void
+ proc __notes {} {
+ Notes #auto {} {}
+ }
+
+ ## Invoke "Base convertor"
+ # @return void
+ proc __base_convertor {} {
+ variable base_convertors ;# List: All base convertor objects
+
+ set obj [BaseConvertor #auto]
+ lappend base_convertors ::X::$obj
+
+ return $obj
+ }
+
+ ## Close "Base convertor"
+ # @return void
+ proc __base_convertor_close {obj} {
+ variable base_convertors ;# List: All base convertor objects
+
+ set idx [lsearch -ascii -exact $base_convertors $obj]
+ if {$idx != -1} {
+ set base_convertors [lreplace $base_convertors $idx $idx]
+ }
+ }
+
+ ## Invoke "LED panel" (section Virtual Hardware)
+ # @return void
+ proc __vhw_LED_panel {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [LedPanel #auto $actualProject]
+ }
+
+ ## Invoke "LED display" (section Virtual Hardware)
+ # @return void
+ proc __vhw_LED_display {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [LedDisplay #auto $actualProject]
+ }
+
+ ## Invoke "LED matrix" (section Virtual Hardware)
+ # @return void
+ proc __vhw_LED_matrix {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [LedMatrix #auto $actualProject]
+ }
+
+ ## Invoke "Multiplexed LED display" (section Virtual Hardware)
+ # @return void
+ proc __vhw_M_LED_display {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [MultiplexedLedDisplay #auto $actualProject]
+ }
+
+ ## Invoke "Simple keypad" (section Virtual Hardware)
+ # @return void
+ proc __vhw_keys {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [SimpleKeyPad #auto $actualProject]
+ }
+
+ ## Invoke "Matrix keypad" (section Virtual Hardware)
+ # @return void
+ proc __vhw_matrix_keypad {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ return [MatrixKeyPad #auto $actualProject]
+ }
+
+ ## Open VHW file (section Virtual Hardware)
+ # @return void
+ proc __open_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Ask user for save modified VHW scenario
+ if {[${::X::actualProject} pale_modified]} {
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -title [mc "File modified"] \
+ -message [mc "The current VHW connections have been modified,\ndo you want to save them before closing ?"]
+ ] == {yes}} then {
+ if {![$actualProject pale_save]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to write to file:\n\"%s\"" [$actualProject pale_get_scenario_filename]]
+ }
+ }
+ }
+
+ # Create file selection dialog
+ catch {delete object ::fsd}
+ KIFSD::FSD ::fsd \
+ -title [mc "Open file - Virtual HW - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 0 -filetypes [list \
+ [list [mc "Virtual HW"] {*.vhw}] \
+ [list [mc "VH component"] {*.vhc}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ ::fsd setokcmd {
+ set filename [::fsd get]
+ if {[${::X::actualProject} pale_open_scenario $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to read file:\n\"%s\"" $filename]
+ } {
+ ::X::recent_files_add 2 $filename
+ }
+ }
+
+ # activate the dialog
+ ::fsd activate
+ }
+
+ ## Import virtual hardware file
+ # @return void
+ proc __load_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Create file selection dialog
+ catch {delete object ::fsd}
+ KIFSD::FSD ::fsd \
+ -title [mc "Load file - Virtual HW - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -defaultmask 0 -multiple 1 -filetypes [list \
+ [list [mc "Virtual HW"] {*.vhw}] \
+ [list [mc "VH component"] {*.vhc}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ ::fsd setokcmd {
+ foreach filename [::fsd get] {
+ if {[${::X::actualProject} pale_load_scenarion $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to read file:\n\"%s\"" $filename]
+ } {
+ ::X::recent_files_add 2 $filename
+ }
+ }
+ }
+
+ # Activate the dialog
+ ::fsd activate
+ }
+
+ ## Save virtual hardware scenario to a file
+ # @return void
+ proc __save_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ if {![$actualProject pale_save]} {
+ Sbar [mc "Unable to save Virtual HW connections"]
+ }
+ }
+
+ ## Save virtual hardware scenario under a different filename
+ # @return void
+ proc __save_as_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Create file selection dialog
+ catch {delete object ::fsd}
+ KIFSD::FSD ::fsd \
+ -title [mc "Save file - Virtual HW - MCU 8051 IDE"] \
+ -directory [$actualProject cget -projectPath] \
+ -initialfile [$actualProject pale_get_scenario_filename]\
+ -defaultmask 0 -multiple 1 -filetypes [list \
+ [list [mc "Virtual HW"] {*.vhw}] \
+ [list [mc "All files"] {*}] \
+ ]
+
+ # Open file after press of OK button
+ ::fsd setokcmd {
+ set abort 0
+ set filename [::fsd get]
+
+ # Ask user for overwrite existing file
+ if {[file exists $filename]} {
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent . \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Do you want to overwrite it ?" [file tail $filename]]
+ ] != {yes}
+ } {
+ set abort 1
+ }
+ }
+
+ if {!$abort} {
+ if {![${::X::actualProject} pale_save_as $filename]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to save file:\n\"%s\"" $filename]
+ } {
+ ::X::recent_files_add 2 $filename
+ }
+ }
+ }
+
+ # Activate the dialog
+ ::fsd activate
+ }
+
+ ## Remove all virtual hardware and forget VHW filename
+ # @return void
+ proc __remove_all_VHW {} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ # Ask user for comfirmation
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent . \
+ -title [mc "Are you sure ?"] \
+ -message [mc "Do you really want to remove all virtual hardware from the current simulation scenario ?"]
+ ] != {yes}
+ } {
+ return
+ }
+
+ $actualProject pale_forget_all
+ }
+
+ ## Toggle fullscreen mode
+ # @return void
+ proc __toggle_fullscreen {} {
+ # Normal window
+ if {[wm attributes . -fullscreen]} {
+ if {[winfo exists .mainIconBar.fullscreen]} {
+ .mainIconBar.fullscreen configure -image ::ICONS::22::window_fullscreen
+ }
+ wm attributes . -fullscreen 0
+ # Fullscreen window
+ } {
+ if {[winfo exists .mainIconBar.fullscreen]} {
+ .mainIconBar.fullscreen configure -image ::ICONS::22::window_nofullscreen
+ }
+ wm attributes . -fullscreen 1
+ }
+
+ # Restore position of bottom pane
+ after 300 {
+ foreach project ${::X::openedProjects} {
+ $project bottomNB_redraw_pane
+ }
+ }
+ }
+
+ ## Invoke the special calculator
+ # @return void
+ proc __spec_calc {} {
+ variable spec_calc_objects ;# List: All special calculator objects
+
+ lappend spec_calc_objects [SpecCalc #auto]
+ }
+
+ ## Invoke RS232/UART debugger
+ # @return void
+ proc __rs232debugger {} {
+ variable rs232debugger_objects ;# List: All RS232 Debugger objects
+
+ lappend rs232debugger_objects [RS232Debugger #auto]
+ }
+
+ ## Invoke a functional diagram of the given type
+ # @parm Int type -
+ # @return void
+ proc __functional_diagram {type} {
+ }
+
+ ## Invoke a virtual terminal of the given type
+ # @parm Int type -
+ # @return void
+ proc __virtual_terminal {type} {
+ variable actualProject ;# Object: Current project
+ variable project_menu_locked ;# Bool: Indicates than there is at least one opened project
+
+ if {$project_menu_locked} {return}
+
+ switch -- $type {
+ {u} {
+ $actualProject virtual_uart_termial_invoke_dialog
+ }
+ }
+ }
+}
diff --git a/lib/bottompanel/bottomnotebook.tcl b/lib/bottompanel/bottomnotebook.tcl
new file mode 100755
index 0000000..463f93d
--- /dev/null
+++ b/lib/bottompanel/bottomnotebook.tcl
@@ -0,0 +1,469 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements bottom panel of the project tab
+# --------------------------------------------------------------------------
+
+# Import nesesary sources
+source "${::LIB_DIRNAME}/bottompanel/calculator.tcl" ;# Calculator
+source "${::LIB_DIRNAME}/bottompanel/todo.tcl" ;# Todo list
+source "${::LIB_DIRNAME}/bottompanel/graph.tcl" ;# Graph
+source "${::LIB_DIRNAME}/bottompanel/messages.tcl" ;# Messages
+source "${::LIB_DIRNAME}/bottompanel/terminal.tcl" ;# Terminal
+source "${::LIB_DIRNAME}/bottompanel/find_in_files.tcl" ;# Find in files
+source "${::LIB_DIRNAME}/bottompanel/cvarsview.tcl" ;# C variables
+
+class BottomNoteBook {
+
+ # Inherit content of some other clases
+ inherit Calculator Todo Simulator Graph Messages Terminal FindInFiles CVarsView
+
+ ## Public
+ public variable simulator_frame ;# Identifier of tab of NoteBook widget for simulator
+ public variable cvarsview_frame ;# Identifier of tab of NoteBook widget for c variables
+ public variable graph_frame ;# Identifier of tab of NoteBook widget for graph
+ public variable messages_frame ;# Identifier of tab of NoteBook widget for messages box
+ public variable todo_frame ;# Identifier of tab of NoteBook widget for todo box
+ public variable calculator_frame ;# Identifier of tab of NoteBook widget for calculator
+ public variable terminal_frame ;# Identifier of tab of NoteBook widget for terminal
+ public variable findinfiles_frame ;# Identifier of tab of NoteBook widget for terminal
+
+ ## Private
+ private variable pri_notebook ;# Identifier of NoteBook widget when panel is visible
+ private variable sec_notebook ;# Identifier of NoteBook widget when panel is hidden
+ private variable main_frame ;# Identifier of frame containing both NoteBooks
+
+ private variable panel_hidding_ena 1 ;# Is panel hidding enabled
+ private variable redraw_pane_in_progress 0 ;# Is panel pane redraw in progress
+ private variable parentPane ;# Identifier of parent pane
+ private variable last_PanelSize ;# Last panel height
+ private variable PanelVisible $CONFIG(BOTTOM_PANEL) ;# Is panel visible
+ private variable active_page $CONFIG(BOTTOM_PANEL_ACTIVE_PAGE) ;# Identifier of active NoteBook page
+ private variable PanelSize $CONFIG(BOTTOM_PANEL_SIZE) ;# Current panel height
+
+ ## object constructor
+ constructor {} {
+ # Validate and set active page
+ if {$active_page == {Terminal}} {
+ set active_page {Simulator}
+ } elseif {
+ [lsearch {Simulator CVarsView Graph Messages Todo Calculator FindInFiles} $active_page] == -1
+ } {
+ puts stderr "Invalid value of active page '$active_page', setting to {Simulator}"
+ set active_page {Simulator}
+ }
+ }
+
+ ## object destructor
+ destructor {
+ # Destroy GUI
+ destroy $main_frame
+ notebook_Sbar_unset {bottomnb}
+ }
+
+ ## Create Bottom NoteBook (This function must be called after contructor)
+ # @parm widget mainframe - Frame for bottom notebook
+ # @parm widget PaneWindow - parent pane window contaier
+ # @parm String todoText - content of todo text
+ # @parm List calculatorList - List of values for calculator (display content, radix, etc.)
+ # @parm List graph_config - Graph configuration list
+ # @return Widget - ID of frame containg both notebooks
+ public method initiate_BottomNoteBook {mainframe PaneWindow todoText calculatorList graph_config} {
+
+ # set parent pane window
+ set parentPane $PaneWindow
+
+ ## Create some widgets
+ # Frame for primary and secondary notebook
+ set main_frame $mainframe
+ # Primary notebook
+ set pri_notebook [NoteBook $main_frame.ntb_bottomNB_pri \
+ -side top -bd 1 \
+ -arcradius 4 -bg {#EEEEEE} \
+ -font [font create -family {helvetica} -size -12 -weight bold] \
+ ]
+ # Secondary notebook
+ set sec_notebook [NoteBook $main_frame.ntb_bottomNB_sec \
+ -side top \
+ -arcradius 4 \
+ -borderwidth 1 -bg {#EEEEEE} \
+ -font [font create -family {helvetica} -size -12 -weight bold] \
+ ]
+
+ # Register notebook status bar tips
+ notebook_Sbar_set {bottomnb} [list \
+ Simulator [mc "Simulator panel"] \
+ CVarsView [mc "List of variables defined in C program"] \
+ Graph [mc "Graph showing voltage levels"] \
+ Messages [mc "Compiler messages"] \
+ Todo [mc "Editable notepad"] \
+ Calculator [mc "Scientific calculator"] \
+ Terminal [mc "Linux terminal emulator"] \
+ FindInFiles [mc "Search string in files"] \
+ Hide [mc "Hide the panel"] \
+ Show [mc "Show the panel"] \
+ ]
+ $pri_notebook bindtabs <Enter> "notebook_Sbar bottomnb"
+ $pri_notebook bindtabs <Leave> "Sbar {} ;#"
+ $sec_notebook bindtabs <Enter> "notebook_Sbar bottomnb"
+ $sec_notebook bindtabs <Leave> "Sbar {} ;#"
+
+ ## create Primary NoteBook tabs
+ # Tab "Simulator"
+ set simulator_frame [$pri_notebook insert end {Simulator} \
+ -text [mc "Simulator"] \
+ -image ::ICONS::16::kcmmemory \
+ -raisecmd "$this bottomNB_set_active_page {Simulator}" \
+ -helptext [mc "Simulator panel %s" "(Ctrl+1)"] \
+ -createcmd [list $this CreateSimulatorGUI] \
+ ]
+ # Tab "C variables"
+ set cvarsview_frame [$pri_notebook insert end {CVarsView} \
+ -text [mc "C variables"] \
+ -image ::ICONS::16::player_playlist \
+ -raisecmd "$this bottomNB_set_active_page {CVarsView}" \
+ -helptext [mc "Variables from C source code %s" ""] \
+ -createcmd [list $this CreateCVarsViewGUI] \
+ ]
+ # Tab "Graph"
+ set graph_frame [$pri_notebook insert end {Graph} \
+ -text [mc "IO Ports"] \
+ -image ::ICONS::16::graph \
+ -raisecmd "$this bottomNB_set_active_page {Graph}" \
+ -helptext [mc "Graph showing state of MCU ports %s" "(Ctrl+2)"] \
+ -createcmd [list $this CreateGraphGUI] \
+ ]
+ # Tab "Messages"
+ set messages_frame [$pri_notebook insert end {Messages} \
+ -text [mc "Messages"] \
+ -image ::ICONS::16::kcmsystem \
+ -raisecmd "$this bottomNB_set_active_page {Messages}" \
+ -helptext [mc "Compiler messages %s" "(Ctrl+3)"] \
+ -createcmd [list $this CreateMessagesGUI] \
+ ]
+ # Tab "Notes"
+ set todo_frame [$pri_notebook insert end {Todo} \
+ -text [mc "Notes"] \
+ -image ::ICONS::16::camera_test \
+ -raisecmd "$this bottomNB_set_active_page {Todo}" \
+ -helptext [mc "Personal todo list & notepad %s" "(Ctrl+4)"]\
+ -createcmd [list $this CreateTodoGUI] \
+ ]
+ # Tab "Calculator"
+ set calculator_frame [$pri_notebook insert end {Calculator} \
+ -text [mc "Calculator"] \
+ -image ::ICONS::16::xcalc \
+ -raisecmd "$this bottomNB_set_active_page {Calculator}" \
+ -helptext [mc "Scientific calculator %s" "(Ctrl+5)"] \
+ -createcmd [list $this CreateCalculatorGUI] \
+ ]
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no terminal emulator
+ # Tab "Terminal"
+ set terminal_frame [$pri_notebook insert end {Terminal} \
+ -text [mc "Terminal"] \
+ -image ::ICONS::16::terminal \
+ -raisecmd "$this bottomNB_set_active_page {Terminal}" \
+ -helptext [mc "Terminal emulator %s" ""] \
+ -createcmd [list $this CreateTerminalEmulGUI] \
+ -state [expr {${::PROGRAM_AVALIABLE(urxvt)} ? "normal" : "disabled"}] \
+ ]
+ }
+ # Tab "Find in files"
+ set findinfiles_frame [$pri_notebook insert end {FindInFiles} \
+ -text [mc "Find in files"] \
+ -image ::ICONS::16::filefind \
+ -raisecmd "$this bottomNB_set_active_page {FindInFiles}"\
+ -helptext [mc "Find in files %s" ""] \
+ -createcmd [list $this CreateFindInFilesGUI] \
+ ]
+
+ # Tab "Hide"
+ $pri_notebook insert end {Hide} \
+ -text [mc "Hide"] \
+ -image ::ICONS::16::2downarrow \
+ -raisecmd "$this bottomNB_show_hide" \
+ -helptext [mc "Hide this panel"] \
+
+ ## Create Secondary NoteBook tabs
+ # tab "Simulator"
+ $sec_notebook insert end {Simulator} \
+ -text [mc "Simulator"] \
+ -image ::ICONS::16::kcmmemory \
+ -raisecmd "$this bottomNB_show_hide Simulator" \
+ -helptext [mc "Simulator panel %s" "(Ctrl+1)"]
+ # tab "C variables"
+ $sec_notebook insert end {CVarsView} \
+ -text [mc "C variables"] \
+ -image ::ICONS::16::player_playlist \
+ -raisecmd "$this bottomNB_show_hide CVarsView" \
+ -helptext [mc "Variables from C source code %s" ""]
+ # tab "Graph"
+ $sec_notebook insert end {Graph} \
+ -text [mc "IO Ports"] \
+ -image ::ICONS::16::graph \
+ -raisecmd "$this bottomNB_show_hide Graph" \
+ -helptext [mc "Graph showing state of MCU ports %s" "(Ctrl+2)"]
+ # tab "Messages"
+ $sec_notebook insert end {Messages} \
+ -text [mc "Messages"] \
+ -image ::ICONS::16::kcmsystem \
+ -raisecmd "$this bottomNB_show_hide Messages" \
+ -helptext [mc "Compiler messages %s" "(Ctrl+3)"]
+ # tab "Notes"
+ $sec_notebook insert end {Todo} \
+ -text [mc "Notes"] \
+ -image ::ICONS::16::camera_test \
+ -raisecmd "$this bottomNB_show_hide Todo" \
+ -helptext [mc "Personal todo list & notepad %s" "(Ctrl+4)"]
+ # tab "Calculator"
+ $sec_notebook insert end {Calculator} \
+ -text [mc "Calculator"] \
+ -image ::ICONS::16::xcalc \
+ -raisecmd "$this bottomNB_show_hide Calculator" \
+ -helptext [mc "Scientific calculator %s" "(Ctrl+5)"]
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no terminal emulator
+ # tab "Terminal"
+ $sec_notebook insert end {Terminal} \
+ -text [mc "Terminal"] \
+ -image ::ICONS::16::terminal \
+ -raisecmd "$this bottomNB_show_hide Terminal" \
+ -helptext [mc "Terminal emulator %s" ""] \
+ -state [expr {${::PROGRAM_AVALIABLE(urxvt)} ? "normal" : "disabled"}]
+ }
+ # tab "Find in files"
+ $sec_notebook insert end {FindInFiles} \
+ -text [mc "Find in files"] \
+ -image ::ICONS::16::filefind \
+ -raisecmd "$this bottomNB_show_hide FindInFiles" \
+ -helptext [mc "Find in files %s" ""] \
+ -createcmd [list $this CreateFindInFilesGUI]
+ # tab "Show"
+ $sec_notebook insert end {Show} \
+ -text [mc "Show"] \
+ -image ::ICONS::16::2uparrow \
+ -raisecmd "$this bottomNB_show_hide" \
+ -helptext [mc "Show this panel"]
+
+ # Prepare panel componenets but do not create GUI elements
+ PrepareCalculator $calculator_frame $calculatorList
+ PrepareGraph $graph_frame $graph_config
+ PrepareMessages $messages_frame
+ PrepareTodo $todo_frame $todoText
+ PrepareSimulator $simulator_frame
+ PrepareCVarsView $cvarsview_frame
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no terminal emulator
+ PrepareTerminal $terminal_frame
+ }
+ PrepareFindInFiles $findinfiles_frame
+
+
+ # take case of proper pane resizing
+ bind $parentPane <ButtonRelease-1> "$this bottomNB_panel_set_size"
+
+ # Show primary notebook if panel is visible or secondary notebook ohterwise
+ if {$PanelVisible != 0} {
+ pack $pri_notebook -expand 1 -fill both
+ $parentPane paneconfigure $main_frame -minsize 190
+ $parentPane configure -sashwidth 2
+
+ # Raise tab
+ catch {$pri_notebook raise $active_page}
+ } {
+ pack $sec_notebook -anchor nw -fill x -expand 1
+ $parentPane paneconfigure $main_frame -minsize 0
+ $parentPane configure -sashwidth 0
+ bind $parentPane <Button> {break}
+ set last_PanelSize $PanelSize
+ set PanelSize 24
+ }
+ }
+
+ ## Return true if the panel is visible
+ # @return bool result
+ public method isBottomPanelVisible {} {return $PanelVisible}
+
+ ## Return panel height
+ # @return int panle height
+ public method getBottomPanelSize {} {
+ if {$PanelVisible} {
+ return $PanelSize
+ } {
+ return $last_PanelSize
+ }
+ }
+
+ ## Return ID of active page of the NoteBook
+ # @return String Active page
+ public method getBottomPanelActivePage {} {return $active_page}
+
+ ## Set active page for both notebooks (primary and secondary)
+ # This function may also inform GUI of new active page about that it has became active
+ # @parm String pageName - ID of page to set
+ # @return void
+ public method bottomNB_set_active_page {pageName} {
+ switch -- $pageName {
+ Simulator {$this SimulatorTabRaised}
+ CVarsView {$this CVarsViewTabRaised}
+ Graph {$this GraphTabRaised}
+ Messages {$this MessagesTabRaised}
+ Todo {$this TodoTabRaised}
+ Calculator {$this CalculatorTabRaised}
+ FindInFiles {$this FindInFilesTabRaised}
+ }
+ set active_page $pageName
+ }
+
+ ## Show or hide the panel
+ # @parm String args = NULL - name of active page (show panel)
+ # @return void
+ public method bottomNB_show_hide args {
+
+ # If panel hidding is disabled -- abort
+ if {!$panel_hidding_ena} {return}
+
+ # Hide the panel
+ if {$PanelVisible} {
+ $parentPane paneconfigure $main_frame -minsize 0
+
+ # Ged rid of primary notebook
+ pack forget $pri_notebook ;# Hide primary notebook
+ set last_PanelSize $PanelSize ;# Save current panel size
+ set PanelSize 24 ;# Set New panel size
+ bottomNB_redraw_pane ;# Perform hidding
+
+ # Create and show secondary notebook
+ pack $sec_notebook -anchor nw -fill x -expand 1
+ $sec_notebook compute_size
+ set panel_hidding_ena 0
+ $sec_notebook raise $active_page
+ set panel_hidding_ena 1
+ $parentPane configure -sashwidth 0
+ bind $parentPane <Button> {break}
+
+ # Panel is now hidden
+ set PanelVisible 0
+
+ # Show the panel
+ } {
+ $parentPane paneconfigure $main_frame -minsize 190
+
+ # Hide secondary notebook
+ pack forget $sec_notebook
+
+ # Create and show primary notebook
+ set PanelSize $last_PanelSize ;# Restore panel size
+ bottomNB_redraw_pane ;# Perform showing
+ # Raise active page
+ if {$args == {}} {
+ $pri_notebook raise $active_page
+ } {
+ $pri_notebook raise $args
+ }
+ # Pack primary notebook
+ pack $pri_notebook -expand 1 -fill both
+ # Restore sash width
+ $parentPane configure -sashwidth 2
+ bind $parentPane <Button> {}
+
+ # Panel is now shown
+ set PanelVisible 1
+ }
+
+ update idle
+ $this editor_procedure {} Configure {}
+ }
+
+ ## Get true panel size and store it into variable PanelSize
+ # @return void
+ public method bottomNB_panel_set_size {} {
+ set PanelSize [lindex [$parentPane sash coord 0] 1]
+ set PanelSize [expr {[winfo height $parentPane] - $PanelSize}]
+
+ update idle
+ $this editor_procedure {} Configure {}
+ $this editor_procedure {} goto \
+ [$this editor_procedure {} get_current_line_number {}]
+ }
+
+ ## Move panel pane up by the given number of pixels
+ # @parm Int by - pixels
+ # @return void
+ public method bottomNB_move_pane_up {by} {
+ update idle
+ $parentPane sash place 0 0 [expr {[winfo height $parentPane] - $PanelSize - $by}]
+ }
+
+ ## Redraw panel pane
+ # @return void
+ public method bottomNB_redraw_pane {} {
+ update idle
+ $parentPane sash place 0 0 [expr {[winfo height $parentPane] - $PanelSize}]
+ }
+
+ ## Redraw panel pane on expose event
+ # @return void
+ public method bottomNB_redraw_pane_on_expose {} {
+ if {$redraw_pane_in_progress} {
+ after 50 "$this bottomNB_redraw_pane_on_expose"
+ return
+ }
+ set redraw_pane_in_progress 1
+
+ update idle
+ $parentPane sash place 0 0 [expr {[winfo height $parentPane] - $PanelSize}]
+ update idle
+
+ set redraw_pane_in_progress 0
+ }
+
+ ## Raise specified page
+ # This function should not be bypased
+ # @parm String page - ID of page to show
+ # @return void
+ public method bottomNB_show_up {page} {
+ if {$PanelVisible} {
+ $pri_notebook raise $page
+ } {
+ bottomNB_show_hide $page
+ }
+ }
+
+ ## Destroy current simulator control panel and create a new one
+ # @return void
+ public method simulator_itialize_simulator_control_panel {} {
+ foreach wdg [winfo children $simulator_frame] {
+ destroy $wdg
+ }
+ $this sumulator_clear_widgets
+ PrepareSimulator $simulator_frame
+ CreateSimulatorGUI
+ }
+
+ ## Destroy current graph panel and create a new one
+ # @return void
+ public method graph_itialize_simulator_graph_panel {graph_config} {
+ $this graph_change_mcu
+ }
+} \ No newline at end of file
diff --git a/lib/bottompanel/calculator.tcl b/lib/bottompanel/calculator.tcl
new file mode 100755
index 0000000..5196b40
--- /dev/null
+++ b/lib/bottompanel/calculator.tcl
@@ -0,0 +1,2071 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+#
+# --------------------------------------------------------------------------
+
+class Calculator {
+
+ common count 0 ;# counter of instances
+ # Font for numerical keypad
+ common large_font [font create \
+ -family {helveticat} \
+ -size -12 \
+ -weight {bold} \
+ ]
+
+ common oper_fg_color {#0000FF} ;# Foreground color for operator display
+ common error_bg_color {#FF6666} ;# Background color for display containing too many characters
+ common display_bg_color {#DDFFDD} ;# Background color for main display
+ common buffer_bg_color {#DDDDFF} ;# Background color for buffer display
+
+ # Variables related to object initialization
+ private variable parent ;# Teportary variable -- GUI parent
+ private variable calculatorList ;# Teportary variable -- COnfiguration list
+ private variable gui_initialized 0 ;# Bool: GUI created
+
+ # GUI variables
+ private variable calc_num_keypad ;# Container of left side of calc. (keypad)
+ private variable calc_num_display ;# Container for right side (displays etc.)
+ private variable calc_timers_calc ;# ID of label frame of timer preset calculator
+ private variable calc_display_widget ;# ID of main display widget
+ private variable calc_oper_widget ;# ID of operator display widget
+ private variable calc_buffer_widget ;# ID of buffer display widget
+ private variable timerscalc_THxDec_label ;# ID of THx (dec) label
+ private variable timerscalc_THxHex_label ;# ID of THx (hex) label
+ private variable timerscalc_THxOct_label ;# ID of THx (oct) label
+ private variable timerscalc_TLxDec_label ;# ID of TLx (dec) label
+ private variable timerscalc_TLxHex_label ;# ID of TLx (hex) label
+ private variable timerscalc_TLxOct_label ;# ID of TLx (oct) label
+ private variable timerscalc_RepeatDec_label ;# ID of Repeat (dec) label
+ private variable timerscalc_RepeatHex_label ;# ID of Repeat (hex) label
+ private variable timerscalc_RepeatOct_label ;# ID of Repeat (oct) label
+ private variable timerscalc_CorrectionDec_label ;# ID of Correction (dec) label
+ private variable timerscalc_CorrectionHex_label ;# ID of Correction (hex) label
+ private variable timerscalc_CorrectionOct_label ;# ID of Correction (oct) label
+ private variable timerscalc_freq_entry ;# ID of frequency entry widget
+ private variable timerscalc_mode_spinbox ;# ID of mode spinbox widget
+ private variable timerscalc_time_entry ;# ID of tim entry widget
+ private variable mem_entry_0 ;# ID of memory 0 entry widget
+ private variable mem_entry_1 ;# ID of memory 1 entry widget
+ private variable mem_entry_2 ;# ID of memory 2 entry widget
+
+ # Core variables
+ private variable base ;# Numeric base (Hex, Dec. Oct, Bin)
+ private variable last_base ;# Last numeric base
+ private variable angle ;# Angle unit (rad, deg, grad)
+ private variable last_angle ;# Last angle unit
+ private variable calc_oper {} ;# Chosen mathematical operation
+ private variable calc_oper_h ;# Human readible $calc_oper
+ private variable calc_last_oper ;# Last $calc_oper
+ private variable calc_display ;# Actual display text variable
+ private variable calc_buffer ;# Last display text variable
+ private variable calc_last_display ;# Var. for UNDO/REDO (takes back $calc_display)
+ private variable calc_last_buffer ;# Var. for UNDO/REDO (takes back $calc_buffer)
+ private variable ena_undo 0 ;# Undo enabled
+ private variable ena_redo 0 ;# Redo enabled
+ private variable after_eval 0 ;# Clear display if actual display val. is result of last operation
+ private variable scrollable_frame ;# Widget: Scrollable area (parent for all other widgets)
+ private variable horizontal_scrollbar ;# Widget: Horizontal scrollbar for scrollable area
+
+ # other public variables
+ private variable calc_idx ;# number of current instance
+ private variable timerscalc_validation_dis 1 ;# Disabled validation of timers calc
+
+ # definition of calculator keyboard
+ # {
+ # # row
+ # { # button
+ # {text path_part command_postfix
+ # columnspan rowspan
+ # helptext width
+ # height bgColor
+ # activeBackground bool_large_font
+ # }
+ # {separator}
+ # }
+ # }
+ common calculator_keyboard {
+ {
+ {{AND} {and} {calc_opr and 1} {} {}
+ {Bit-wise AND}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Bit-wise AND. Valid for integer operands only.}}
+ {{Sin} {S} {calc_opr Sin 1} {} {}
+ {Sine}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Sine}}
+ {{Cos} {Cs} {calc_opr Cos 1} {} {}
+ {Cosine}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Cosine}}
+ {{Tan} {T} {calc_opr Tan 1} {} {}
+ {Tangent}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Tangent}}
+ {{A} {A} {calc_val A} {} {} {} {} {} {5} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{F} {F} {calc_val F} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{/} {div} {calc_opr div 1} {} {} {} {} {} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ {{*} {mul} {calc_opr mul 1} {} {} {} {} {} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ {{-} {min} {calc_opr min 1} {} {} {} {} {} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ } {
+ {{OR} {or} {calc_opr or 1} {} {}
+ {Bit-wise OR}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Bit-wise OR. Valid for integer operands only.}}
+ {{ASin} {AS} {calc_opr ASin 1} {} {}
+ {Arc sine}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Arc sine. Argument should be in the range \[-1,1\].}}
+ {{ACos} {AC} {calc_opr ACos 1} {} {}
+ {Arc cosine}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Arc cosine. Argument should be in the range \[-1,1\].}}
+ {{ATan} {AT} {calc_opr ATan 1} {} {}
+ {Arc tangent}
+ {5} {} {} {Calculator_RED} {#FFDDDD} 0
+ {Arc tangent}}
+
+ {{B} {B} {calc_val B} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{7} {7} {calc_val 7} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{8} {8} {calc_val 8} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{9} {9} {calc_val 9} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{+} {add} {calc_opr add 1} {} {2} {} {} {2} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ } {
+ {{NOT} {not} {calc_opr not 1} {} {}
+ {Bit-wise NOT}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Bit-wise NOT. Valid for integer operands only.}}
+ {{e**} {exp} {calc_opr Exp 1} {} {}
+ {Exponential of argument (e**arg)}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Exponential of argument (e**arg)}}
+ {{sqrt} {sqr} {calc_opr Sqr 1} {} {}
+ {Square root}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Square root. Argument must be non-negative.}}
+ {{pow} {power} {calc_opr pow 1} {} {}
+ {Power}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Computes the value of x raised to the power y. If x is negative, y must be an integer value.}}
+
+ {{C} {C} {calc_val C} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{4} {4} {calc_val 4} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{5} {5} {calc_val 5} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{6} {6} {calc_val 6} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ } {
+ {{XOR} {xor} {calc_opr xor 1} {} {}
+ {Bit-wise exclusive OR}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Bit-wise exclusive OR. Valid for integer operands only.}}
+ {{Log} {L} {calc_opr Log 1} {} {}
+ {Base 10 logarithm}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Returns the base 10 logarithm of argument. Argument must be a positive value.}}
+ {{Ln} {Ln} {calc_opr Ln 1} {} {}
+ {Natural logarithm}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Returns the natural logarithm of argument. Argument must be a positive value.}}
+ {{PI} {P} {calc_val PI} {} {}
+ {Constant Pi}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Constant Pi}}
+
+ {{D} {D} {calc_val D} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{1} {1} {calc_val 1} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{2} {2} {calc_val 2} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{3} {3} {calc_val 3} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{=} {=} {calc_Evaluate} {} {2} {} {} {2} {} {Calculator_YELLOW} {#FFFFDD} 1}
+ } {
+ {{>>} {right} {calc_opr right 1} {} {}
+ {Right shift}
+ {5} {} {} {Calculator_GREEN} {#CCFFCC} 0
+ {Right shift. Valid for integer operands only. A right shift always propagates the sign bit.}}
+ {{Mod} {M} {calc_opr mod 1} {} {}
+ {Modulo}
+ {5} {} {} {Calculator_CYAN} {#AAFFFF} 0
+ {Computes remainder of integer division}}
+ {{UNDO} {U} {calc_UNDO} {} {}
+ {Undo last operation}
+ {5} {} {} {Calculator_GRAY} {#F8F8F8} 0
+ {Undo last operation. Not all operations are supported.}}
+ {{REDO} {RE} {calc_REDO} {} {}
+ {Take back last undo operation}
+ {5} {} {} {Calculator_GRAY} {#F8F8F8} 0
+ {Take back last undo operation. Not all operations are supported.}}
+
+ {{E} {E} {calc_val E} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ {{0} {0} {calc_val 0} {2} {} {} {5} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+
+ {{.} {dot} {calc_val .} {} {} {} {} {} {} {Calculator_PURPLE} {#DDDDFF} 1}
+ }
+ }
+
+ ## object constructor
+ constructor {} {
+ # Initialize some variables
+ incr count ;# Instance counter
+ set calc_idx $count ;# Index of this object
+ set base Dec ;# Default numeric base
+ set angle rad ;# Default angle unit
+ set last_base $base ;# Last numeric base
+ set last_angle $angle ;# Last angle unit
+
+ # Configure ttk styles
+ ttk::style configure Calculator_Buffer.TEntry \
+ -fieldbackground $buffer_bg_color
+ ttk::style configure Calculator_Oper.TEntry \
+ -fieldbackground {#FFDDDD} \
+ -fieldforeground $oper_fg_color \
+ -justify center
+ ttk::style configure Calculator_OperError.TEntry\
+ -fieldbackground {#FFDDDD} \
+ -foreground {#FF0000} \
+ -justify center
+ ttk::style configure Calculator_Display.TEntry \
+ -fieldbackground $display_bg_color
+ ttk::style configure Calculator_Error.TEntry \
+ -fieldbackground $error_bg_color
+
+ ttk::style configure Calculator_GREEN.TButton -padding 2
+ ttk::style map Calculator_GREEN.TButton \
+ -background [list active {#AAFFAA} {!active !disabled} {#CCFFCC} disabled {#DDEEDD}]
+
+ ttk::style configure Calculator_RED.TButton -padding 2
+ ttk::style map Calculator_RED.TButton \
+ -background [list active {#FFAAAA} {!active !disabled} {#FFDDDD} disabled {#EEDDDD}]
+
+ ttk::style configure Calculator_CYAN.TButton -padding 2
+ ttk::style map Calculator_CYAN.TButton \
+ -background [list active {#88EEEE} {!active !disabled} {#AAFFFF} disabled {#DDEEEE}]
+
+ ttk::style configure Calculator_GRAY.TButton -padding 2
+ ttk::style map Calculator_GRAY.TButton \
+ -background [list active {#DDDDDD} {!active !disabled} {#F8F8F8} disabled {#EEEEEE}]
+
+ ttk::style configure Calculator_PURPLE.TButton -padding 2 -font $large_font
+ ttk::style map Calculator_PURPLE.TButton \
+ -background [list active {#AAAAFF} {!active !disabled} {#DDDDFF} disabled {#DDDDEE}]
+
+ ttk::style configure Calculator_YELLOW.TButton -padding 2 -font $large_font
+ ttk::style map Calculator_YELLOW.TButton \
+ -background [list active {#FFFFAA} {!active !disabled} {#FFFFDD} disabled {#EEEEDD}]
+ }
+
+ ## object destructor
+ destructor {
+ # Unallocate GUI related variables
+ catch {
+ unset ::Calculator::calc_base$calc_idx
+ unset ::Calculator::calc_angle$calc_idx
+ unset ::Calculator::calc_buffer$calc_idx
+ unset ::Calculator::calc_oper$calc_idx
+ unset ::Calculator::calc_displ$calc_idx
+ unset ::Calculator::calc_mem0_$calc_idx
+ unset ::Calculator::calc_mem1_$calc_idx
+ unset ::Calculator::calc_mem2_$calc_idx
+ }
+ }
+
+ ## Append given value to the end of the display
+ # Use carefully, it does not check value validity !
+ # @parm String value - value to append
+ # @return String - new display content
+ public method calc_val {value} {
+ # Read raw content of the main display
+ reread_display 1
+
+ # Insert PI
+ if {$value == {PI}} {
+ # Conver PI to selected numeric base
+ switch -- $base {
+ {Hex} {set value [NumSystem::dec2hex ${Angle::PI}]}
+ {Dec} {set value ${Angle::PI}}
+ {Oct} {set value [NumSystem::dec2oct ${Angle::PI}]}
+ {Bin} {set value [NumSystem::dec2bin ${Angle::PI}]}
+ }
+ # Save current values
+ set calc_last_display [reread_display] ;# Main display
+ set calc_last_buffer [reread_buffer] ;# Buffer
+ # Clear main display
+ set calc_display {}
+ # Save current opetaror
+ set calc_last_oper $calc_oper
+ enable_undo ;# enable UNDO operation
+
+ # Clear main display if current value is result of the last operation
+ } elseif {$after_eval} {
+ set calc_last_display $calc_display ;# Save current content of display
+ set calc_last_buffer {}
+ set calc_last_oper {}
+ set calc_display {}
+ set after_eval 0
+ enable_undo ;# enable UNDO operation
+ }
+
+ # Append given value to the end of main display
+ set tmp "$calc_display$value"
+ if {[calc_validate $calc_display_widget $tmp]} {
+ set ::Calculator::calc_displ$calc_idx $tmp
+
+ catch {
+ $calc_display_widget delete sel.first sel.last
+ }
+ }
+
+ $calc_display_widget icursor end
+ $calc_buffer_widget icursor end
+ return $calc_display
+ }
+
+ ## Choose mathematical operation
+ # @parm String operation - Selected operation
+ # @parm Bool external - Evaluate result
+ # @return void
+ public method calc_opr {operation external} {
+
+ # Save current operator and set the new one
+ set calc_last_oper $calc_oper
+ set calc_oper $operation
+ # Clear displays if external
+ if {$external} {
+ set calc_last_display [reread_display]
+ set calc_last_buffer [reread_buffer]
+ set calc_buffer $calc_display
+ set calc_display {}
+ enable_undo
+ rewrite_buffer
+ rewrite_display
+ }
+
+ # Evaluate specified operation
+ switch -- $operation {
+ {div} { ;# Division
+ set calc_oper_h {/}
+ }
+ {mul} { ;# Multiplication
+ set calc_oper_h {*}
+ }
+ {min} { ;# Subtraction
+ set calc_oper_h {-}
+ }
+ {add} { ;# Addition
+ set calc_oper_h {+}
+ }
+ {pow} { ;# Power
+ set calc_oper_h {**}
+ }
+ {mod} { ;# Modulo
+ set calc_oper_h {mod}
+ }
+ {and} { ;# Bit-wise and
+ set calc_oper_h {&}
+ }
+ {or} { ;# Bit-wise inclusive or
+ set calc_oper_h {|}
+ }
+ {xor} { ;# Bit-wise exclusive or
+ set calc_oper_h {^}
+ }
+ {right} { ;# Right shift
+ set calc_oper_h {>>}
+ }
+
+ {not} { ;# Bit-wise inversion
+ set calc_oper_h {~}
+ if {$external} {calc_Evaluate}
+ }
+ {Exp} { ;# Exponential of argument
+ set calc_oper_h {e**}
+ if {$external} {calc_Evaluate}
+ }
+ {Sqr} { ;# Square root
+ set calc_oper_h {sqrt}
+ if {$external} {calc_Evaluate}
+ }
+ {Log} { ;# Decimal logarithm
+ set calc_oper_h {lg}
+ if {$external} {calc_Evaluate}
+ }
+ {Ln} { ;# Natural logarithm
+ set calc_oper_h {ln}
+ if {$external} {calc_Evaluate}
+ }
+ {Sin} { ;# Sine
+ set calc_oper_h {sin}
+ if {$external} {calc_Evaluate}
+ }
+ {Cos} { ;# Cosine
+ set calc_oper_h {cos}
+ if {$external} {calc_Evaluate}
+ }
+ {Tan} { ;# Tangent
+ set calc_oper_h {tan}
+ if {$external} {calc_Evaluate}
+ }
+ {ASin} { ;# Arc sine
+ set calc_oper_h {asin}
+ if {$external} {calc_Evaluate}
+ }
+ {ACos} { ;# Arc cosine
+ set calc_oper_h {acos}
+ if {$external} {calc_Evaluate}
+ }
+ {ATan} { ;# Acr cotangent
+ set calc_oper_h {atan}
+ if {$external} {calc_Evaluate}
+ }
+ default { ;# No operand
+ set calc_oper_h {}
+ }
+ }
+
+ # Display selected operand
+ set ::Calculator::calc_oper$calc_idx $calc_oper_h
+ }
+
+ ## Perform operation with calulator memory
+ # @parm String action - "Save" (to main display) or "Load" (from main display)
+ # @parm Int cell - Index of memory cell
+ # @return void
+ public method mem {action cell} {
+ if {$action == {Save}} {
+ # Show message on status bar
+ Sbar [mc "Calculator: M%s saved" $cell]
+ # Save content of main display
+ set calc_mem [reread_display]
+ if {[regexp {\.0$} $calc_mem]} {
+ set calc_mem [string range $calc_mem 0 {end-2}]
+ }
+ set ::Calculator::calc_mem${cell}_$calc_idx $calc_mem
+ } {
+ # Load memory content into main display
+ set calc_display [subst "\$::Calculator::calc_mem${cell}_$calc_idx"]
+ rewrite_display
+ }
+ }
+
+ ## Perform evaluation of given mathematical expression
+ # @return void
+ public method calc_Evaluate {} {
+
+ ## Check for presence of nessesary values
+ # * For unary operations
+ set display [reread_display]
+ set buffer [reread_buffer]
+ if {$buffer == {} || $buffer == {-}} {
+ Sbar [mc "Calculator: Unable to evaluate, missing argument"]
+ return 0
+ }
+ if {$calc_oper == {}} {
+ Sbar [mc "Calculator: Unable to evaluate, missing operator"]
+ return 0
+ }
+ # * For binary operations
+ if {
+ $calc_oper == {div} || $calc_oper == {mul} ||
+ $calc_oper == {min} || $calc_oper == {add} ||
+ $calc_oper == {pow} || $calc_oper == {mod} ||
+ $calc_oper == {and} || $calc_oper == {or} ||
+ $calc_oper == {xor} || $calc_oper == {nand}
+ } {
+ # Check display value length
+ if {$display == {}} {
+ Sbar [mc "Calculator: Unable to evaluate, missing argument"]
+ return 0
+ }
+ }
+
+ # Make backup for display, buffer and operator
+ enable_undo ;# enable UNDO operation
+ set calc_last_display $display
+ set calc_last_buffer $buffer
+
+ # Load up content of buffer and display
+ read_buffer_inDec
+ read_display_inDec
+
+ # Perform evaluation in safe environment
+ if {[catch {
+ switch -- $calc_oper {
+ {and} { ;# Bit-wise and
+ set calc_display [expr {wide($calc_buffer) & wide($calc_display)}]
+ }
+ {or} { ;# Bit-wise or
+ set calc_display [expr {wide($calc_buffer) | wide($calc_display)}]
+ }
+ {xor} { ;# Bit-wise xor
+ set calc_display [expr {wide($calc_buffer) ^ wide($calc_display)}]
+ }
+ {right} { ;# Right shift
+ set tmp [expr {wide($calc_display)}]
+ if {$tmp > 0} {
+ set calc_display [expr {wide($calc_buffer) >> $tmp}]
+ } elseif {$tmp < 0} {
+ set calc_display [expr {wide($calc_buffer) << abs($tmp)}]
+ } else {
+ set calc_display [expr {wide($calc_buffer)}]
+ }
+ }
+ {mul} { ;# Multiplication
+ set calc_display [expr {$calc_buffer * $calc_display}]
+ }
+ {min} { ;# Subtraction
+ set calc_display [expr {$calc_buffer - $calc_display}]
+ }
+ {add} { ;# Addtion
+ set calc_display [expr {$calc_buffer + $calc_display}]
+ }
+ {mod} { ;# Modulo
+ set calc_display [expr {int(fmod($calc_buffer,$calc_display))}]
+ }
+ {pow} { ;# Power
+ set calc_display [expr {pow($calc_buffer, $calc_display)}]
+ }
+ {div} { ;# Division
+ if {$calc_display == 0} {
+ Sbar [mc "Calculator: WARNING result is +/- infinity => operation terminated !"]
+ return
+ }
+ if {![regexp {\.} $calc_buffer]} {
+ set calc_buffer "$calc_buffer.0"
+ }
+ set calc_display [expr {$calc_buffer / $calc_display}]
+ }
+ {not} { ;# Bit-wise inversion
+ set len [string length [format {%X} [expr {int($calc_buffer)}]]]
+ if {$len > 8} {
+ Sbar [mc "Calculator: This value is too high to invert (max. 0xFFFFFFFF)"]
+ return
+ }
+ incr len -1
+ set calc_display [expr {0x7FFFFFFF ^ int($calc_buffer)}]
+ set calc_display [format {%X} $calc_display]
+ set calc_display [string range $calc_display end-$len end]
+ set calc_display [expr "0x$calc_display"]
+ }
+ {Exp} { ;# Exponential of argument
+ set calc_display [expr {exp($calc_buffer)}]
+ }
+ {Sqr} { ;# Square root
+ set calc_display [expr {sqrt($calc_buffer)}]
+ }
+ {Log} { ;# Decimal logarithm
+ set calc_display [expr {log10($calc_buffer)}]
+ }
+ {Ln} { ;# Natiral logarithm
+ set calc_display [expr {log($calc_buffer)}]
+ }
+ {ASin} { ;# Arc sine
+ set calc_display [expr {asin($calc_buffer)}]
+ set calc_display [rad_to_Xangle $calc_display]
+ }
+ {ACos} { ;# Arc cosine
+ set calc_display [expr {acos($calc_buffer)}]
+ set calc_display [rad_to_Xangle $calc_display]
+ }
+ {ATan} { ;# Arc Tangent
+ set calc_display [expr {atan($calc_buffer)}]
+ set calc_display [rad_to_Xangle $calc_display]
+ }
+ {Sin} { ;# Sine
+ set calc_buffer [Xangle_to_rad $calc_buffer]
+ set calc_display [expr {sin($calc_buffer)}]
+ }
+ {Cos} { ;# Cosine
+ set calc_buffer [Xangle_to_rad $calc_buffer]
+ set calc_display [expr {cos($calc_buffer)}]
+ }
+ {Tan} { ;# Arc tangent
+ set calc_buffer [Xangle_to_rad $calc_buffer]
+ set calc_display [expr {tan($calc_buffer)}]
+ }
+ }
+ }]} {
+ # If error occured -> show error message
+ Sbar [mc "Calculator: ERROR (result value is out of allowed range)"]
+ return
+ }
+
+ # If result value contain exponent -> show error message
+ if {[regexp {e} $calc_display]} {
+ Sbar[mc "Calculator: Unable to evaluate, result value is too high"]
+ return
+ }
+
+ # Display result
+ set calc_buffer {}
+ set after_eval 1
+ rewrite_buffer
+ calc_opr {} 0
+ write_display_inXbase $calc_display
+ }
+
+ ## Safely clear display
+ # @return void
+ public method calc_ClearActual {} {
+ # enable UNDO operation
+ enable_undo
+ # save actual values
+ set calc_last_display [reread_display]
+ set calc_display {}
+ set calc_last_buffer [reread_buffer]
+ # show new values
+ rewrite_display
+ }
+
+ ## Safely clear display and buffer
+ # @return void
+ public method calc_Clear {} {
+ # enable UNDO operation
+ enable_undo
+ # save actual values
+ set calc_last_display [reread_display]
+ set calc_display {}
+ set calc_last_buffer [reread_buffer]
+ set calc_buffer {}
+ calc_opr {} 0
+ # show new values
+ rewrite_display
+ rewrite_buffer
+ }
+
+ ## Enable execution of UNDO operation and disable REDO
+ # @return void
+ private method enable_undo {} {
+ # set status
+ set ena_undo 1
+ set ena_redo 0
+ # enable/disable UNDO and REDO buttons
+ enable_buttons {U}
+ disable_buttons {RE}
+ }
+
+ ## Enable execution of REDO operation and disable UNDO
+ # @return void
+ private method enable_redo {} {
+ # set status
+ set ena_undo 0
+ set ena_redo 1
+ # enable/disable UNDO and REDO buttons
+ enable_buttons {RE}
+ disable_buttons {U}
+ }
+
+ ## Take back the last operation
+ # @return void
+ public method calc_UNDO {} {
+ # enable REDO operation
+ enable_redo
+ # ....
+ set after_eval 0
+ # save actual status and restore previous
+ calc_opr $calc_last_oper 0
+ set tmp [reread_display]
+ set calc_display $calc_last_display
+ set calc_last_display $tmp
+ set tmp [reread_buffer]
+ set calc_buffer $calc_last_buffer
+ set calc_last_buffer $tmp
+ # show new values
+ rewrite_display
+ rewrite_buffer
+ # inform user by starts bar
+ Sbar [mc "Calculator: UNDO: previous state was: %s %s %s" $calc_last_buffer $calc_last_oper $calc_last_display]
+ }
+
+ ## Take back the UNDO operation
+ # @return void
+ public method calc_REDO {} {
+ # enable UNDO operation
+ enable_undo
+ # save actual status and restore previous
+ calc_opr $calc_last_oper 0
+ set tmp [reread_display]
+ set calc_display $calc_last_display
+ set calc_last_display $tmp
+ set tmp [reread_buffer]
+ set calc_buffer $calc_last_buffer
+ set calc_last_buffer $tmp
+ # show new values
+ rewrite_display
+ rewrite_buffer
+ # inform user by starts bar
+ Sbar [mc "Calculator: REDO: previous state was: %s %s %s" $calc_last_buffer $calc_last_oper $calc_last_display]
+ }
+
+ ## Convert content of both displays and all merory cells using given command
+ # @parm String command - command to use for converion
+ # @return void
+ private method convert_displays {command} {
+
+ # Determinate what displays aren't empty
+ if {[reread_display] == {}} {set dis 0} {set dis 1}
+ if {[reread_buffer] == {}} {set buf 0} {set buf 1}
+
+ # Determinate what memory cells aren't empty
+ for {set i 0} {$i < 3} {incr i} {
+ set mem [[subst "\$mem_entry_$i"] get]
+ if {[string index $mem end] == {.}} {
+ append mem 0
+ }
+ set memory$i $mem
+ if {$mem == {} || $mem == 0} {
+ set mem$i 0
+ } {
+ set mem$i 1
+ }
+ }
+
+ # Convert all non empty displays
+ foreach cnd "$dis $buf $mem0 $mem1 $mem2" \
+ var {calc_display calc_buffer memory0 memory1 memory2} {
+ if {$cnd} {
+ if {[catch {
+ set $var [$command [subst "\$$var"]]
+ }]} {
+ Sbar [mc "Calculator: Value is too high to convert, value deleted !"]
+ set $var 0
+ }
+ }
+ }
+
+ # Display new content of memory cells
+ for {set i 0} {$i < 3} {incr i} {
+ [subst "\$mem_entry_$i"] delete 0 end
+ [subst "\$mem_entry_$i"] insert end [subst "\$memory$i"]
+ }
+ }
+
+ ## Switch numeric base
+ # @return void
+ public method cal_switchBase {} {
+
+ # Get chosen value
+ set base [subst "\$::Calculator::calc_base$calc_idx"]
+
+ # Convert display content to setected numeric system
+ if {$base == $last_base} {
+ set last_base $base
+ return
+ }
+
+ # Adjust value in display and buffer
+ if {[regexp {\.0$} $calc_display]} {
+ set calc_display [string range $calc_display 0 {end-2}]
+ }
+ if {[regexp {\.0$} $calc_buffer]} {
+ set calc_buffer [string range $calc_buffer 0 {end-2}]
+ }
+
+ # Covert content of all displays to new numeric base
+ switch -- $base {
+ {Hex} { ;# to Hexadecimal
+ enable_buttons {0 1 2 3 4 5 6 7 8 9 A B C D E F}
+ switch -- $last_base {
+ {Dec} {convert_displays NumSystem::dec2hex}
+ {Oct} {convert_displays NumSystem::oct2hex}
+ {Bin} {convert_displays NumSystem::bin2hex}
+ }
+ }
+ {Dec} { ;# to Decimal
+ disable_buttons {A B C D E F}
+ enable_buttons {0 1 2 3 4 5 6 7 8 9}
+ switch -- $last_base {
+ {Hex} {convert_displays NumSystem::hex2dec}
+ {Oct} {convert_displays NumSystem::oct2dec}
+ {Bin} {convert_displays NumSystem::bin2dec}
+ }
+ }
+ {Oct} { ;# to Octal
+ disable_buttons {8 9 A B C D E F}
+ enable_buttons {0 1 2 3 4 5 6 7}
+ switch -- $last_base {
+ {Hex} {convert_displays NumSystem::hex2oct}
+ {Dec} {convert_displays NumSystem::dec2oct}
+ {Bin} {convert_displays NumSystem::bin2oct}
+ }
+ }
+ {Bin} { ;# to Binary
+ disable_buttons {2 3 4 5 6 7 8 9 A B C D E F}
+ enable_buttons {0 1}
+ switch -- $last_base {
+ {Hex} {convert_displays NumSystem::hex2bin}
+ {Dec} {convert_displays NumSystem::dec2bin}
+ {Oct} {convert_displays NumSystem::oct2bin}
+ }
+ }
+ }
+
+ # Display new values
+ rewrite_display
+ rewrite_buffer
+
+ # set last value
+ set last_base $base
+ }
+
+ ## Disable buttons specified in the given list
+ # example: disable_buttons {1 2} ;# disable .calc_1_0 and .calc_2_0
+ # @return void
+ private method disable_buttons {buttons_list} {
+ foreach path $buttons_list {
+ $calc_num_keypad.calc_${path} \
+ configure -state disabled
+ }
+ }
+
+ ## Enable buttons specified in the given list
+ # example: enable_buttons {1 2} ;# enable .calc_1_0 and .calc_2_0
+ # @return void
+ private method enable_buttons {buttons_list} {
+ foreach path $buttons_list {
+ $calc_num_keypad.calc_${path} \
+ configure -state normal
+ }
+ }
+
+ ## Switch angle unit
+ # @return void
+ public method cal_switchAngle {} {
+
+ # Get chosen unit
+ set angle [subst "\$::Calculator::calc_angle$calc_idx"]
+
+ # Convert all displays
+ if {$angle != $last_angle} {
+ # Convert display if is not empty
+ if {[read_display_inDec] != {}} {
+ write_display_inXbase [Angle::${last_angle}2${angle} $calc_display]
+ }
+ # Convert buffer if is not empty
+ if {[read_buffer_inDec] != {}} {
+ write_buffer_inXbase [Angle::${last_angle}2${angle} $calc_buffer]
+ }
+ # Conver memory cells
+ for {set i 0} {$i <3} {incr i} {
+ # Get memory cell value
+ set mem [[subst "\$mem_entry_$i"] get]
+ # Adjust that value
+ if {[string index $mem end] == {.}} {
+ append mem 0
+ }
+ # Display new value
+ if {$mem != {}} {
+ set mem [Angle::${last_angle}2${angle} $mem]
+ [subst "\$mem_entry_$i"] delete 0 end
+ [subst "\$mem_entry_$i"] insert end $mem
+ }
+ }
+ }
+
+ # Set last unit
+ set last_angle $angle
+ }
+
+ ## Read content of main display in decimal system
+ # @return Float result
+ private method read_display_inDec {} {
+ # get display content
+ if {[reread_display] != {}} {
+ # convert to decimal value
+ if {$base != {Dec}} {
+ switch -- $base {
+ {Hex} { ;# from Hexadecimal
+ set calc_display [NumSystem::hex2dec $calc_display]
+ }
+ {Oct} { ;# from Octal
+ set calc_display [NumSystem::oct2dec $calc_display]
+ }
+ {Bin} { ;# from Binary
+ set calc_display [NumSystem::bin2dec $calc_display]
+ }
+ }
+ }
+ }
+ # done
+ return $calc_display
+ }
+
+ ## Write the given number (in dec) to main display (in selected base)
+ # @parm Float dec_content - number to display
+ # @return void
+ private method write_display_inXbase {dec_content} {
+
+ # If selected numeric base isn't Dec -> perform conversion
+ if {$base != {Dec}} {
+ switch -- $base {
+ {Hex} { ;# to Hexadecimal
+ if {[catch {
+ set calc_display [NumSystem::dec2hex $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, result is too high (cannot be displayed)"]
+ set calc_display 0
+ }
+ }
+ {Oct} { ;# to Octal
+ if {[catch {
+ set calc_display [NumSystem::dec2oct $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, result is too high (cannot be displayed)"]
+ set calc_display 0
+ }
+ }
+ {Bin} { ;# to Binary
+ if {[catch {
+ set calc_display [NumSystem::dec2bin $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, result is too high (cannot be displayed)"]
+ set calc_display 0
+ }
+ }
+ }
+ # If selected numeric base is Dec -> do nothing
+ } {
+ set calc_display $dec_content
+ }
+
+ # display (new) value
+ rewrite_display
+ }
+
+ ## Read content of buffer in decimal system
+ # @return Float result
+ private method read_buffer_inDec {} {
+ # Get content buffer display
+ if {[reread_buffer] != {}} {
+ # Convert to decimal value
+ if {$base != {Dec}} {
+ switch -- $base {
+ {Hex} { ;# from Hexadecimal
+ set calc_buffer [NumSystem::hex2dec $calc_buffer]
+ }
+ {Oct} { ;# from Octal
+ set calc_buffer [NumSystem::oct2dec $calc_buffer]
+ }
+ {Bin} { ;# from BInary
+ set calc_buffer [NumSystem::bin2dec $calc_buffer]
+ }
+ }
+ }
+ }
+ # done
+ return $calc_buffer
+ }
+
+ ## Write the given number (in dec) to buffer display (in selected base)
+ # @parm Float dec_content - number to display
+ # @return void
+ private method write_buffer_inXbase {dec_content} {
+
+ # If selected numeric base isn't Dec -> perform conversion
+ if {$base != {Dec}} {
+ switch -- $base {
+ {Hex} { ;# to Hexadecimal
+ if {[catch {
+ set calc_buffer [NumSystem::dec2hex $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, value is too high"]
+ set calc_buffer 0
+ }
+ }
+ {Oct} { ;# to Octal
+ if {[catch {
+ set calc_buffer [NumSystem::dec2oct $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, value is too high"]
+ set calc_buffer 0
+ }
+ }
+ {Bin} { ;# to Binary
+ if {[catch {
+ set calc_buffer [NumSystem::dec2bin $dec_content]
+ }]} {
+ Sbar [mc "Calculator: ERROR, value is too high"]
+ set calc_buffer 0
+ }
+ }
+ }
+ # If selected numeric base is Dec -> do nothing
+ } {
+ set calc_buffer $dec_content
+ }
+
+ # display (new) value
+ rewrite_buffer
+ }
+
+ ## Write adjusted content of variable calc_display to main display widget
+ # @return void
+ private method rewrite_display {} {
+ # Adust content of source variable
+ if {[regexp {\.0$} $calc_display]} {
+ set calc_display [string range $calc_display 0 {end-2}]
+ }
+ # Show its content
+ set ::Calculator::calc_displ$calc_idx $calc_display
+ }
+
+ ## Write adjusted content of variable calc_buffer to buffer display widget
+ # @return void
+ private method rewrite_buffer {} {
+ # Adust content of source variable
+ if {[regexp {\.0$} $calc_buffer]} {
+ set calc_buffer [string range $calc_buffer 0 {end-2}]
+ }
+ # Show its content
+ set ::Calculator::calc_buffer$calc_idx $calc_buffer
+ }
+
+ ## Read true content of main display widget converted
+ # @parm args = False - adjust to float
+ # @return Float - content of the main display
+ private method reread_display args {
+
+ # Get content of the widget
+ set calc_display [$calc_display_widget get]
+ regsub {\,} $calc_display {.} calc_display
+
+ # Adhust to float (if requested)
+ if {$args != 1} {
+ if {[regexp {^\.} $calc_display]} {
+ set calc_display "0$calc_display"
+ } elseif {[regexp {\.$} $calc_display]} {
+ append calc_display 0
+ }
+ if {[string first {.} $calc_display] == -1} {
+ append calc_display {.0}
+ }
+ }
+
+ # Remove trailing '.0'
+ if {[regexp {^\.0$} $calc_display]} {
+ set calc_display {}
+ }
+
+ # Return result
+ return $calc_display
+ }
+
+ ## Read true content of buffer display widget converted
+ # @return Float - content of the buffer
+ private method reread_buffer {} {
+
+ # Get content of the widget
+ set calc_buffer [$calc_buffer_widget get]
+ regsub {\,} $calc_buffer {.} calc_buffer
+
+ # Adhust to float
+ if {[regexp {^\.} $calc_buffer]} {
+ set calc_buffer "0$calc_buffer"
+ } elseif {[regexp {\.$} $calc_buffer]} {
+ append calc_buffer 0
+ }
+ if {[string first {.} $calc_buffer] == -1} {
+ append calc_buffer {.0}
+ }
+
+ # Remove trailing '.0'
+ if {[regexp {^\.0$} $calc_buffer]} {
+ set calc_buffer {}
+ }
+
+ # Return result
+ return $calc_buffer
+ }
+
+ ## Covert given angle to current angle unit
+ # @parm Float dec_angle - angle to convert in decimal
+ # @return Float - angle in radians
+ private method Xangle_to_rad {dec_angle} {
+ # If current angle unit isn't radians -> perform converison
+ if {$angle != {rad}} {
+ # From grad
+ if {$angle == {grad}} {
+ set dec_angle [Angle::grad2rad $dec_angle]
+ # From degrees
+ } {
+ set dec_angle [Angle::deg2rad $dec_angle]
+ }
+ }
+ # return result
+ return $dec_angle
+ }
+
+ ## Convert given angle in radians to current angle unit
+ # @parm Float dec_angle - angle to conver in radians (decimal)
+ # @return Float - converted angle
+ private method rad_to_Xangle {dec_angle} {
+ # If current angle unit isn't radians -> perform converison
+ if {$angle != {rad}} {
+ # To grad
+ if {$angle == {grad}} {
+ set dec_angle [Angle::rad2grad $dec_angle]
+ # To degrees
+ } {
+ set dec_angle [Angle::rad2deg $dec_angle]
+ }
+ }
+ # return result
+ return $dec_angle
+ }
+
+ ## Validate display content
+ # @parm Widget widget - entry widget
+ # @parm String content - content to validate
+ # @return bool - result
+ public method calc_validate {widget content} {
+
+ # Set default background color for that widget
+ if {$widget == $calc_display_widget} {
+ $widget configure -style Calculator_Display.TEntry
+ } elseif {$widget == $calc_buffer_widget} {
+ $widget configure -style Calculator_Buffer.TEntry
+ } else {
+ $widget configure -style TEntry
+ }
+
+ # Valid if content is empty
+ set len [string length $content]
+ if {$len == 0 || $content == {-}} {
+ return 1
+ }
+
+ # Invalid if content is too wide
+ if {$len > 40} {
+ Sbar [mc "Calculator: ERROR, value is too high"]
+ if {[string length [$widget get]] > 13} {
+ $widget configure -style Calculator_Error.TEntry
+ }
+ return 0
+ }
+
+ # Adjust content
+ regsub {\,} $content {.} content
+ if {[regexp {\.$} $content]} {
+ append content 0
+ }
+
+ # Check for valid numeric base
+ switch -- $base {
+ {Hex} {set content [NumSystem::ishex $content]}
+ {Dec} {set content [NumSystem::isdec $content]}
+ {Oct} {set content [NumSystem::isoct $content]}
+ {Bin} {set content [NumSystem::isbin $content]}
+ default {set content 0}
+ }
+
+ # Evaluate filan result
+ if {$content} {
+ if {$len > 13} {
+ $widget configure -style Calculator_Error.TEntry
+ }
+ return 1
+ } {
+ Sbar [mc "Calculator: Trying to insert invalid value"]
+ return 0
+ }
+ }
+
+ ## Validate content of operator diaplay
+ # @parm String content - string to validate
+ # @return Bool - result of validation
+ public method calc_oper_validate {content} {
+
+ # Check for length
+ if {[string length $content] > 4} {
+ return 0
+ }
+
+ # Check for allowed content
+ switch -- $content {
+ {/} {set calc_oper {div}}
+ {*} {set calc_oper {mul}}
+ {-} {set calc_oper {min}}
+ {+} {set calc_oper {add}}
+ {**} {set calc_oper {pow}}
+ {mod} {set calc_oper {mod}}
+ {&} {set calc_oper {and}}
+ {|} {set calc_oper {or}}
+ {^} {set calc_oper {xor}}
+ {>>} {set calc_oper {right}}
+ {~} {set calc_oper {not}}
+ {e**} {set calc_oper {Exp}}
+ {sqrt} {set calc_oper {Sqr}}
+ {lg} {set calc_oper {Log}}
+ {ln} {set calc_oper {Ln}}
+ {sin} {set calc_oper {Sin}}
+ {cos} {set calc_oper {Cos}}
+ {tan} {set calc_oper {Tan}}
+ {asin} {set calc_oper {ASin}}
+ {acos} {set calc_oper {ACos}}
+ {atan} {set calc_oper {ATan}}
+ default {
+ # Set foteground color to #FF0000 if content is invalid
+ set calc_oper {}
+ $calc_oper_widget configure -style Calculator_OperError.TEntry
+ return 1
+ }
+ }
+
+ # Set foreground color to default and return result (True)
+ $calc_oper_widget configure -style Calculator_Oper.TEntry
+ return 1
+ }
+
+ ## Negate content of the main display
+ # @return void
+ public method calc_NegateDis {} {
+ # Empty display -> abort
+ if {[reread_display] == {}} {
+ return
+
+ # Negate value
+ } {
+ if {[regexp {^\-} $calc_display]} {
+ set calc_display [string range $calc_display 1 end]
+ } {
+ set calc_display "-$calc_display"
+ }
+ }
+
+ # Write result
+ rewrite_display
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - parent widget (some frame)
+ # @parm List _calculatorList - List of initial values (displays,, memory, radix, angle unit)
+ # @return void
+ public method PrepareCalculator {_parent _calculatorList} {
+ set parent $_parent
+ set calculatorList $_calculatorList
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method CalculatorTabRaised {} {
+ $calc_display_widget selection range 0 end
+ $calc_display_widget icursor end
+ focus $calc_display_widget
+ }
+
+ ## Initialize calculator GUI
+ # @return void
+ public method CreateCalculatorGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Create scrollable area
+ set scrollable_frame [ScrollableFrame $parent.scrollable_frame \
+ -xscrollcommand "$this calc_gui_scroll_set" \
+ ]
+ set horizontal_scrollbar [ttk::scrollbar $parent.horizontal_scrollbar \
+ -orient horizontal -command "$scrollable_frame xview" \
+ ]
+ pack $scrollable_frame -fill both -side bottom -expand 1
+ set parent [$scrollable_frame getframe]
+
+ # LEFT HALF
+
+ # create numeric keypad
+ set calc_num_keypad [frame $parent.calc_num_keypad]
+ makeKeypad $calc_num_keypad $calculator_keyboard
+
+
+ # RIGHT HALF
+
+ # create display
+ set calc_num_display [frame $parent.calc_num_display]
+ set frame0 [frame $calc_num_display.calc_num_display0]
+ set frame1 [frame $calc_num_display.calc_num_display1]
+
+ # Buffer display
+ set calc_buffer_widget [ttk::entry $frame0.calc_buffer \
+ -textvariable ::Calculator::calc_buffer$calc_idx \
+ -validate key \
+ -validatecommand "$this calc_validate %W %P" \
+ -width 13 \
+ -style Calculator_Buffer.TEntry \
+ ]
+ DynamicHelp::add $frame0.calc_buffer -text [mc "Buffer display"]
+ setStatusTip -widget $calc_buffer_widget \
+ -text [mc "Calculator buffer"]
+ # Operator display
+ set calc_oper_widget [ttk::entry $frame0.calc_oper \
+ -textvariable ::Calculator::calc_oper$calc_idx \
+ -validate all \
+ -width 3 \
+ -validatecommand "$this calc_oper_validate %P" \
+ -style Calculator_Oper.TEntry \
+ ]
+ DynamicHelp::add $frame0.calc_oper -text [mc "Selected operation"]
+ setStatusTip -widget $calc_oper_widget \
+ -text [mc "Selected operation"]
+ # Main display
+ set calc_display_widget [ttk::entry $frame0.calc_displ \
+ -textvariable ::Calculator::calc_displ$calc_idx \
+ -validate key \
+ -validatecommand "$this calc_validate %W %P" \
+ -width 13 \
+ -style Calculator_Display.TEntry \
+ ]
+ DynamicHelp::add $frame0.calc_displ -text [mc "Main display"]
+ setStatusTip -widget $calc_display_widget \
+ -text [mc "Main display"]
+ # Pack displays
+ pack $calc_buffer_widget -side left
+ pack $calc_oper_widget -side left
+ pack $calc_display_widget -side left
+ # Create binding for displays
+ bind $calc_buffer_widget <KP_Enter> "$this calc_Evaluate"
+ bind $calc_oper_widget <KP_Enter> "$this calc_Evaluate"
+ bind $calc_display_widget <KP_Enter> "$this calc_Evaluate"
+ bind $calc_buffer_widget <Return> "$this calc_Evaluate"
+ bind $calc_oper_widget <Return> "$this calc_Evaluate"
+ bind $calc_display_widget <Return> "$this calc_Evaluate"
+
+
+ ## Create: numeric base and angle unit switch + CA + C
+ frame $frame1.lf
+ # Numeric base switch
+ pack [ttk::combobox $frame1.lf.calc_base_CB \
+ -state readonly \
+ -values {Hex Dec Oct Bin} \
+ -textvariable ::Calculator::calc_base$calc_idx \
+ -width 4 \
+ ] -side left
+ bind $frame1.lf.calc_base_CB <<ComboboxSelected>> "$this cal_switchBase"
+ DynamicHelp::add $frame1.lf.calc_base_CB -text [mc "Numeric base"]
+ setStatusTip -widget $frame1.lf.calc_base_CB \
+ -text [mc "Numeric base"]
+ # Angle unit switch
+ pack [ttk::combobox $frame1.lf.calc_angle_CB \
+ -state readonly \
+ -values {rad deg grad} \
+ -textvariable ::Calculator::calc_angle$calc_idx \
+ -width 4 \
+ ] -side left
+ bind $frame1.lf.calc_angle_CB <<ComboboxSelected>> "$this cal_switchAngle"
+ DynamicHelp::add $frame1.lf.calc_angle_CB -text [mc "Angle unit"]
+ setStatusTip -widget $frame1.lf.calc_angle_CB \
+ -text [mc "Angle unit"]
+ pack $frame1.lf -side left -padx 5
+
+ frame $frame1.rf
+ # Button "Clear"
+ pack [ttk::button $frame1.rf.calc_Clear \
+ -text {C} \
+ -command "$this calc_Clear" \
+ -width 3 \
+ ] -side left
+ DynamicHelp::add $frame1.rf.calc_Clear \
+ -text [mc "Clear both displays"]
+ setStatusTip -widget $frame1.rf.calc_Clear \
+ -text [mc "Clear both displays"]
+ # Button "Clear actual"
+ pack [ttk::button $frame1.rf.calc_Clear_act \
+ -text {CA} \
+ -command "$this calc_ClearActual" \
+ -width 3 \
+ ] -side left
+ DynamicHelp::add $frame1.rf.calc_Clear_act \
+ -text [mc "Clear main display"]
+ setStatusTip -widget $frame1.rf.calc_Clear_act \
+ -text [mc "Clear main display"]
+ # Button "Negate"
+ pack [ttk::button $frame1.rf.calc_Negate_dis \
+ -text {+/-} \
+ -command "$this calc_NegateDis" \
+ -width 3 \
+ ] -side left
+ DynamicHelp::add $frame1.rf.calc_Negate_dis \
+ -text [mc "Negate value in main display"]
+ setStatusTip -widget $frame1.rf.calc_Negate_dis \
+ -text [mc "Negate value in main display"]
+ pack $frame1.rf -side right -padx 5
+
+ # Create calculator memory cells
+ for {set i 0} {$i < 3} {incr i} {
+ # Determinate ID of target frame
+ set frame_id [frame $calc_num_display.calc_num_display[expr $i + 2]]
+ # Label "Mx:"
+ pack [Label $frame_id.calc_mem_label_${i} \
+ -text "M$i: " -helptext [mc "Memory bank %s" $i]\
+ ] -side left
+ setStatusTip -widget $frame_id.calc_mem_label_${i} \
+ -text [mc "Memory bank %s" $i]
+ # Entry widget
+ set entry [ttk::entry $frame_id.calc_mem_entry_${i} \
+ -textvariable ::Calculator::calc_mem${i}_${calc_idx} \
+ -validate all \
+ -validatecommand "$this calc_validate %W %P" \
+ ]
+ DynamicHelp::add $frame_id.calc_mem_entry_${i} -text [mc "Memory bank %s" $i]
+ pack $entry -side left
+ set mem_entry_$i $entry
+ setStatusTip -widget $entry -text [mc "Memory bank %s" $i]
+ # Button "Save"
+ pack [ttk::button $frame_id.calc_mem_save_button_${i} \
+ -text [mc "Save"] \
+ -command "$this mem Save $i" \
+ -width 5 \
+ ] -side left
+ DynamicHelp::add $frame_id.calc_mem_save_button_${i} \
+ -text [mc "Save content of main display to this memory bank %s" $i]
+ setStatusTip -widget $frame_id.calc_mem_save_button_${i} \
+ -text [mc "Save content of main display to this memory bank %s" $i]
+ # Button "Load"
+ pack [ttk::button $frame_id.calc_mem_load_button_${i} \
+ -text [mc "Load"] \
+ -command "$this mem Load $i" \
+ -width 5 \
+ ] -side left
+ DynamicHelp::add $frame_id.calc_mem_load_button_${i} \
+ -text [mc "Load content of this bank into main display"]
+ setStatusTip -widget $frame_id.calc_mem_load_button_${i} \
+ -text [mc "Load content of memory bank %s into calculator main display" $i]
+ }
+
+ bind $mem_entry_0 <Up> "focus $mem_entry_2"
+ bind $mem_entry_0 <Down> "focus $mem_entry_1"
+
+ bind $mem_entry_1 <Up> "focus $mem_entry_0"
+ bind $mem_entry_1 <Down> "focus $mem_entry_2"
+
+ bind $mem_entry_2 <Up> "focus $mem_entry_1"
+ bind $mem_entry_2 <Down> "focus $mem_entry_0"
+
+
+ # TIMERS CALC
+
+ set calc_timers_calc [ttk::labelframe $parent.calc_timers_calc -text [mc "Timers preset"]]
+ makeTimersCalc $calc_timers_calc
+
+
+ # INNER INITIALIZATION
+
+ # pack "left side" of calculator
+ pack $calc_num_keypad -side left
+
+ # pack "right side" of calculator
+ for {set i 0} {$i < 5} {incr i} {
+ if {$i == 1} {
+ pack $calc_num_display.calc_num_display${i} -pady 10
+ } {
+ pack $calc_num_display.calc_num_display${i}
+ }
+ }
+ pack $calc_num_display -side left -padx 10
+
+ # pack timres calc
+ pack $calc_timers_calc -side left -expand 0 -anchor nw
+
+ ## save data given by $calculatorList
+ # "$base $angle $calc_display $calc_oper $calc_buffer $calc_mem0 $calc_mem1 $calc_mem2"
+ set base [lindex $calculatorList 0]
+ set angle [lindex $calculatorList 1]
+ if {
+ $base != {Hex} && $base != {Dec} &&
+ $base != {Oct} && $base != {Bin}
+ } {
+ set base [lindex ${X::project_edit_defaults} {3 1}]
+ puts stderr [mc "Invalid numerical base: '%s'" $base]
+ }
+ if {$angle != {rad} && $angle != {deg} && $angle != {grad}} {
+ puts stderr [mc "Invalid angle unit: '%s'" $angle]
+ set angle [lindex ${X::project_edit_defaults} {4 1}]
+ }
+ set ::Calculator::calc_base$calc_idx $base
+ set ::Calculator::calc_angle$calc_idx $angle
+
+ set last_base $base
+ set last_angle $angle
+
+ # Enable/Disable buttons on numeric keypad
+ switch -- $base {
+ {Hex} {
+ enable_buttons {0 1 2 3 4 5 6 7 8 9 A B C D E F}
+ disable_buttons {U RE}}
+ {Dec} {
+ enable_buttons {0 1 2 3 4 5 6 7 8 9}
+ disable_buttons {A B C D E F U RE}}
+ {Oct} {
+ enable_buttons {0 1 2 3 4 5 6 7}
+ disable_buttons {8 9 A B C D E F U RE}}
+ {Bin} {
+ enable_buttons {0 1}
+ disable_buttons {2 3 4 5 6 7 8 9 A B C D E F U RE}}
+ }
+
+ # Fill displays
+ set calc_display [lindex $calculatorList 2]
+ rewrite_display
+ calc_opr [lindex $calculatorList 3] 0
+ set calc_buffer [lindex $calculatorList 4]
+ rewrite_buffer
+ set ::Calculator::calc_mem0_$calc_idx [lindex $calculatorList 5]
+ set ::Calculator::calc_mem1_$calc_idx [lindex $calculatorList 6]
+ set ::Calculator::calc_mem2_$calc_idx [lindex $calculatorList 7]
+
+ # Set frequenci and mode in timers calculator
+ set freq [lindex $calculatorList 8]
+ set mode [lindex $calculatorList 10]
+ if {$freq == {} || [regexp {^\d\+$} $freq] || $freq < 0 || $freq > 99999} {
+ set freq 12000
+ }
+ if {$mode != 0 && $mode != 1 && $mode != 2} {
+ set mode 0
+ }
+ $timerscalc_freq_entry insert 0 $freq
+ $timerscalc_time_entry insert 0 [lindex $calculatorList 9]
+ $timerscalc_mode_spinbox delete 0 end
+ $timerscalc_mode_spinbox insert 0 $mode
+
+ # Unset teportary variables
+ unset parent
+ unset calculatorList
+ }
+
+ ## Get calculator list for later initialization
+ # @return List - resulting list of values
+ public method get_calculator_list {} {
+ if {!$gui_initialized} {CreateCalculatorGUI}
+ return [list $base $angle \
+ [$calc_display_widget get] \
+ $calc_oper \
+ [$calc_buffer_widget get] \
+ [subst "\$::Calculator::calc_mem0_$calc_idx"] \
+ [subst "\$::Calculator::calc_mem1_$calc_idx"] \
+ [subst "\$::Calculator::calc_mem2_$calc_idx"] \
+ [$timerscalc_freq_entry get] \
+ [$timerscalc_time_entry get] \
+ [$timerscalc_mode_spinbox get]]
+ }
+
+ ## Validate and evaluate content of Frequency entry (timers calculator)
+ # @parm String content - String to validate (and evaluate)
+ # @return Bool - result of validation
+ public method calc_timerscalc_freq_validate {content} {
+ # If validation disabled -> abort
+ if {$timerscalc_validation_dis} {
+ return 1
+ }
+ # If content is decimal number (max 5. digits) -> evaluate and return True
+ if {[regexp {^\d*$} $content] && ([string length $content] < 6)} {
+ calc_timerscalc_evaluate \
+ $content \
+ [$timerscalc_time_entry get] \
+ [$timerscalc_mode_spinbox get] \
+
+ return 1
+ }
+ # Otherwise -> return False
+ Sbar [mc "Calculator - timers preset: you are trying to insert an invalid value"]
+ return 0
+ }
+
+ ## Validate and evaluate content of Mode entry (timers calculator)
+ # @parm String content - String to validate (and evaluate)
+ # @return Bool - result of validation
+ public method calc_timerscalc_mode_validate {content} {
+ # If validation disabled -> abort
+ if {$timerscalc_validation_dis} {
+ return 1
+ }
+ # If the given value is one of {0 1 2} the evaluate and return True
+ if {[regexp {^\d?$} $content]} {
+ if {$content > 2} {
+ return 0
+ }
+ calc_timerscalc_evaluate \
+ [$timerscalc_freq_entry get] \
+ [$timerscalc_time_entry get] \
+ $content
+ return 1
+ }
+ # Otherwise -> return False
+ Sbar [mc "Calculator - timers preset: you are trying to insert an invalid value"]
+ return 0
+ }
+
+ ## Validate and evaluate content of Time entry (timers calculator)
+ # @parm String content - String to validate (and evaluate)
+ # @return Bool - result of validation
+ public method calc_timerscalc_time_validate {content} {
+ # If validation disabled -> abort
+ if {$timerscalc_validation_dis} {
+ return 1
+ }
+ # If content is decimal number (max 9. digits) -> evaluate and return True
+ if {[regexp {^\d*$} $content] && ([string length $content] < 10)} {
+ calc_timerscalc_evaluate \
+ [$timerscalc_freq_entry get] \
+ $content \
+ [$timerscalc_mode_spinbox get]
+ return 1
+ }
+ # Otherwise -> return False
+ Sbar [mc "Calculator - timers preset: you are trying to insert an invalid value"]
+ return 0
+ }
+
+ ## Highlight result of timer preset calculator
+ # @parm Bool valid - highlight for valid results
+ # @return void
+ private method calc_timerscalc_highlight {valid} {
+
+ # List of widgets to highlight
+ set widgets "
+ $timerscalc_THxDec_label
+ $timerscalc_THxHex_label
+ $timerscalc_THxOct_label
+ $timerscalc_TLxDec_label
+ $timerscalc_TLxHex_label
+ $timerscalc_TLxOct_label
+ $timerscalc_RepeatDec_label
+ $timerscalc_RepeatHex_label
+ $timerscalc_RepeatOct_label
+ $timerscalc_CorrectionDec_label
+ $timerscalc_CorrectionHex_label
+ $timerscalc_CorrectionOct_label
+ "
+
+ # Perform highlighting
+ if {$valid} {
+ foreach widget $widgets {
+ $widget configure -state normal
+ }
+ } {
+ foreach widget $widgets {
+ $widget configure -state disabled
+ }
+ }
+ }
+
+ ## Evaluate tmers preset (timers preset calculator)
+ # @parm Int freq - Frequency
+ # @parm Int time - Time in miliseconds
+ # @parm Int mode - Mode {0 1 2}
+ # @return Bool - Resulting status
+ private method calc_timerscalc_evaluate {freq time mode} {
+
+ # Set default results
+ set TLx 0
+ set THx 0
+ set repeat 0
+ set correction 0
+
+ # Check for validity of given values
+ if {$freq == {} || $freq == 0 || $time == {} || $mode == {} } {
+ set mode {invalid}
+ } {
+ # Compute time in machine cycles
+ set time [expr {int($time * (12000.0 / $freq))}]
+ }
+
+ # Perform computation for the given mode
+ switch -- $mode {
+ 0 {
+ # Determinate apparent number of repeats
+ set repeat [expr {($time >> 13) + 1}]
+ # Compute tempotary results
+ if {[expr {!($time & 0x1FFF)}]} {
+ incr repeat -1
+ set stepsPerIter 0x1FFF
+ } {
+ set stepsPerIter [expr {$time / $repeat}]
+ set tmp [expr {0x2000 - $stepsPerIter}]
+ set TLx [expr {$tmp & 0x1F}]
+ set THx [expr {$tmp >> 5}]
+ set correction [expr {$time - ((0x1FFF - $tmp) * $repeat)}]
+ }
+ }
+ 1 {
+ # Determinate apparent number of repeats
+ set repeat [expr {($time >> 16) + 1}]
+ # Compute tempotary results
+ if {[expr {!($time & 0xFFFF)}]} {
+ incr repeat -1
+ set stepsPerIter 0xFFFF
+ } {
+ set stepsPerIter [expr {$time / $repeat}]
+ set tmp [expr {0x10000 - $stepsPerIter}]
+ set TLx [expr {$tmp & 0xFF}]
+ set THx [expr {$tmp >> 8}]
+ set correction [expr {$time - ((0x10000 - $tmp) * $repeat)}]
+ }
+ }
+ 2 {
+ # Determinate apparent number of repeats
+ set repeat [expr {($time >> 8) + 1}]
+ # Compute tempotary results
+ if {[expr {!($time & 0xFF)}]} {
+ incr repeat -1
+ set stepsPerIter 0xFF
+ } {
+ set stepsPerIter [expr {$time / $repeat}]
+ set TLx [expr {0x100 - $stepsPerIter}]
+ set THx $TLx
+ set correction [expr {$time - ((0xFF - $THx) * $repeat)}]
+ }
+ }
+ {invalid} { ;# Invalid input data
+ calc_timerscalc_highlight 0
+ }
+ default { ;# Something went wrong
+ error "Calculator error: Invalid timer mode $mode"
+ return 0
+ }
+ }
+
+ # If pre-computation was performed succesfully -- finish the results
+ if {$mode != {invalid}} {
+ # Highlight results as valid
+ calc_timerscalc_highlight 1
+
+ # Perform correction
+ if {$correction >= $stepsPerIter} {
+ incr repeat [expr {$correction / $stepsPerIter}]
+ set correction [expr {$correction % $stepsPerIter}]
+ }
+ }
+
+ # Check for allowed length of results (string representation)
+ if {
+ [string length [format "%o" $repeat]] > 6
+ ||
+ [string length [format "%o" $correction]] > 6
+ } {
+ set TLx 0
+ set THx 0
+ set repeat 0
+ set correction 0
+ calc_timerscalc_highlight 0
+ Sbar [mc "Calculator: Unable to evaluate, result value is too high"]
+ }
+
+ ## Write results
+ # THx values
+ $timerscalc_THxDec_label configure -text $THx
+ $timerscalc_THxHex_label configure -text [format "%X" $THx]
+ $timerscalc_THxOct_label configure -text [format "%o" $THx]
+ # TLx values
+ $timerscalc_TLxDec_label configure -text $TLx
+ $timerscalc_TLxHex_label configure -text [format "%X" $TLx]
+ $timerscalc_TLxOct_label configure -text [format "%o" $TLx]
+ # Repeat values
+ $timerscalc_RepeatDec_label configure -text $repeat
+ $timerscalc_RepeatHex_label configure -text [format "%X" $repeat]
+ $timerscalc_RepeatOct_label configure -text [format "%o" $repeat]
+ # Correction values
+ $timerscalc_CorrectionDec_label configure -text $correction
+ $timerscalc_CorrectionHex_label configure -text [format "%X" $correction]
+ $timerscalc_CorrectionOct_label configure -text [format "%o" $correction]
+
+ return 1
+ }
+
+ ## Create widgets of timers preset calculator
+ # @parm widget parent - parent contaner (some frame)
+ # @return void
+ private method makeTimersCalc {parent} {
+ # TOP HALF
+ set top_frame [frame $parent.calc_timerscalc_top_frame]
+ # frequency
+ grid [label $top_frame.calc_timerscalc_freq_label \
+ -text [mc "Frequency \[kHz\]"] \
+ ] -row 0 -column 0 -sticky w
+ set timerscalc_freq_entry [ttk::entry \
+ $top_frame.calc_timerscalc_freq_entry \
+ -width 5 \
+ -validate all \
+ -validatecommand "$this calc_timerscalc_freq_validate %P" \
+ ]
+ grid $timerscalc_freq_entry -row 0 -column 1 -sticky we
+ # mode
+ grid [label $top_frame.calc_timerscalc_mode_label \
+ -text [mc "Mode"] \
+ ] -row 0 -column 2 -sticky w
+ set timerscalc_mode_spinbox [spinbox \
+ $top_frame.calc_timerscalc_mode_spinbox \
+ -bg {#FFFFFF} -highlightthickness 0 \
+ -from 0 -to 2 -width 1 -validate key \
+ -vcmd "$this calc_timerscalc_mode_validate %P" \
+ ]
+ grid $timerscalc_mode_spinbox -row 0 -column 3 -sticky we
+ # time
+ grid [label $top_frame.calc_timerscalc_time_label \
+ -text [mc "Time \[us\]"] \
+ ] -row 1 -column 0 -sticky w
+ set timerscalc_time_entry [ttk::entry \
+ $top_frame.calc_timerscalc_time_entry \
+ -width 8 \
+ -validate all \
+ -validatecommand "$this calc_timerscalc_time_validate %P" \
+ ]
+ grid $timerscalc_time_entry -row 1 -column 1 -sticky we -columnspan 3
+
+ # BOTTOM HALF
+ set bottom_frame [frame $parent.calc_timerscalc_bottom_frame]
+
+ # "dec" "hex" "oct"
+ grid [label $bottom_frame.calc_timerscalc_dec_label \
+ -text [mc "DEC"] -font $::smallfont -anchor e \
+ -highlightthickness 0 \
+ ] -row 0 -column 1 -ipadx 12
+ grid [label $bottom_frame.calc_timerscalc_hex_label \
+ -text [mc "HEX"] -font $::smallfont -anchor e \
+ -highlightthickness 0 \
+ ] -row 0 -column 2 -ipadx 12
+ grid [label $bottom_frame.calc_timerscalc_oct_label \
+ -text [mc "OCT"] -font $::smallfont -anchor e \
+ -highlightthickness 0 \
+ ] -row 0 -column 3 -ipadx 12
+
+ # "THx" "TLx" "Repeat" "Correction"
+ grid [label $bottom_frame.calc_timerscalc_thx_label \
+ -text "THx" \
+ ] -row 1 -column 0 -sticky w
+ grid [label $bottom_frame.calc_timerscalc_tlx_label \
+ -text "TLx" \
+ ] -row 2 -column 0 -sticky w
+ grid [label $bottom_frame.calc_timerscalc_repeat_label \
+ -text [mc "Repeats"] \
+ ] -row 3 -column 0 -sticky w
+ grid [label $bottom_frame.calc_timerscalc_correction_label \
+ -text [mc "Correction"] \
+ ] -row 4 -column 0 -sticky w
+
+ # THx values
+ set timerscalc_THxDec_label [label \
+ $bottom_frame.calc_timerscalc_THxDec_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_THxHex_label [label \
+ $bottom_frame.calc_timerscalc_THxHex_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_THxOct_label [label \
+ $bottom_frame.calc_timerscalc_THxOct_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+
+ # TLx values
+ set timerscalc_TLxDec_label [label \
+ $bottom_frame.calc_timerscalc_TLxDec_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_TLxHex_label [label \
+ $bottom_frame.calc_timerscalc_TLxHex_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_TLxOct_label [label \
+ $bottom_frame.calc_timerscalc_TLxOct_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+
+ # Repeat values
+ set timerscalc_RepeatDec_label [label \
+ $bottom_frame.calc_timerscalc_RepeatDec_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_RepeatHex_label [label \
+ $bottom_frame.calc_timerscalc_RepeatHex_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_RepeatOct_label [label \
+ $bottom_frame.calc_timerscalc_RepeatOct_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+
+ # Correction values
+ set timerscalc_CorrectionDec_label [label \
+ $bottom_frame.calc_timerscalc_CorrectionDec_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_CorrectionHex_label [label \
+ $bottom_frame.calc_timerscalc_CorrectionHex_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+ set timerscalc_CorrectionOct_label [label \
+ $bottom_frame.calc_timerscalc_CorrectionOct_label \
+ -text "0" -disabledforeground {#AAAAAA} -fg {#000033} \
+ ]
+
+ # Show widgets
+ grid $timerscalc_THxDec_label -row 1 -column 1 -sticky e
+ grid $timerscalc_THxHex_label -row 1 -column 2 -sticky e
+ grid $timerscalc_THxOct_label -row 1 -column 3 -sticky e
+ grid $timerscalc_TLxDec_label -row 2 -column 1 -sticky e
+ grid $timerscalc_TLxHex_label -row 2 -column 2 -sticky e
+ grid $timerscalc_TLxOct_label -row 2 -column 3 -sticky e
+ grid $timerscalc_RepeatDec_label -row 3 -column 1 -sticky e
+ grid $timerscalc_RepeatHex_label -row 3 -column 2 -sticky e
+ grid $timerscalc_RepeatOct_label -row 3 -column 3 -sticky e
+ grid $timerscalc_CorrectionDec_label -row 4 -column 1 -sticky e
+ grid $timerscalc_CorrectionHex_label -row 4 -column 2 -sticky e
+ grid $timerscalc_CorrectionOct_label -row 4 -column 3 -sticky e
+
+ # Make widgets in table as small as possible
+ foreach widget "
+ $bottom_frame.calc_timerscalc_dec_label
+ $bottom_frame.calc_timerscalc_hex_label
+ $bottom_frame.calc_timerscalc_oct_label
+ $bottom_frame.calc_timerscalc_thx_label
+ $bottom_frame.calc_timerscalc_tlx_label
+ $bottom_frame.calc_timerscalc_repeat_label
+ $bottom_frame.calc_timerscalc_correction_label
+ $timerscalc_THxDec_label
+ $timerscalc_THxHex_label
+ $timerscalc_THxOct_label
+ $timerscalc_TLxDec_label
+ $timerscalc_TLxHex_label
+ $timerscalc_TLxOct_label
+ $timerscalc_RepeatDec_label
+ $timerscalc_RepeatHex_label
+ $timerscalc_RepeatOct_label
+ $timerscalc_CorrectionDec_label
+ $timerscalc_CorrectionHex_label
+ $timerscalc_CorrectionOct_label
+ " {
+ $widget configure -bd 0 -relief raised -pady 0 -highlightthickness 0
+ }
+
+ # Pack frames
+ pack $top_frame -padx 5 -pady 2
+ pack $bottom_frame -padx 5 -pady 2
+
+ # Highlight calculator results as invalid
+ calc_timerscalc_highlight 0
+ set timerscalc_validation_dis 0
+ }
+
+ ## Create calculator keypad
+ # @parm widget parent - target contaner (some frame)
+ # @parm List definition - keypad definition (see class header)
+ # @return void
+ private method makeKeypad {parent definition} {
+ # Local variables
+ set row 0 ;# Current row in the grid
+
+ # Oterate over row definitions in the given keypad definition
+ foreach line $definition {
+ # Local variables
+ set col 0 ;# current column in the grid
+
+ # Iterate over button definitions in the row
+ foreach item $line {
+ if {$item == "separator"} {continue}
+
+ # Inicalize array of button features
+ for {set i 0} {$i < 13} {incr i} {
+ set parm($i) [lindex $item $i]
+ }
+
+ if {[lsearch -ascii -exact {A B C D E} $parm(0)] != -1} {
+ incr col
+ }
+
+ # Initialize default values for some items
+ foreach i {3 4 7} {
+ if {$parm($i) == {}} {set parm($i) 1}
+ }
+ if {$parm(6) == {}} {set parm(6) 2}
+ if {$parm(8) == {}} {set parm(8) 0}
+ if {$parm(9) == {}} {set parm(9) {#FFFFFF}}
+ if {$parm(10) == {}} {set parm(10) {#FFFFFF}}
+
+ if {[string index $parm(9) 0] == {#}} {
+ set parm(9) {Calculator}
+ }
+
+ # Set button ID
+ set path "$parent.calc_$parm(1)"
+ # Create button
+ ttk::button $path \
+ -text $parm(0) \
+ -command "$this $parm(2)" \
+ -width $parm(6) \
+ -style $parm(9).TButton
+# -activebackground $parm(10) \
+# -height $parm(7) \
+ DynamicHelp::add $path -text [mc $parm(5)]
+ # Confugure button
+# if {$parm(11) == 1} {$path configure -font $large_font -pady 2}
+ if {$parm(12) != {}} {
+ setStatusTip -widget $path -text [mc $parm(12)]
+ }
+
+ if {$parm(3) > 1} {
+ set sticky {we}
+ } elseif {$parm(4) > 1} {
+ set sticky {ns}
+ } else {
+ set sticky {}
+ }
+
+ # Show button
+ grid $path \
+ -columnspan $parm(3) \
+ -rowspan $parm(4) \
+ -sticky $sticky \
+ -padx 2 \
+ -pady 2 \
+ -column $col \
+ -row $row
+
+ # Incremet number of current column
+ incr col $parm(3)
+ }
+ # Incremet number of current row
+ incr row
+ }
+
+ grid columnconfigure $parent 4 -minsize 10
+ }
+
+ ## Adjust scrollbar for scrollable area
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method calc_gui_scroll_set {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $horizontal_scrollbar]} {
+ pack forget $horizontal_scrollbar
+ update
+ }
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $horizontal_scrollbar]} {
+ pack $horizontal_scrollbar -fill x -side top -before $scrollable_frame
+ }
+ $horizontal_scrollbar set $frac0 $frac1
+ update
+ }
+ }
+}
diff --git a/lib/bottompanel/cvarsview.tcl b/lib/bottompanel/cvarsview.tcl
new file mode 100755
index 0000000..fbc5dd2
--- /dev/null
+++ b/lib/bottompanel/cvarsview.tcl
@@ -0,0 +1,1303 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides GUI interface designed for the bottom panel to show and
+# manipulate contents of variables in a running C program on simulated 8051
+# --------------------------------------------------------------------------
+
+class CVarsView {
+ ## COMMON
+ # Normal font fot the text widget
+ common text_wdg_font_n [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight normal \
+ -slant roman \
+ ]
+ # Bold font for the text widget
+ common text_wdg_font_b [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ -slant roman \
+ ]
+ # Italic font for the text widget
+ common text_wdg_font_i [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight normal \
+ -slant italic \
+ ]
+ # Background color for selected lines
+ common color_selected_line {#CCCCFF}
+
+ private variable main_frame ;# Widget: Main frame
+
+ # Variables related to object initialization
+ private variable parent ;# Widget: parent widget
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+
+ private variable panedwindow ;# Widget: Paned window for local and global variables
+ # Int: Last paned window sash position
+ private variable panel_sash_position [lindex $::CONFIG(C_VARS_VIEW_CONF) 0]
+
+ private variable local_variables_nlist {} ;# List of Strings: Names of all local variables
+ private variable local_variables {} ;# List of Lists: Detail definition of all local variables
+ private variable local_addresses {} ;# List of Lists: Addresses of all local variables
+ private variable local_addresses_list {} ;# List of Lists: {scope name level block}
+
+ private variable global_variables_nlist {} ;# List of Strings: Names of all global variables
+ private variable global_variables {} ;# List of Lists: Detail definition of all global variables
+ private variable global_addresses {} ;# List of Lists: Addresses of all global variables
+ private variable global_addresses_list {} ;# List of Lists: {scope name level block}
+ private variable global_displayed {} ;# List of Integers: Indexes of displayed variables
+
+ private variable help_window_frame {} ;# Widget: Main frame for the help window
+
+ private variable text_widget_local ;# Widget: Text widget for local variables
+ private variable text_widget_global ;# Widget: Text widget for global variables
+ private variable current_level {} ;# Int: Current code level (determinated by simulator)
+ private variable current_block {} ;# Int: Current code level (determinated by simulator)
+
+ private variable validation_ena 1 ;# Bool: Entries validation and synchronization enabled
+
+ private variable search_entry_Local ;# Widget: Search entry for local variables
+ private variable search_clear_Local ;# Widget: Clear button for search entry box for local variables
+ private variable search_entry_Global ;# Widget: Search entry for global variables
+ private variable search_clear_Global ;# Widget: Clear button for search entry box for global variables
+ private variable search_val_in_progress 0 ;# Bool: Search is in progress
+
+ private variable selected_line_global 0 ;# Int: Number of currently selected line in global variables (0 == nothig selected)
+ private variable selected_line_local 0 ;# Int: Number of currently selected line in local variables (0 == nothig selected)
+
+ constructor {} {
+ }
+
+ destructor {
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - GUI parent widget
+ # @return void
+ public method PrepareCVarsView {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method CVarsViewTabRaised {} {
+ }
+
+ ## Create GUI of this tab
+ # @return void
+ public method CreateCVarsViewGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ ## Create GUI of main frame
+ set main_frame [frame $parent.main_frame]
+ set panedwindow [panedwindow $main_frame.pw \
+ -sashwidth 5 -showhandle 0 \
+ -opaqueresize 1 -orient horizontal \
+ ]
+
+ # Create part containing local variables
+ set pane [create_list_of_variables Local]
+# $panedwindow add $pane
+# $panedwindow paneconfigure $pane -minsize 200
+
+ # Create part containing global variables
+ set pane [create_list_of_variables Global]
+ $panedwindow add $pane
+ $panedwindow paneconfigure $pane -minsize 200
+
+ # Pack main GUI parts of the panel
+ pack $panedwindow -fill both -expand 1
+ pack $main_frame -fill both -expand 1
+
+ # Restore sash position
+ cvarsview_redraw_pane
+
+ # Load CDB file if simulator is engaged and C language is used
+ if {[$this cget -programming_language] && [$this is_frozen]} {
+ set filename [$this simulator_get_cdb_filename]
+ if {[catch {
+ set file [open $filename r]
+ }]} {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to read file\n'%s'"] $filename
+ } {
+ cvarsview_load_cdb $file
+ close $file
+ }
+ }
+ }
+
+ ## Restore paned window sash position
+ # @return void
+ public method cvarsview_redraw_pane {} {
+ if {!$gui_initialized} {return}
+# update idle
+# $panedwindow sash place 0 $panel_sash_position 0
+ }
+
+ ## Get panel configuration list
+ # @return List - Panel config
+ public method cvarsview_get_config {} {
+ if {$gui_initialized} {
+# set panel_sash_position [lindex [$panedwindow sash coord 0] 0]
+ }
+ return [list $panel_sash_position]
+ }
+
+ ## Search for certain variable by its name
+ # @parm String type - Basic variable type specification ("Global" or "Local")
+ # @parm String string - Variable name
+ # @return Bool - allways 1
+ public method cvarsview_search {type string} {
+ # Lock this function
+ if {$search_val_in_progress} {return 0}
+ set search_val_in_progress 1
+
+ # Empty string given
+ if {![string length $string]} {
+ [subst "\$search_entry_$type"] configure -style TEntry
+ [subst "\$search_clear_$type"] configure -state disabled
+ set search_val_in_progress 0
+ return 1
+ }
+ [subst "\$search_clear_$type"] configure -state normal
+
+ ## Perform search
+ set idx 0
+ set found 0
+ # Global variable
+ if {$type == {Global}} {
+ foreach name $global_variables_nlist {
+ if {![string first $string $name] && [lsearch $global_displayed $idx] != -1} {
+ set found 1
+ break
+ }
+ incr idx
+ }
+ # Local variable
+ } {
+ }
+
+
+ # Variable found
+ if {$found} {
+ cvarsview_select_line $type [expr {[lsearch $global_displayed $idx] + 1}] 1
+ [subst "\$search_entry_$type"] configure -style StringFound.TEntry
+ # Variable not found
+ } {
+ [subst "\$search_entry_$type"] configure -style StringNotFound.TEntry
+ }
+
+
+ # Unlock this function
+ set search_val_in_progress 0
+ return 1
+ }
+
+ ## Select line in the text widget
+ # @parm String type - Basic variable type specification ("Global" or "Local")
+ # @parm Int line_number - Number of line to select (1 .. infinity)
+ # @parm Bool nofocus - Do not focus the entrybox
+ # @return void
+ public method cvarsview_select_line {type line_number nofocus} {
+ cvarsview_unselect_line $type
+
+ # Line with a global variable
+ if {$type == {Global}} {
+ set max [llength $global_displayed]
+ if {$line_number > $max} {
+ return
+ }
+
+ set selected_line_global $line_number
+ $text_widget_global tag add tag_current_line $line_number.0 $line_number.0+1l
+ $text_widget_global see $line_number.0
+ incr line_number -1
+ set eid [lindex $global_displayed $line_number]
+ $text_widget_global.e_$eid configure \
+ -bg $color_selected_line \
+ -disabledbackground $color_selected_line
+ if {!$nofocus} {
+ focus $text_widget_global.e_$eid
+ }
+
+ # Line with a local variable
+ } {
+ }
+ }
+
+ ## Unselect line in the text widget
+ # @parm String type - Basic variable type specification ("Global" or "Local")
+ # @return void
+ public method cvarsview_unselect_line {type} {
+ # View with a global variable
+ if {$type == {Global}} {
+ if {$selected_line_global != 0} {
+ incr selected_line_global -1
+ $text_widget_global.e_[lindex $global_displayed $selected_line_global] configure \
+ -bg white -disabledbackground white
+ }
+ $text_widget_global tag remove tag_current_line 0.0 end
+ set selected_line_global 0
+ # View with a local variable
+ } {
+ }
+ }
+
+ ## Select line above the current one
+ # @parm Bool isglobal - Global scope
+ # @parm Int lines - Distance
+ # @return void
+ public method cvarsview_selection_up {isglobal lines} {
+ if {$isglobal} {
+ if {$selected_line_global == 0} {
+ return
+ }
+ set max [llength $global_displayed]
+ set target_line $selected_line_global
+
+ incr target_line -$lines
+ while {$target_line < 1} {
+ incr target_line $max
+ }
+
+ cvarsview_select_line Global $target_line 0
+ }
+ }
+
+ ## Select line below the current one
+ # @parm Bool isglobal - Global scope
+ # @parm Int lines - Distance
+ # @return void
+ public method cvarsview_selection_down {isglobal lines} {
+ if {$isglobal} {
+ if {$selected_line_global == 0} {
+ return
+ }
+ set max [llength $global_displayed]
+ set target_line $selected_line_global
+
+ incr target_line $lines
+ while {$target_line > $max} {
+ incr target_line -$max
+ }
+
+ cvarsview_select_line Global $target_line 0
+ }
+ }
+
+ ## Open the helpwindow for certain variable
+ # @parm Int id - Variable ID
+ # @parm Bool isglobal - Related to global scope variable
+ # @return void
+ public method cvarsview_create_help_window {id isglobal} {
+# set help_window_frame [frame .cvarsview_help_window -bg {#BBBBFF}]
+#
+# if {$isglobal} {
+# set variable_def [lindex $global_variables $id]
+# pack [label $help_window_frame.header \
+# -text [lindex $variable_def 1] \
+# -bg {#BBBBFF} \
+# ] -anchor w
+#
+# set var_det_frame [frame $help_window_frame.details_frame -bg {#FFFFFF}]
+# pack $var_det_frame -fill both -padx 2 -pady 2
+#
+# grid [label $var_det_frame.value_lbl \
+# -text "Value:" \
+# ] -row 0 -column 0 -columnspan 3 -sticky w
+#
+# }
+#
+# # lappend global_variables [list \
+# # $scope $name \
+# # [lindex $type_record 0] [lindex $type_record end] \
+# # [lrange $type_record 1 end-1] $address_space \
+# # $onstack $stack \
+# # $registers 0 \
+# # 0 \
+# # ]
+ }
+
+ ## Move with the help window
+ # @parm Bool isglobal - Related to global scope variable
+ # @parm Int X - Absolute X position
+ # @parm Int Y - Absolute Y position
+ # @return void
+ public method cvarsview_help_window_move {isglobal X Y} {
+ if {[winfo exists $help_window_frame]} {
+ incr X 10
+ incr Y 10
+ place $help_window_frame -x $X -y $Y -anchor sw
+ raise $help_window_frame
+ }
+ }
+
+ ## Hide the help window
+ # @parm Bool isglobal - Related to global scope variable
+ # @return void
+ public method cvarsview_help_window_hide {isglobal} {
+ if {[winfo exists $help_window_frame]} {
+ destroy $help_window_frame
+ }
+ }
+
+ ## Create panel with list of global or local variables
+ # @parm String type - Basic variable type specification ("Global" or "Local")
+ # @return void
+ private method create_list_of_variables {type} {
+ set local_frame [frame $main_frame.var_${type}_frame]
+
+ # Create the top frame
+ set top_frame [frame $local_frame.top_frame]
+ pack [label $top_frame.header \
+ -text "$type static scalar variables" \
+ -anchor w -justify left \
+ ] -side left
+
+ # Create search frame
+ set search_frame [frame $top_frame.search_frame]
+ pack [label $search_frame.search_lbl \
+ -text [mc "Search:"] \
+ ] -side left
+ set search_entry_$type [ttk::entry $search_frame.search_ent \
+ -validate all \
+ -validatecommand "$this cvarsview_search $type %P" \
+ ]
+ pack $search_frame.search_ent -side left
+ set search_clear_$type [ttk::button $search_frame.search_clr_but\
+ -image ::ICONS::16::clear_left \
+ -style Flat.TButton \
+ -command "$search_frame.search_ent delete 0 end" \
+ -state disabled \
+ ]
+ pack $search_frame.search_clr_but -side left
+
+ # Pack top frame
+ pack $search_frame -side right
+ pack $top_frame -fill x -anchor nw
+
+ # Create the text widget
+ set text_frame [frame $local_frame.text_frame]
+ set text_frame_main [frame $text_frame.main_frame -bd 1 -relief sunken]
+ if {$type == {Local}} {
+ set text [mc "Value Level Data type Variable name"]
+ } {
+ set text [mc "Value Data type Variable name"]
+ }
+ pack [label $text_frame_main.header \
+ -font $text_wdg_font_b -justify left \
+ -text $text \
+ -bd 0 -relief flat -bg white -anchor w \
+ ] -fill x -anchor w -padx 0 -pady 0
+ pack [ttk::separator $text_frame_main.sep \
+ -orient horizontal \
+ ] -fill x
+ set text_widget [text $text_frame_main.text \
+ -bg white -exportselection 0 -bd 0 \
+ -width 0 -height 0 -relief flat \
+ -font $text_wdg_font_n \
+ -yscrollcommand "$text_frame.scrollbar set" \
+ -state disabled \
+ -cursor left_ptr \
+ ]
+ bind $text_widget <<Selection>> "false_selection $text_widget; break"
+ bind $text_widget <Button-1> "$this cvarsview_select_line $type \[expr {int(\[%W index @%x,%y\])}\] 0"
+ bind $text_widget <Menu> {break}
+ bind $text_widget <ButtonRelease-3> {break}
+ pack $text_widget -fill both -expand 1
+
+ pack $text_frame_main -fill both -expand 1 -side left
+ pack [ttk::scrollbar $text_frame.scrollbar \
+ -command "$text_widget yview" \
+ -orient vertical \
+ ] -fill y -side right -after $text_frame_main
+ pack $text_frame -fill both -expand 1
+
+ if {$type == {Local}} {
+ set text_widget_local $text_widget
+ } {
+ set text_widget_global $text_widget
+ }
+
+ # Create text tags
+ $text_widget tag configure tag_current_line -background $color_selected_line
+ $text_widget tag configure tag_variable -font $text_wdg_font_b
+ $text_widget tag configure tag_datatype -font $text_wdg_font_i
+
+ return $local_frame
+ }
+
+ ## Load CDB file (debugging file generated by SDCC)
+ # @parm File cdb_file - Opened CDB file
+ # @return Bool - True in success
+ public method cvarsview_load_cdb {cdb_file} {
+ if {!$gui_initialized} {CreateCVarsViewGUI}
+ set result 1
+
+ set local_variables_nlist {}
+ set local_variables_list {}
+ set local_variables {}
+ set local_addresses {}
+ set local_addresses_list {}
+ set global_variables_nlist {}
+ set global_variables {}
+ set global_addresses {}
+ set global_addresses_list {}
+
+ # Parse linker and symbol records
+ while {![eof $cdb_file]} {
+ set line [gets $cdb_file]
+ set subtype [string index $line 2]
+ switch -- [string index $line 0] {
+ {S} { ;# Symbol record
+ if {$subtype != {G} && $subtype != {L} && $subtype != {F}} {
+ continue
+ }
+ if {![symbol_record $subtype [string range $line 3 end]]} {
+ set result 0
+ }
+ }
+ {L} { ;# Linker record
+ if {$subtype != {G} && $subtype != {L} && $subtype != {F}} {
+ continue
+ }
+ if {![link_address_of_symbol $subtype [string range $line 3 end]]} {
+ set result 0
+ }
+ }
+ default {
+ continue
+ }
+ }
+ }
+
+ # Initialize list of displayed global variables
+ set global_displayed {}
+
+ # Clear search entries
+ $search_entry_Global delete 0 end
+
+ # Adjust lists of addresses
+ evaluate_lists_of_addresses
+
+ # Clear the viewers
+ cvarsview_clear_view local
+ cvarsview_clear_view global
+
+ # Load gained informations into the viewers
+ cvarsview_load_global_variables
+
+ return $result
+ }
+
+ ## Adjust lists of addresses
+ # @see cvarsview_load_cdb
+ # Translate each start address to list of address of all registers occupied by the variable
+ # @return void
+ private method evaluate_lists_of_addresses {} {
+
+ # Process global vaiables
+ set global_addresses_new {}
+ set global_variables_new {}
+ set global_variables_nlist_new {}
+ foreach start_address $global_addresses name $global_addresses_list {
+ set name [lindex $name 1]
+ set idx [lsearch $global_variables_nlist $name]
+ set addresses {}
+ set lenght 0
+
+ if {$idx == -1} {
+ puts stderr "CVarsView::evaluate_lists_of_addresses :: Unknown error 0"
+ continue
+ }
+
+ set glob_var_def [lindex $global_variables $idx]
+ set length [lindex $glob_var_def 2]
+ for {set i 0} {$i < $length} {incr i} {
+ lappend addresses $start_address
+ incr start_address
+ }
+ lappend global_addresses_new $addresses
+ lappend global_variables_new $glob_var_def
+ lappend global_variables_nlist_new $name
+ }
+ set global_addresses $global_addresses_new
+ set global_variables $global_variables_new
+ set global_variables_nlist $global_variables_nlist_new
+
+ # Process local vaiables
+ }
+
+ ## Handle symbol record
+ # @see cvarsview_load_cdb
+ # @parm Char subtype - Variable scope ('G' == Global; 'L' == Local; 'F' == File)
+ # @parm String record - Record data
+ # @return Bool - True on success
+ private method symbol_record {subtype record} {
+ set scope {}
+ set name {}
+ set level {}
+ set block {}
+ set type_record {}
+ set address_space {}
+ set onstack {}
+ set stack {}
+ set registers {}
+
+ if {$subtype == {F}} {
+ set subtype {G}
+ }
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set scope [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set name [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set level [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set bracket_idx [string first {(} $record]
+ if {$bracket_idx == -1} {return 0}
+ set block [string range $record 0 [expr {$bracket_idx - 1}]]
+
+ set record [string replace $record 0 $bracket_idx]
+ set bracket_idx [string first {)} $record]
+ if {$bracket_idx == -1} {return 0}
+ set type_record [string range $record 1 [expr {$bracket_idx - 1}]]
+ set type_record [split $type_record {\{\},:}]
+
+ set record [string replace $record 0 [expr {$bracket_idx + 1}]]
+ set comma_idx [string first {,} $record]
+ if {$comma_idx == -1} {return 0}
+ set address_space [string range $record 0 [expr {$comma_idx - 1}]]
+
+ set record [string replace $record 0 $comma_idx]
+ set comma_idx [string first {,} $record]
+ if {$comma_idx == -1} {return 0}
+ set onstack [string range $record 0 [expr {$comma_idx - 1}]]
+
+ set record [string replace $record 0 $comma_idx]
+ set comma_idx [string first {,} $record]
+ if {$comma_idx == -1} {
+ set comma_idx [string length $record]
+ }
+ set stack [string range $record 0 [expr {$comma_idx - 1}]]
+
+ if {$record != {}} {
+ set record [string replace $record 0 $comma_idx]
+ set registers [split [string range $record 1 end-1] {,}]
+ }
+
+ if {$subtype == {G}} {
+ lappend global_variables_nlist $name
+ lappend global_variables [list \
+ $scope $name \
+ [lindex $type_record 0] [lindex $type_record end] \
+ [lrange $type_record 1 end-1] $address_space \
+ $onstack $stack \
+ $registers 0 \
+ 0 \
+ ]
+ } {
+ lappend local_variables_nlist $name
+ lappend local_variables_list [list $level $block]
+ lappend local_variables [list \
+ $scope $name \
+ [lindex $type_record 0] [lindex $type_record end] \
+ [lrange $type_record 1 end-1] $address_space \
+ $onstack $stack \
+ $registers $level \
+ $block \
+ ]
+ }
+
+ return 1
+ }
+
+ ## Handle linker record
+ # @see cvarsview_load_cdb
+ # @parm Char subtype - Variable scope ('G' == Global; 'L' == Local; 'F' == File)
+ # @parm String record - Record data
+ # @return Bool - True on success
+ private method link_address_of_symbol {subtype record} {
+ set scope {}
+ set name {}
+ set level {}
+ set block {}
+ set address {}
+
+ if {$subtype == {F}} {
+ set subtype {G}
+ }
+
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set scope [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set name [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set dolar_idx [string first {$} $record]
+ if {$dolar_idx == -1} {return 0}
+ set level [string range $record 0 [expr {$dolar_idx - 1}]]
+
+ set record [string replace $record 0 $dolar_idx]
+ set colon_idx [string first {:} $record]
+ if {$colon_idx == -1} {return 0}
+ set block [string range $record 0 [expr {$colon_idx - 1}]]
+
+ set address [string replace $record 0 $colon_idx]
+
+ if {$subtype == {G}} {
+ set addresses_lst {global_addresses}
+ set addresses_list_lst {global_addresses_list}
+ } {
+ set addresses_lst {local_addresses}
+ set addresses_list_lst {local_addresses_list}
+ }
+ lappend $addresses_lst [expr "0x$address"]
+ lappend $addresses_list_lst [list $scope $name $level $block]
+
+ return 1
+ }
+
+ ## Clear the specified viewer
+ # @parm String type - "Local" or "Global"
+ # @return void
+ public method cvarsview_clear_view {type} {
+ if {!$gui_initialized} {CreateCVarsViewGUI}
+
+ if {$type == {local}} {
+ set text_widget $text_widget_local
+ set current_level {}
+ set current_block {}
+ } {
+ set text_widget $text_widget_global
+ }
+ $text_widget configure -state normal
+ $text_widget delete 1.0 end
+ $text_widget configure -state disabled
+ }
+
+ ## Create variable record in the viewer
+ # @parm Int id - Variable ID (an unique number)
+ # @parm String name - Variable name
+ # @parm Int level - Block level
+ # @parm Bool isglobal - Is variable in global sope
+ # @parm Int isvector - Is variable a vector
+ # @parm Int start_address - Variable start address
+ # @parm Int end_address - Variable end address
+ # @parm Char memory_type - Type of memory where is the variable stored (see SDCC manual for more)
+ # @parm Bool signed - Is variable signed (has meaning only for integers)
+ # @parm String datatype - List describing data type (e.g. {SI DA2} is an array of two integers)
+ # @return void
+ private method create_variable_record {id name level isglobal isvector start_address end_address memory_type signed datatype} {
+ set data_type {}
+ set dt_func {}
+ set pointer { }
+ if {$isglobal} {
+ set text_widget $text_widget_global
+ } {
+ set text_widget $text_widget_local
+ }
+
+ foreach dt $datatype {
+ switch -glob -- $dt {
+ {DA*} { ;# Array of <n> elements
+ set argument [string replace $dt 0 1]
+ return
+ }
+ {ST*} { ;# Structure of name <name>
+ set argument [string replace $dt 0 1]
+ return
+ }
+ {SB*} { ;# Bit field of <n> bits
+ set argument [string replace $dt 0 1]
+ return
+ }
+ {SX} { ;# Sbit
+ set data_type {sbit}
+ }
+ {DG} { ;# Generic pointer
+ set pointer {*}
+ }
+ {DC} { ;# Code pointer
+ set pointer {*}
+ }
+ {DX} { ;# External ram pointer
+ set pointer {*}
+ }
+ {DD} { ;# Internal ram pointer
+ set pointer {*}
+ }
+ {DP} { ;# Paged pointer
+ set pointer {*}
+ }
+ {DI} { ;# Upper 128 byte pointer
+ set pointer {*}
+ }
+ {DF} { ;# Function
+ set dt_func {>> }
+ }
+ {SL} { ;# Long integer
+ if {$signed == {U}} {
+ set data_type {ulong}
+ } {
+ set data_type {long}
+ }
+ }
+ {SI} { ;# Integer
+ if {$signed == {U}} {
+ set data_type {uint}
+ } {
+ set data_type {int}
+ }
+ }
+ {SC} { ;# Char
+ if {$signed == {U}} {
+ set data_type {uchar}
+ } {
+ set data_type {char}
+ }
+ }
+ {SS} { ;# Short integer
+ if {$signed == {U}} {
+ set data_type {ushort}
+ } {
+ set data_type {short}
+ }
+ }
+ {SV} { ;# Void
+ set data_type {void}
+ }
+ {SF} { ;# Float
+ set data_type {float}
+ }
+ }
+ }
+
+ if {!$isglobal} {
+ set level_str [string repeat { } [expr {7 - [string length $level]}]]
+ append level_str $level { }
+ $text_widget insert insert $level_str
+ }
+
+ $text_widget configure -state normal
+ set entry [create_embedded_entry $text_widget $id $isglobal $start_address]
+ if {$data_type == {float}} {
+ $entry configure -state readonly
+ }
+ $text_widget window create insert -window $entry -pady 0
+
+ set data_type "${dt_func}${data_type}${pointer}"
+ set data_type "[string repeat { } [expr {12 - [string length $data_type]}]]$data_type"
+ set tag_indexes {}
+
+ lappend tag_indexes [$text_widget index insert]
+ $text_widget insert insert $data_type
+ lappend tag_indexes [$text_widget index insert]
+ $text_widget insert insert { }
+ lappend tag_indexes [$text_widget index insert]
+ $text_widget insert insert $name
+ lappend tag_indexes [$text_widget index insert]
+ $text_widget insert insert "\n"
+
+ $text_widget tag add tag_datatype [lindex $tag_indexes 0] [lindex $tag_indexes 1]
+ $text_widget tag add tag_variable [lindex $tag_indexes 2] [lindex $tag_indexes 3]
+
+ $text_widget configure -state disabled
+ }
+
+ ## Create embeddable entry box for representing variable value
+ # @parm Widget target_widget - Target text widget
+ # @parm Int id - Variable ID (an unique number)
+ # @parm Bool isglobal - Is variable in global scope
+ # @parm Int start_address - Variable start address
+ # @return Widget - Created entry box
+ private method create_embedded_entry {target_widget id isglobal start_address} {
+ lappend global_displayed $id
+
+ # Create entry widget
+ set entry [entry $target_widget.e_$id \
+ -width 11 -font $text_wdg_font_b \
+ -bg {#FFFFFF} -validate key \
+ -takefocus 0 -highlightthickness 0 \
+ -bd 0 -justify right \
+ -disabledbackground {#FFFFFF} \
+ -fg ${::Simulator::normal_color} \
+ -validatecommand "$this cvarsview_validate $id $isglobal $start_address %P" \
+ ]
+ $entry insert insert 0
+ if {$isglobal} {
+ set type {Global}
+ } {
+ set type {Local}
+ }
+
+ # Set event bindings
+ bind $entry <Button-1> "$this cvarsview_select_line $type [expr {$id + 1}] 1"
+ bind $entry <Key-Up> "$this cvarsview_selection_up $isglobal 1"
+ bind $entry <Key-Down> "$this cvarsview_selection_down $isglobal 1"
+ bind $entry <Key-Next> "$this cvarsview_selection_down $isglobal 4"
+ bind $entry <Key-Prior> "$this cvarsview_selection_up $isglobal 4"
+ bind $entry <Motion> "$this cvarsview_help_window_move $isglobal %X %Y"
+ bind $entry <Leave> "$this cvarsview_help_window_hide $isglobal"
+ bind $entry <Enter> "$this cvarsview_create_help_window $id $isglobal"
+ bind $entry <FocusIn> "%W configure -fg ${::Simulator::normal_color}"
+ bind $entry <Button-4> "$target_widget yview scroll -5 units"
+ bind $entry <Button-5> "$target_widget yview scroll +5 units"
+
+ # Return entry reference
+ return $entry
+ }
+
+ ## Load definded global variables into the viewer
+ # @return void
+ public method cvarsview_load_global_variables {} {
+ set id 0
+ foreach variable_def $global_variables {
+ set isvector 0
+ set idx [lsearch $global_addresses_list [list \
+ [lindex $variable_def 0] [lindex $variable_def 1] \
+ [lindex $variable_def 9] [lindex $variable_def 10] \
+ ] \
+ ]
+ if {$idx == -1} {
+ continue
+ }
+ set start_address [lindex $global_addresses [list $idx 0]]
+ set end_address [lindex $global_addresses [list $idx end]]
+ create_variable_record \
+ $id [lindex $variable_def 1] {} 1 \
+ $isvector $start_address $end_address \
+ [lindex $variable_def 5] \
+ [lindex $variable_def 3] \
+ [lindex $variable_def 4]
+ incr id
+ }
+ }
+
+ ## Load definded global variables into the viewer
+ # TODO: This function is not implemented yet
+ # @return void
+ # @parm Int level - Variable level
+ # @parm Int block - Program block
+ # @return void
+ public method cvarsview_load_local_variables {level block} {
+ return
+ if {$current_level == $level && $current_block == $block} {
+ return
+ }
+
+ set current_level $level
+ set current_block $block
+
+ set idx [lsearch -ascii -exact $local_variables_list [list $level $block]]
+ if {$idx == -1} {
+ return 0
+ }
+
+ set variable_def [lindex $local_variables $idx]
+
+ return 1
+ }
+
+ ## Validator for entryboxes representing variable values
+ # @parm Int id - Variable ID (an unique number)
+ # @parm Bool isglobal - Variable is in the global scope
+ # @parm Int address - Vaiable start address
+ # @parm String string - String to validate
+ # @return Bool - Validation result
+ public method cvarsview_validate {id isglobal address string} {
+ set value $string
+ set negative 0
+ set min_value 0
+ set max_value 0
+
+ if {!$validation_ena} {return 1}
+ set validation_ena 0
+
+ if {$isglobal} {
+ set definition [lindex $global_variables $id]
+ } {
+ set validation_ena 1
+ return 0 ;# <-- DEBUG
+ }
+ if {$address == {}} {
+ error "Unknown address"
+ }
+
+ set datatype [lindex $definition 4]
+ set mem_type [lindex $definition 5]
+ set len [lindex $definition 2]
+ set signed [lindex $definition 3]
+ if {$signed == {S}} {
+ set signed 1
+ } {
+ set signed 0
+ }
+
+ # Check for valid characters
+ if {$signed} {
+ if {[string index $string 0] == {-}} {
+ set negative 1
+ set value [string replace $string 0 0]
+ }
+ }
+ if {$value == {}} {
+ set validation_ena 1
+ return 1
+ }
+ if {![string is digit -strict $value]} {
+ set validation_ena 1
+ return 0
+ }
+
+ # Determinate valid value range
+ if {$mem_type == {J} || $mem_type == {H}} {
+ set max_value 1
+ } {
+ set max_value [expr {int(pow(2, $len*8))}]
+ if {$signed} {
+ set min_value [expr {$max_value / 2}]
+ set max_value [expr {$max_value / 2 - 1}]
+ } {
+ incr max_value -1
+ }
+ }
+
+ # Check for valid range
+ if {$negative} {
+ if {$value > $min_value} {
+ set validation_ena 1
+ return 0
+ }
+ } {
+ if {$value > $max_value} {
+ set validation_ena 1
+ return 0
+ }
+ }
+
+ ## Convert to list of decimal values
+ # Bit value
+ if {$mem_type == {J} || $mem_type == {H}} {
+ set value_list $value
+ # Other values
+ } {
+ set value_list [list]
+ set value [format %X $string]
+ set value [string range $value end-[expr {$len * 2}] end]
+
+ for {set i 0} {$i < $len} {incr i} {
+ set val [string range $value end-1 end]
+ set value [string replace $value end-1 end]
+
+ if {$val == {}} {
+ lappend value_list 0
+ } {
+ lappend value_list [expr "0x$val"]
+ }
+ }
+ }
+
+ set command {}
+ switch -- $mem_type {
+ {A} { ;# External stack
+ }
+ {B} { ;# Internal stack
+ }
+ {C} { ;# Code
+ set validation_ena 1
+ return 0
+ }
+ {D} { ;# Code / static segment
+ set validation_ena 1
+ return 0
+ }
+ {E} { ;# Internal ram (lower 128) bytes
+ set command {setDataDEC}
+ set mem_type_for_SE D
+ set synccmd {Simulator_sync_reg}
+ }
+ {F} { ;# External ram
+ set command {setXdataDEC}
+ set mem_type_for_SE X
+ set synccmd {Simulator_XDATA_sync}
+ }
+ {G} { ;# Internal ram
+ set command {setDataDEC}
+ set mem_type_for_SE I
+ set synccmd {Simulator_sync_reg}
+ }
+ {H} { ;# Bit addressable
+ set mem_type_for_SE B
+ if {[$this simulator_address_range $mem_type_for_SE $address]} {
+ $this setBit $address $value
+ $this Simulator_sync_reg [$this getRegOfBit $address]
+ }
+ set validation_ena 1
+ return 1
+ }
+ {I} { ;# SFR space
+ set mem_type_for_SE D
+ set command {setSfr_directly}
+ set synccmd {Simulator_sync_sfr}
+ }
+ {J} { ;# SBIT space
+ set mem_type_for_SE B
+ if {[$this simulator_address_range $mem_type_for_SE $address]} {
+ $this setBit $address $value
+ $this Simulator_sync_sfr [$this getRegOfBit $address]
+ }
+ set validation_ena 1
+ return 1
+ }
+ {R} { ;# Register space
+ }
+ {Z} { ;# Used for function records, or any undefined space code
+ }
+ default {
+ set validation_ena 1
+ return 1
+ }
+ }
+
+ if {$command == {}} {
+ set validation_ena 1
+ return 0
+ }
+ foreach val $value_list {
+ if {[$this simulator_address_range $mem_type_for_SE $address]} {
+ $this $command $address $val
+ $this $synccmd $address
+ }
+ incr address
+ }
+
+ set validation_ena 1
+ return 1
+ }
+
+ ## Enable or disable the panel
+ # @parm Bool enabled - 1 == Enable; 0 == Disable
+ # @return void
+ public method cvarsview_setEnabled {enabled} {
+ if {!$gui_initialized} {return}
+
+ if {$enabled} {
+ set state normal
+ } {
+ set state disabled
+ }
+
+ foreach id $global_displayed {
+ if {[$text_widget_global.e_$id cget -state] == {readonly}} {
+ continue
+ }
+ $text_widget_global.e_$id configure -state $state
+ }
+ }
+
+ ## Synchronize with simulator engine (data are obtained from the engine)
+ # @parm Char memtype - Type of memory (e.g. 'E' means IDATA)
+ # @parm Int address - Address of changed register
+ # @return void
+ public method cvarsview_sync {memtype address} {
+ if {!$gui_initialized} {return}
+ if {!$validation_ena} {return}
+ if {$memtype == {I} && !($address % 8)} {
+ set bitaddr $address
+ for {set i 0} {$i < 8} {incr i} {
+ cvarsview_sync J $bitaddr
+ incr bitaddr
+ }
+ } elseif {$memtype == {E} && $address > 31 && $address < 40} {
+ set bitaddr [expr {($address - 32) * 8}]
+ for {set i 0} {$i < 8} {incr i} {
+ cvarsview_sync H $bitaddr
+ incr bitaddr
+ }
+ }
+
+ set idx 0
+ foreach addr $global_addresses {
+ if {[lsearch $addr $address] != -1} {
+ if {[lindex $global_variables [list $idx 5]] != $memtype} {
+ continue
+ }
+ refresh_global_variable $idx
+ break
+ }
+ incr idx
+ }
+ }
+
+ ## Refresh contents of certain global variable (synchronize with simulator engine)
+ # @parm Int idx - Variable ID
+ # @return void
+ private method refresh_global_variable {idx} {
+ if {[lsearch $global_displayed $idx] == -1} {
+ return
+ }
+
+ set validation_ena 0
+ set variable_def [lindex $global_variables $idx]
+ set address_space [lindex $variable_def 5]
+ set datatype [lindex $variable_def 4]
+ set signed [lindex $variable_def 3]
+ set length [lindex $variable_def 2]
+
+ set value 0
+ set byte_num 0
+ foreach addr [lindex $global_addresses $idx] {
+ switch -- $address_space {
+ {G} {
+ if {[$this simulator_address_range I $addr]} {
+ incr value [expr {[$this getDataDEC $addr] << ($byte_num * 8)}]
+ }
+ }
+ {E} {
+ if {[$this simulator_address_range I $addr]} {
+ incr value [expr {[$this getDataDEC $addr] << ($byte_num * 8)}]
+ }
+ }
+ {I} {
+ if {[$this simulator_address_range D $addr]} {
+ incr value [expr {[$this getSfrDEC $addr] << ($byte_num * 8)}]
+ }
+ }
+ {F} {
+ if {[$this simulator_address_range X $addr]} {
+ incr value [expr {[$this getXdataDEC $addr] << ($byte_num * 8)}]
+ }
+ }
+ {J} {
+ if {[$this simulator_address_range B $addr]} {
+ incr value [$this getBit $addr]
+ }
+ }
+ {H} {
+ if {[$this simulator_address_range B $addr]} {
+ incr value [$this getBit $addr]
+ }
+ }
+ }
+ incr byte_num
+ }
+
+ ## Adjust value
+ # IEEE 754-1985 single precision floating-point number
+ if {$datatype == {SF}} {
+ ## Special cases
+ # Zero
+ if {$value == 0} {
+ # One
+ } elseif {$value == 0x3F800000} {
+ set value 1
+ # Minus One
+ } elseif {$value == 0xBF800000} {
+ set value -1
+ # Positive infinity
+ } elseif {$value == 0x7F800000} {
+ set value {+ infinity}
+ # Negative infinity
+ } elseif {$value == 0xFF800000} {
+ set value {- infinity}
+ # Not a number
+ } elseif {(($value & 0x7F800000) == 0x7F800000) && ($value & 0x007FFFFF)} {
+ set value {NaN}
+
+ ## Common cases
+ } else {
+ set sign [expr {($value & 0x80000000) ? 1 : 0}]
+ set exponent [expr {int(($value & 0x7F800000) >> 23)}]
+ set fraction_b [expr {$value & 0x007FFFFF}]
+
+ incr exponent -127
+
+ set fraction 1
+ set val 0.5
+ set mask 0x00400000
+ for {set i 0} {$i < 23} {incr i} {
+ if {$fraction_b & $mask} {
+ set fraction [expr {$fraction + $val}]
+ }
+ set val [expr {$val / 2}]
+ set mask [expr {$mask >> 1}]
+ }
+
+ set value [expr {pow(-1,$sign) * pow(2,$exponent) * $fraction}]
+ }
+
+ # Common signed integer
+ } elseif {$signed == {S}} {
+ set max_positive_value [expr {pow(2,($length * 8 - 1)) - 1}]
+ if {$value > $max_positive_value} {
+ set value [expr {pow(2,($length * 8)) - $value}]
+ }
+ set value [expr {int($value)}]
+
+ # Common unsigned integer
+ } else {
+ set value [expr {int($value)}]
+ }
+
+ # Write value to the entrybox
+ if {$datatype == {SF}} {
+ $text_widget_global.e_$idx configure -state normal
+ }
+ $text_widget_global.e_$idx delete 0 end
+ $text_widget_global.e_$idx insert 0 $value
+ $text_widget_global.e_$idx configure -fg ${::Simulator::highlight_color}
+ if {$datatype == {SF}} {
+ $text_widget_global.e_$idx configure -state readonly
+ }
+
+ # Reeanable synchronization and entryboxes validation
+ set validation_ena 1
+ }
+}
diff --git a/lib/bottompanel/find_in_files.tcl b/lib/bottompanel/find_in_files.tcl
new file mode 100755
index 0000000..d085110
--- /dev/null
+++ b/lib/bottompanel/find_in_files.tcl
@@ -0,0 +1,750 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements panel "Find in files", GUI and function
+# Inteted for bottom panel
+# --------------------------------------------------------------------------
+
+class FindInFiles {
+
+ common count 0 ;# Counter of class instances
+
+ # Variables related to object initialization
+ private variable parent ;# Widget: parent widget
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+
+ private variable obj_idx ;# Int: Object index
+ private variable abort_variable 0 ;# Bool: Abort search
+ private variable iteration 0 ;# Int: Counter of search iterations (lines read)
+ private variable folder ;# String: Choosen folder
+ private variable pattern ;# String: Search pattern
+ private variable reg_expr ;# Bool: Use regular expression
+ private variable case_sen ;# Bool: Perform case sensitive search
+ private variable pattern_length ;# Int: Pettern length
+
+ private variable pattern_entry ;# Windegt: EntryBox "Pattern"
+ private variable main_frame ;# Widget: Main frame
+ private variable menu {} ;# Widget: popup menu for text widge
+ private variable text_widget ;# Widget: Text widget to show results
+ private variable clear_button ;# Widget: Button "Clear"
+ private variable find_stop_button {} ;# Widget: Button "Find / Stop"
+
+ constructor {} {
+ # Increment object counter
+ incr count
+ set obj_idx $count
+
+ # Load configuration
+ set ::FindInFiles::recursive_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 0]
+ set ::FindInFiles::regular_expr_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 1]
+ set ::FindInFiles::case_sensitive_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 2]
+ set ::FindInFiles::folder_$obj_idx [$this cget -projectPath] ;#[lindex $::CONFIG(FIND_IN_FILES_CONFIG) 3]
+ set ::FindInFiles::mask_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 4]
+ set ::FindInFiles::pattern_$obj_idx [lindex $::CONFIG(FIND_IN_FILES_CONFIG) 5]
+
+ # Validate loaded configuration
+ if {![string is boolean -strict [subst "\$::FindInFiles::recursive_$obj_idx"]]} {
+ set ::FindInFiles::recursive_$obj_idx 1
+ }
+ if {![string is boolean -strict [subst "\$::FindInFiles::regular_expr_$obj_idx"]]} {
+ set ::FindInFiles::regular_expr_$obj_idx 0
+ }
+ if {![string is boolean -strict [subst "\$::FindInFiles::case_sensitive_$obj_idx"]]} {
+ set ::FindInFiles::case_sensitive_$obj_idx 1
+ }
+ }
+
+ destructor {
+ # Remove status bar help for popup menus
+ if {$menu != {}} {
+ menu_Sbar_remove $menu
+ }
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - GUI parent widget
+ # @return void
+ public method PrepareFindInFiles {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method FindInFilesTabRaised {} {
+ $pattern_entry selection range 0 end
+ $pattern_entry icursor end
+ focus $pattern_entry
+ }
+
+ ## Create GUI of messages tab
+ # @return void
+ public method CreateFindInFilesGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ create_findinfilesgui
+ create_tags_and_bindings
+ create_popup_menu
+ }
+
+ ## Create GUI elements
+ # @return void
+ private method create_findinfilesgui {} {
+ set main_frame [frame $parent.main_frame]
+
+ ## Top frame
+ set top_frame [frame $main_frame.top_frame]
+ # Entry "Pattern"
+ set pattern_entry [ttk::entry $top_frame.pattern_entry \
+ -validate all \
+ -width 1 \
+ -textvariable ::FindInFiles::pattern_$obj_idx \
+ -validatecommand "$this findinfiles_validate_crit_ent 0 %P" \
+ ]
+ bind $pattern_entry <Return> "$this findinfiles_search"
+ bind $pattern_entry <KP_Enter> "$this findinfiles_search"
+ setStatusTip -widget $pattern_entry \
+ -text [mc "Search pattern"]
+ # Entry "Mask"
+ set mask_entry [ttk::entry $top_frame.mask_entry \
+ -validate all \
+ -width 1 \
+ -textvariable ::FindInFiles::mask_$obj_idx \
+ -validatecommand "$this findinfiles_validate_crit_ent 1 %P" \
+ ]
+ bind $mask_entry <Return> "$this findinfiles_search"
+ bind $mask_entry <KP_Enter> "$this findinfiles_search"
+ setStatusTip -widget $mask_entry \
+ -text [mc "File mask (e.g. \"*.c,*.asm\")"]
+ # Entry "Folder"
+ set folder_entry_frm [frame $top_frame.folder_entry_frm]
+ set folder_entry [ttk::entry $folder_entry_frm.folder_entry \
+ -textvariable ::FindInFiles::folder_$obj_idx \
+ -validate all \
+ -width 1 \
+ -validatecommand "$this findinfiles_validate_crit_ent 2 %P" \
+ ]
+ set ::FindInFiles::folder_$obj_idx [$this cget -projectPath]
+ bind $folder_entry <Return> "$this findinfiles_search"
+ bind $folder_entry <KP_Enter> "$this findinfiles_search"
+ pack $folder_entry -side left -fill x -expand 1
+ # Button "Select directory"
+ pack [ttk::button $folder_entry_frm.select_dir_but \
+ -image ::ICONS::16::fileopen \
+ -style Flat.TButton \
+ -command "$this findinfiles_select_dir" \
+ ] -side left
+ DynamicHelp::add $folder_entry_frm.select_dir_but \
+ -text [mc "Choose destination location"]
+ setStatusTip -widget $folder_entry_frm.select_dir_but -text [mc "Select folder"]
+ # Checkbutton "Recursive"
+ pack [checkbutton $folder_entry_frm.recursive_chb \
+ -variable ::FindInFiles::recursive_$obj_idx \
+ -text [mc "Recursive"] \
+ ] -side left -padx 10
+ setStatusTip -widget $folder_entry_frm.recursive_chb -text [mc "Search in all subfolders"]
+ # Button "Start / Stop search"
+ set top_bottom_frame [frame $top_frame.bottom_frame]
+ set find_stop_button [ttk::button $top_bottom_frame.find_stop_button \
+ -text [mc "Find"] \
+ -image ::ICONS::16::find \
+ -compound left \
+ -command "$this findinfiles_search" \
+ -width 7 \
+ ]
+ setStatusTip -widget $find_stop_button -text [mc "Start / Stop search"]
+ # Button "Clear"
+ set clear_button [ttk::button $top_bottom_frame.clear_button \
+ -text [mc "Clear"] \
+ -image ::ICONS::16::clear_left \
+ -compound left \
+ -command "$this findinfiles_clear" \
+ -state disabled \
+ -width 7 \
+ ]
+ setStatusTip -widget $clear_button -text [mc "Clear results"]
+ pack $find_stop_button -side left
+ pack $clear_button -side left
+ # Separator
+ pack [ttk::separator $top_bottom_frame.sep \
+ -orient vertical \
+ ] -fill y -side left -padx 10 -pady 2
+ # Checkbutton "Case sensitive"
+ pack [checkbutton $top_bottom_frame.case_sen_chb \
+ -text [mc "Case sensitive"] \
+ -variable ::FindInFiles::case_sensitive_$obj_idx \
+ ] -side left
+ setStatusTip -widget $top_bottom_frame.case_sen_chb \
+ -text [mc "Perform case sensitive search"]
+ # Checkbutton "Regular expression"
+ pack [checkbutton $top_bottom_frame.regular_expr_chb \
+ -text [mc "Regular expression"] \
+ -variable ::FindInFiles::regular_expr_$obj_idx \
+ ] -side left
+ setStatusTip -widget $top_bottom_frame.regular_expr_chb \
+ -text [mc "Pattern is a regular expression"]
+ # Labels ... (Pattern, Folder, Mask)
+ grid [label $top_frame.pattern_lbl \
+ -text [mc "Pattern:"] \
+ ] -row 0 -column 0 -sticky w
+ grid [label $top_frame.folder_lbl \
+ -text [mc "Folder:"] \
+ ] -row 0 -column 4 -sticky w
+ grid [label $top_frame.template_lbl \
+ -text [mc "Mask:"] \
+ ] -row 1 -column 0 -sticky w
+ # Button "Clear pattern entrybox"
+ grid [ttk::button $top_frame.pattern_clr_but \
+ -image ::ICONS::16::clear_left \
+ -style Flat.TButton \
+ -command "set ::FindInFiles::pattern_$obj_idx {}"\
+ ] -row 0 -column 2
+ setStatusTip -widget $top_frame.pattern_clr_but \
+ -text [mc "Clear pattern entrybox"]
+ # Button "Show help for file mask"
+ grid [ttk::button $top_frame.mask_show_help \
+ -image ::ICONS::16::help \
+ -style Flat.TButton \
+ -command "$this findinfiles_hlp" \
+ ] -row 1 -column 2
+ setStatusTip -widget $top_frame.mask_show_help \
+ -text [mc "Show help for file mask"]
+ # Place some widgets into the grid
+ grid $pattern_entry -row 0 -column 1 -sticky we
+ grid $folder_entry_frm -row 0 -column 5 -sticky we
+ grid $mask_entry -row 1 -column 1 -sticky we
+ grid $top_bottom_frame -row 1 -column 4 -columnspan 2 -sticky we
+ grid columnconfigure $top_frame 1 -weight 1
+ grid columnconfigure $top_frame 5 -weight 1
+ grid columnconfigure $top_frame 3 -minsize 20
+
+ ## Bottom frame (text widget and its scrollbar)
+ set bottom_frame [frame $main_frame.bottom_frame]
+ set text_widget [text $bottom_frame.text \
+ -bg white -state disabled -bd 1 -wrap none \
+ -highlightthickness 0 -exportselection 0 \
+ -cursor left_ptr -width 0 -height 0 \
+ -yscrollcommand "$bottom_frame.scrollbar set" \
+ -font [font create -family helvetica -size -12] \
+ -fg {#555555} \
+ ]
+ pack $text_widget -side left -fill both -expand 1
+ pack [ttk::scrollbar $bottom_frame.scrollbar \
+ -orient vertical -command "$text_widget yview" \
+ ] -side right -after $text_widget -fill y
+
+ # Mask panel frames
+ pack $top_frame -fill x -anchor nw
+ pack $bottom_frame -fill both -expand 1
+ pack $main_frame -fill both -expand 1
+
+ # Adjust GUI
+ findinfiles_validate_crit_ent -1 {}
+ }
+
+ ## Create text tags and event binding for the text widget
+ # @return void
+ private method create_tags_and_bindings {} {
+ # Create tags
+ set bold_font [font create -family helvetica -size -12 -weight bold]
+ $text_widget tag configure tag_highlight -foreground {#000000} -font $bold_font
+ $text_widget tag configure tag_filename -foreground {#0000DD}
+ $text_widget tag configure tag_linenumber -foreground {#00DD00}
+ $text_widget tag configure tag_normal -foreground {#000000}
+ $text_widget tag configure tag_cur_line -background {#FFFF88}
+
+ # Create evet bindings
+ bind $text_widget <ButtonRelease-3> "$this findinfiles_popupmenu %X %Y %x %y; break"
+ bind $text_widget <Button-1> "$this findinfiles_click %x %y; break"
+ bind $text_widget <Double-Button-1> "$this findinfiles_doubleclick %x %y; break"
+ bind $text_widget <<Selection>> "false_selection $text_widget; break"
+ }
+
+ ## Create popup menu for the text widget
+ # @return void
+ private method create_popup_menu {} {
+ set menu $text_widget.popup_menu
+ menuFactory {
+ {command "Go to" {} 0 "findinfiles_goto_cur_line"
+ {goto} "Go to this line"}
+ {command "Clear" {} 0 "findinfiles_clear"
+ {editdelete} "Clear this panel"}
+ } $menu 0 "$this " 0 {}
+ $menu entryconfigure [::mc "Clear"] -state disabled
+ }
+
+ ## Invoke file selection dialog to select folder where to search
+ # @return void
+ public method findinfiles_select_dir {} {
+ KIFSD::FSD ::fsd \
+ -title [mc "Choose directory - MCU 8051 IDE"] \
+ -fileson 0 -master . \
+ -directory [subst "\$::FindInFiles::folder_$obj_idx"]
+ fsd setokcmd "set ::FindInFiles::folder_$obj_idx \[::fsd get\]"
+ fsd activate
+ }
+
+ ## Start searching
+ # @return void
+ public method findinfiles_search {} {
+ # Gain search options
+ set folder [file normalize [subst "\$::FindInFiles::folder_$obj_idx"]]
+ set mask [subst "\$::FindInFiles::mask_$obj_idx"]
+ set pattern [subst "\$::FindInFiles::pattern_$obj_idx"]
+ set reg_expr [subst "\$::FindInFiles::regular_expr_$obj_idx"]
+ set case_sen [subst "\$::FindInFiles::case_sensitive_$obj_idx"]
+
+ # Validate search options
+ if {![string length $folder] || ![string length $mask] || ![string length $pattern]} {
+ return
+ }
+ if {![file exists $folder]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Folder not found"] \
+ -message [mc "The specified folder does not exist.\n'%s'" $folder]
+ return
+ }
+ if {![file isdirectory $folder]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Folder not found"] \
+ -message [mc "The string specified as a folder is not a folder.\n'%s'" $folder]
+ return
+ }
+ if {$reg_expr && [catch {regexp -about $pattern}]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Error"] \
+ -message [mc "Invalid regular expression"]
+ return
+ }
+
+ # Adjust GUI (Find button, text widget ...)
+ $find_stop_button configure \
+ -text [mc "Stop"] -image ::ICONS::16::cancel \
+ -command "$this findinfiles_stop"
+ $text_widget configure -state normal
+ $text_widget delete 0.0 end
+ update
+
+ # Determinate list of files
+ set new_mask {}
+ foreach glob [split $mask {,}] {
+ lappend new_mask $glob
+ }
+ set mask $new_mask
+ set files [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach m $mask {
+ eval "append files { } \[glob -directory {$folder} -nocomplain -types {f l} -- $m\]"
+ }
+ }
+ if {[subst "\$::FindInFiles::recursive_$obj_idx"]} {
+ append files { } [regsub -all {[\{\}]} [recursive_search $folder $mask] {\\&}]
+ }
+
+ # Search
+ if {!$reg_expr && !$case_sen} {
+ set pattern [string tolower $pattern]
+ }
+ set pattern_length [string length $pattern]
+ set iteration 0
+ foreach filename $files {
+ if {[search_in_file $filename]} {
+ break
+ }
+ }
+
+ # Adjust GUI (Find button, text widget ...)
+ $text_widget delete end-1l end
+ $text_widget configure -state disabled
+ $find_stop_button configure \
+ -text [mc "Find"] \
+ -image ::ICONS::16::find \
+ -command "$this findinfiles_search"
+
+ # Enable / Disable clear button and clear entry in the popup menu
+ if {[$text_widget index {1.0 lineend}] == {1.0}} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $menu entryconfigure [::mc "Clear"] -state $state
+ $clear_button configure -state $state
+ }
+
+ ## Perform recursive search for ceratin files in certain folder
+ # @parm String folder - Directory to search
+ # @parm String mask - File masks
+ # @return List - Found files
+ private method recursive_search {folder mask} {
+ set files {}
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach dir [glob -directory $folder -nocomplain -types {d} -- *] {
+ foreach m $mask {
+ eval "append files { } \[glob -directory {$dir} -nocomplain -types {f l} -- $m\]"
+ }
+ append files { } [recursive_search $dir $mask]
+ }
+ }
+ if {[llength $files]} {
+ update
+ }
+ return $files
+ }
+
+ ## Search in certain file
+ # @parm String filename - File where to search in
+ # @return Bool - 1 == Search aborted; 0 == Normal
+ private method search_in_file {filename} {
+ # Open file
+ if {[catch {
+ set file [open $filename r]
+ }]} {
+ return 0
+ }
+
+ # Local variables
+ set relative_filename [string replace $filename 0 [string length $folder]]
+ set indexes {}
+ set text_idx {end}
+ set line_number 0
+ set matched_str {}
+
+ # Iterate over lines
+ while {![eof $file]} {
+ incr line_number
+ incr iteration
+ set line [gets $file]
+
+ # Update GUI and evaluate abort variable
+ if {$iteration > 100} {
+ if {[lindex [$text_widget yview] 1] == 1} {
+ $text_widget see end
+ }
+ update
+ if {$abort_variable} {
+ set abort_variable 0
+ return 1
+ }
+ }
+
+ ## Search string
+ if {!$case_sen} {
+ set line [string tolower $line]
+ }
+ set indexes {}
+ set lengths {}
+ set last_idx -1
+ set idx 0
+ set found 1
+ # Regular expression
+ if {$reg_expr} {
+ while $found {
+ set found 0
+ if {$case_sen} {
+ set found [regexp -start $idx -- $pattern $line matched_str]
+ } {
+ set found [regexp -nocase -start $idx -- $pattern $line matched_str]
+ }
+
+ set idx [string first $matched_str $line $idx]
+ if {$last_idx >= $idx} {
+ break
+ }
+
+ lappend indexes $idx
+ lappend lengths [string length $matched_str]
+ incr idx
+ set last_idx $idx
+ }
+ # Pure string pattern
+ } {
+ while {$idx != -1} {
+ set idx [string first $pattern $line $idx]
+ if {$last_idx >= $idx} {
+ break
+ }
+
+ lappend indexes $idx
+ lappend lengths $pattern_length
+ incr idx
+ set last_idx $idx
+ }
+ }
+ if {![llength $indexes]} {
+ continue
+ }
+
+ ## Display result
+ # Filename
+ $text_widget insert insert $relative_filename
+ $text_widget tag add tag_filename [list insert linestart] insert
+ set text_idx [$text_widget index insert]
+ # ":"
+ $text_widget insert insert ": "
+ $text_widget tag add tag_normal $text_idx insert
+ set text_idx [$text_widget index insert]
+ # Line number
+ $text_widget insert insert $line_number
+ $text_widget tag add tag_linenumber $text_idx insert
+ set text_idx [$text_widget index insert]
+ # ":"
+ $text_widget insert insert ": "
+ $text_widget tag add tag_normal $text_idx insert
+ set text_idx [$text_widget index insert]
+ scan $text_idx {%d.%d} row col
+ # Line content and highlight pattern found
+ $text_widget insert insert $line
+ foreach index $indexes length $lengths {
+ $text_widget tag add tag_highlight \
+ $row.[expr {$col + $index}] \
+ $row.[expr {$col + $index + $length}]
+ }
+ $text_widget insert insert "\n"
+ }
+
+ # Close file
+ catch {
+ close $file
+ }
+ return 0
+ }
+
+ ## Abort search
+ # @return void
+ public method findinfiles_stop {} {
+ set abort_variable 1
+ }
+
+ ## Clear results
+ # @return void
+ public method findinfiles_clear {} {
+ # Clear text widget
+ $text_widget configure -state normal
+ $text_widget delete 0.0 end
+ $text_widget configure -state disabled
+
+ # Adjust controls
+ $menu entryconfigure [::mc "Clear"] -state disabled
+ $clear_button configure -state disabled
+ }
+
+ ## Invoke popup menu for the text widget
+ # @parm Int X - Absolute mouse pointer position (X axis)
+ # @parm Int Y - Absolute mouse pointer position (Y axis)
+ # @parm Int x - Relative mouse pointer position (X axis)
+ # @parm Int y - Relative mouse pointer position (Y axis)
+ # @return void
+ public method findinfiles_popupmenu {X Y x y} {
+ findinfiles_click $x $y
+ set index [$text_widget index [list @$x,$y linestart]]
+ if {[$text_widget compare $index == [list $index lineend]]} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $menu entryconfigure [::mc "Go to"] -state $state
+ tk_popup $menu $X $Y
+ }
+
+ ## Select line in the text widget by mouse click
+ # @parm Int x - Relative mouse pointer position (X axis)
+ # @parm Int y - Relative mouse pointer position (Y axis)
+ # @return void
+ public method findinfiles_click {x y} {
+ set index [$text_widget index [list @$x,$y linestart]]
+ $text_widget tag remove tag_cur_line 0.0 end
+ if {[$text_widget compare $index != [list $index lineend]]} {
+ $text_widget tag add tag_cur_line $index $index+1l
+ }
+ }
+
+ ## Handle <DoubleButton-1> event on the text widget
+ # - Switch editor and go to specified line
+ # @parm Int x - Relative mouse pointer position (X axis)
+ # @parm Int y - Relative mouse pointer position (Y axis)
+ # @return void
+ public method findinfiles_doubleclick {x y} {
+ editor_goto_line [$text_widget index [list @$x,$y linestart]]
+ }
+
+ ## Activate hypertext link on the specified index
+ # @parm TextIndex index - Index of linestart
+ # @return void
+ private method editor_goto_line {index} {
+ # Determinate line number and relative name of file
+ set filename [$text_widget tag nextrange tag_filename $index [list $index lineend]]
+ set linenumber [$text_widget tag nextrange tag_linenumber $index [list $index lineend]]
+ set filename [$text_widget get [lindex $filename 0] [lindex $filename 1]]
+ set linenumber [$text_widget get [lindex $linenumber 0] [lindex $linenumber 1]]
+ if {![string length $filename] || ![string length $linenumber]} {
+ return
+ }
+
+ # Switch editor
+ set current_filename [lindex [$this editor_procedure {} getFileName {}] 1]
+ if {$filename != $current_filename} {
+ if {![$this fucus_specific_editor $filename 1]} {
+ set filename [file join $folder $filename]
+ if {[$this openfile $filename 1 . def def 0 0 {}] != {}} {
+ $this switch_to_last
+ update idle
+ $this editor_procedure {} parseAll {}
+ } {
+ return
+ }
+ }
+ }
+
+ # Go to target line
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto $linenumber
+ }
+
+ ## Validator function for all entry widgets
+ # Conditionaly disables button "Find"
+ # @parm Int for_what - Number of entrybox from which this function was invoked
+ # 0 - Pattern
+ # 1 - Folder
+ # 2 - Mask
+ # @parm String content - String to validate
+ # @return Bool - Always 1
+ public method findinfiles_validate_crit_ent {for_what content} {
+ if {![winfo exists $find_stop_button]} {
+ return 1
+ }
+ set state normal
+ set string {}
+ foreach var [list pattern_$obj_idx folder_$obj_idx mask_$obj_idx] \
+ number {0 1 2} \
+ {
+ if {$for_what == $number} {
+ set string $content
+ } {
+ set string [subst "\$::FindInFiles::$var"]
+ }
+ if {![string length $string]} {
+ set state disabled
+ break
+ }
+ }
+ $find_stop_button configure -state $state
+ return 1
+ }
+
+ ## Invoke helwindow for entrybox "Mask"
+ # @return void
+ public method findinfiles_hlp {} {
+ # Destroy legend window
+ if {[winfo exists .findinfiles_help_win]} {
+ grab release .findinfiles_help_win
+ destroy .findinfiles_help_win
+ return
+ }
+ set x [expr {[winfo pointerx .] + 10}]
+ set y [winfo pointery .]
+
+ # Create legend window
+ set win [toplevel .findinfiles_help_win -class {Help} -bg {#EEEEEE}]
+ set frame [frame $win.f -bg {#555555} -bd 0 -padx 1 -pady 1]
+ wm overrideredirect $win 1
+
+ # Click to close
+ bind $win <Button-1> "grab release $win; destroy $win"
+
+ # Create header "-- click to close --"
+ pack [label $frame.lbl_header \
+ -text [mc "-- click to close --"] \
+ -bg {#FFFF55} -font $::smallfont \
+ -fg {#000000} -anchor c \
+ ] -side top -anchor c -fill x
+
+ # Create text widget
+ set text [text $frame.text \
+ -bg {#FFFFCC} \
+ -exportselection 0 \
+ -takefocus 0 \
+ -cursor left_ptr \
+ -bd 0 -relief flat \
+ -font ${::Editor::defaultFont} \
+ ]
+
+ pack $frame -fill both -expand 1
+
+ # Fill the text widget
+ $text insert end "Comma separated list of file masks (e.g \"*.c,*.h,*.asm\")\n"
+ $text insert end "The mask may contain any of the following special characters:\n"
+ $text insert end " ? Matches any single character.\n"
+ $text insert end " * Matches any sequence of zero or more characters.\n"
+ $text insert end " \[chars\] Matches any single character in chars.\n"
+ $text insert end " If chars contains a sequence of the form a-b then any\n"
+ $text insert end " character between a and b (inclusive) will match.\n"
+ $text insert end " \x Matches the character x."
+
+ # Show the text
+ $text configure -state disabled
+ pack $text -side bottom -fill both -expand 1
+
+ # Show the window
+ wm geometry $win "=600x180+$x+$y"
+ update
+ catch {
+ grab -global $win
+ }
+ }
+
+ ## Menu action "Go to"
+ # @return void
+ public method findinfiles_goto_cur_line {} {
+ set index [lindex [$text_widget tag nextrange tag_cur_line 1.0 end] 0]
+ if {$index == {}} {
+ return
+ }
+ editor_goto_line $index
+ }
+
+ ## Get configuration list for this panel
+ # - Intented for session management
+ # @return void
+ public method findinfiles_get_config {} {
+ return [list \
+ [subst "\$::FindInFiles::recursive_$obj_idx"] \
+ [subst "\$::FindInFiles::regular_expr_$obj_idx"] \
+ [subst "\$::FindInFiles::case_sensitive_$obj_idx"] \
+ [subst "\$::FindInFiles::folder_$obj_idx"] \
+ [subst "\$::FindInFiles::mask_$obj_idx"] \
+ [subst "\$::FindInFiles::pattern_$obj_idx"] \
+ ]
+ }
+}
diff --git a/lib/bottompanel/graph.tcl b/lib/bottompanel/graph.tcl
new file mode 100755
index 0000000..e9def9b
--- /dev/null
+++ b/lib/bottompanel/graph.tcl
@@ -0,0 +1,714 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Graph panel in the bottom panel - shows states of ports
+# --------------------------------------------------------------------------
+
+source "${::LIB_DIRNAME}/bottompanel/graph_wdg.tcl" ;# Graph widget
+
+class Graph {
+ ## COMMON
+
+ # Variables related to object initialization
+ private variable data_list ;# Teportary variable -- Configuration list
+ private variable gui_initialized 0 ;# Bool: GUI created
+ private variable parent ;# Parent widget
+
+ private variable grid_mode {b} ;# Current grid mode (one of {b n x y})
+ private variable drawing_on 0 ;# Bool: Graph enabled
+ private variable magnification 0 ;# Magnification level (0..3)
+ private variable active_page {} ;# String: ID of currently active page
+
+ private variable start_stop_button ;# Widget: Button "ON"/"OFF"
+ private variable zoom_in_button ;# Widget: Button "Zoom in"
+ private variable zoom_out_button ;# Widget: Button "Zoom out"
+ private variable clear_marks_button ;# Widget: Button "Clear marks"
+ private variable grid_button ;# Widget: Button "Change grid"
+
+ private variable pages_manager ;# Widget: Pages manager for graph widgets
+ private variable nb_state_frame ;# Widget: Frame containing graph "True state"
+ private variable nb_latches_frame ;# Widget: Frame containing graph "Latches"
+ private variable nb_output_frame ;# Widget: Frame containing graph "True Output"
+
+ private variable state_but ;# Widget: Button "True state"
+ private variable latches_but ;# Widget: Button "Latches"
+ private variable output_but ;# Widget: Button "True Output"
+
+ private variable graph_state ;# Object: Graph widget representing "True state"
+ private variable graph_latches ;# Object: Graph widget representing "Latches"
+ private variable graph_output ;# Object: Graph widget representing "True Output"
+
+ private variable graph_state_created 0 ;# Bool: GUI of object $graph_state created
+ private variable graph_latches_created 0 ;# Bool: GUI of object $graph_latches created
+ private variable graph_output_created 0 ;# Bool: GUI of object $graph_output created
+
+
+ ## Object constructor
+ constructor {} {
+ # Configure localy used ttk styles
+ ttk::style configure Graph_ActiveTab.TButton \
+ -background {#AAAAFF} \
+ -padding 0 \
+ -borderwidth 1
+ ttk::style map Graph_ActiveTab.TButton \
+ -background [list active {#DDDDFF}] \
+ -foreground [list active {#0000DD} !active {#000000}]
+ }
+
+ ## Object destructor
+ destructor {
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget Parent - GUI parent widget
+ # @parm List _data_list - Configuration data list
+ # @return void
+ public method PrepareGraph {Parent _data_list} {
+ set parent $Parent
+ set data_list $_data_list
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method GraphTabRaised {} {
+ }
+
+ ## Initialize graph
+ # @return void
+ public method CreateGraphGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Create panel frames
+ set top_bar [frame $parent.top_bar -bg {#CCCCCC}] ;# Buttons for switching pages
+ set bottom_frame [frame $parent.bottom_frame] ;# Graphs
+ set left_bar [frame $bottom_frame.left_bar] ;# Button bar on the left
+
+ ## Create button bar
+ # Button "Enable/Disable"
+ set start_stop_button [ttk::button $left_bar.start_stop_button \
+ -command "$this graph_change_status_on" \
+ -width 3 \
+ ]
+ DynamicHelp::add $left_bar.start_stop_button \
+ -text [mc "Turn graph on/off"]
+ setStatusTip -widget $start_stop_button -text [mc "Enable/Disable graph"]
+ bind $start_stop_button <Button-3> "$this graph_change_status_on; break"
+ pack $start_stop_button -anchor n
+ # Separator
+ pack [ttk::separator $left_bar.sep0 -orient horizontal] -fill x -pady 2
+ # Button "Change grid mode"
+ set grid_button [ttk::button $left_bar.grid_button \
+ -style Flat.TButton \
+ -image ::ICONS::16::grid1 \
+ -command "$this graph_switch_grid_mode 1" \
+ ]
+ DynamicHelp::add $grid_button -text [mc "Change grid"]
+ setStatusTip -widget $grid_button -text [mc "Change grid morfology"]
+ pack $grid_button -anchor n
+ bind $grid_button <Button-1> "$this graph_switch_grid_mode 1; break"
+ bind $grid_button <Button-3> "$this graph_switch_grid_mode -1; break"
+ # Separator
+ pack [ttk::separator $left_bar.sep1 -orient horizontal] -fill x -pady 2
+ # Button "Zoom in"
+ set zoom_in_button [ttk::button $left_bar.zoom_in_button \
+ -image ::ICONS::16::viewmag_in \
+ -command "$this graph_zoom_in" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $zoom_in_button -text [mc "Change bit length on X axis to a lower value"]
+ setStatusTip -widget $zoom_in_button -text [mc "Zoom in (X axis)"]
+ pack $zoom_in_button
+ # Button "Zoom out"
+ set zoom_out_button [ttk::button $left_bar.zoom_out_button \
+ -image ::ICONS::16::viewmag_out \
+ -command "$this graph_zoom_out" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $zoom_out_button -text [mc "Change bit length on X axis to a higher value"]
+ setStatusTip -widget $zoom_out_button -text [mc "Zoom out (X axis)"]
+ pack $zoom_out_button
+ # Separator
+ pack [ttk::separator $left_bar.sep2 -orient horizontal] -fill x -pady 2
+ # Button "Clear marks"
+ set clear_marks_button [ttk::button $left_bar.clear_marks_button \
+ -image ::ICONS::16::editdelete \
+ -command "$this graph_clear_marks" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $clear_marks_button -text [mc "Clear user marks"]
+ setStatusTip -widget $clear_marks_button -text [mc "Clear marks"]
+ pack $clear_marks_button
+
+ # Create graphs
+ set pages_manager [PagesManager $bottom_frame.pages_manager -background {#eeeeee}]
+ set nb_state_frame [$pages_manager add {state}]
+ set nb_latches_frame [$pages_manager add {latches}]
+ set nb_output_frame [$pages_manager add {output}]
+
+ ## Create buttons
+ # Button "True state"
+ set state_but [ttk::button $top_bar.state_but \
+ -text [mc "True state"] \
+ -image ::ICONS::16::dot_g \
+ -command "$this Graph_set_active_page {state}" \
+ -compound left \
+ -style Flat.TButton \
+ ]
+ pack $state_but -side left -pady 0 -ipady 0 -padx 1
+ # Button "Port Latches"
+ set latches_but [ttk::button $top_bar.latches_but \
+ -text [mc "Port latches"] \
+ -compound left \
+ -image ::ICONS::16::dot \
+ -command "$this Graph_set_active_page {latches}" \
+ -style Flat.TButton \
+ ]
+ pack $latches_but -side left -pady 0 -ipady 0 -padx 1
+ # Button "True Output"
+ set output_but [ttk::button $top_bar.output_but \
+ -text [mc "True output"] \
+ -compound left \
+ -image ::ICONS::16::dot_r \
+ -command "$this Graph_set_active_page {output}" \
+ -style Flat.TButton \
+ ]
+ pack $output_but -side left -pady 0 -ipady 0 -padx 1
+ # Button "Show legend"
+ set help_but [ttk::button $top_bar.help_but \
+ -text [mc "Legend"] \
+ -command "$this Graph_show_legend" \
+ -style Flat.TButton \
+ ]
+ pack $help_but -side left -pady 0 -ipady 0 -padx 1
+
+ set graph_state [GraphWidget #auto $nb_state_frame $this]
+ set graph_latches [GraphWidget #auto $nb_latches_frame $this]
+ set graph_output [GraphWidget #auto $nb_output_frame $this]
+
+ pack $top_bar -anchor nw -ipady 1
+ pack $left_bar -anchor n -side left
+ pack [ttk::separator $bottom_frame.sep -orient vertical] -fill y -side left -padx 1
+ pack $pages_manager -fill both -expand 1 -side left
+ pack $bottom_frame -fill both -expand 1
+
+ # Adjust configuration to the given datalist
+ set grid_mode [lindex $data_list 0]
+ set magnification [lindex $data_list 1]
+ set drawing_on [lindex $data_list 2]
+ set mark_flags_s [lindex $data_list 3]
+ set mark_flags_l [lindex $data_list 4]
+ set mark_flags_o [lindex $data_list 5]
+ set active_page [lindex $data_list 6]
+
+ # Validate the loaded confiuration
+ foreach mark_flags {mark_flags_s mark_flags_l mark_flags_o} {
+ set mark_flags_data [subst "\$$mark_flags"]
+ if {
+ ![regexp {^[01]+$} $mark_flags_data]
+ ||
+ [string bytelength $mark_flags_data] != 170
+ } then {
+ puts stderr "Invalid graph mark flags -- discarded"
+ set $mark_flags [string repeat {0 } 170]
+ } else {
+ set $mark_flags [split $mark_flags_data {}]
+ }
+ }
+ if {
+ $magnification != {0} && $magnification != {1} &&
+ $magnification != {2} && $magnification != {3}
+ } {
+ puts stderr "Invalid graph magnification level -- setting to default"
+ set magnification 0
+ }
+ if {$drawing_on != {0} && $drawing_on != {1}} {
+ puts stderr "Invalid graph on/off flag -- setting to 'on'"
+ set drawing_on 1
+ }
+ if {
+ $grid_mode != {b} && $grid_mode != {n} &&
+ $grid_mode != {y} && $grid_mode != {x}
+ } {
+ puts stderr "Invalid graph grid mode -- setting to 'y'"
+ set grid_mode {y}
+ }
+ if {[lsearch -ascii -exact {state latches output} $active_page] == -1} {
+ puts stderr "Invalid graph active page -- setting to 'state'"
+ set active_page {state}
+ }
+
+ set mark_flags [list $mark_flags_s $mark_flags_l $mark_flags_o]
+ set i 0
+ foreach obj [list $graph_state $graph_latches $graph_output] {
+ $obj graph_set_data \
+ $grid_mode \
+ $magnification \
+ $drawing_on \
+ [lindex $mark_flags $i]
+ incr i
+ }
+
+ adjust_mag_buttons
+ adjust_on_off_button
+ adjust_grid_button
+
+ # Unset tempotary variables
+ unset data_list
+
+ Graph_set_active_page $active_page
+ }
+
+ ## Show legend for graph
+ # @return void
+ public method Graph_show_legend {} {
+ # Destroy legend window
+ if {[winfo exists .graph_help_win]} {
+ grab release .graph_help_win
+ destroy .graph_help_win
+ return
+ }
+ set win_x [expr {[winfo pointerx .] + 10}]
+ set win_y [winfo pointery .]
+
+ # Create legend window
+ set win [toplevel .graph_help_win -class {Help} -bg {#EEEEEE}]
+ set frame [frame $win.f -bg {#555555} -bd 0 -padx 1 -pady 1]
+ wm overrideredirect $win 1
+
+ # Click to close
+ bind $win <Button-1> "grab release $win; destroy $win"
+
+ # Create header "-- click to close --"
+ pack [label $frame.lbl_header \
+ -text [mc "-- click to close --"] \
+ -bg {#FFFF55} -font $::smallfont \
+ -fg {#000000} -anchor c \
+ ] -side top -anchor c -fill x
+
+ # Create canvas widget
+ set canvas [canvas $frame.canvas\
+ -bg {#FFFFFF} \
+ -takefocus 0 \
+ -cursor left_ptr \
+ -bd 0 -relief flat \
+ -width 1 -height 1 \
+ ]
+
+ pack $frame -fill both -expand 1
+
+ # Fill in the canvas widget
+ Graph_create_legend $canvas 0
+
+ # Show the canvas
+ pack $canvas -side bottom -fill both -expand 1
+
+ # Show the window
+ wm geometry $win "=260x135+$win_x+$win_y"
+ update
+ catch {
+ grab -global $win
+ }
+ }
+
+ ## Fill in the specified canvas widget to contain the graph legend
+ # @parm Widget canvas - Target canvas widget
+ # @parm Bool nc_instead_of_X - Show "Not connected" instead of "Access to external memory"
+ # @return void
+ public method Graph_create_legend {canvas nc_instead_of_X} {
+ set x 10
+ # {=} Log. 1 forced to log. 0
+ $canvas create line $x 20 [expr {$x + 20}] 20 -fill {#FF00AA} -width 2
+ incr x 20
+ # {} Not connected
+ if {$nc_instead_of_X} {
+ $canvas create line $x 20 $x 15 -fill {#FF00AA} -width 2
+ $canvas create line $x 15 [expr {$x + 20}] 15 -fill {#000000} -width 2
+
+ # {X} Access to external memory
+ } {
+ $canvas create rectangle $x 20 \
+ [expr {$x + 20}] 15 \
+ -fill {#00FF00} -width 0 -outline {#00FF00}
+ $canvas create rectangle $x 15 \
+ [expr {$x + 20}] 10 \
+ -fill {#FF0000} -width 0 -outline {#FF0000}
+ }
+ incr x 20
+ # {-} Undeterminable state
+ $canvas create line $x 15 \
+ [expr {$x + 5}] 11 \
+ [expr {$x + 10}] 15 \
+ [expr {$x + 15}] 17 \
+ [expr {$x + 20}] 14 -fill {#FF8800} -width 2
+ incr x 20
+ # {?} No voltage
+ $canvas create line $x 15 [expr {$x + 20}] 15 -fill {#888888} -width 2
+ incr x 20
+ # {1} Log. 1
+ $canvas create line $x 15 $x 10 [expr {$x + 20}] 10 [expr {$x + 20}] 15 -fill {#FF0000} -width 2
+ incr x 20
+ # {0} Log. 0
+ $canvas create line $x 15 $x 20 [expr {$x + 20}] 20 -fill {#00FF00} -width 2
+ incr x 20
+
+ ## Descriptions
+ # {=} Log. 1 forced to log. 0
+ $canvas create line 20 23 20 100 30 100 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 30 100 -fill {#000000} -anchor w \
+ -text [mc "Log. 1 forced to log. 0"] \
+ -font $::smallfont
+ # {} Not connected
+ if {$nc_instead_of_X} {
+ set tmp_txt [mc "Not connected"]
+ # {X} Access to external memory
+ } {
+ set tmp_txt [mc "Access to external memory"]
+ }
+ $canvas create line 40 23 40 86 50 86 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 50 86 -fill {#000000} -anchor w \
+ -text $tmp_txt -font $::smallfont
+ # {-} Undeterminable state
+ $canvas create line 60 23 60 72 70 72 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 70 72 -fill {#000000} -anchor w \
+ -text [mc "Undeterminable state"] -font $::smallfont
+ # {?} No voltage
+ $canvas create line 80 23 80 58 90 58 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 90 58 -fill {#000000} -anchor w \
+ -text [mc "No voltage"] -font $::smallfont
+ # {1} Log. 1
+ $canvas create line 100 23 100 44 110 44 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 110 44 -fill {#000000} -anchor w \
+ -text [mc "Log. 1"] -font $::smallfont
+ # {0} Log. 0
+ $canvas create line 120 23 120 30 130 30 \
+ -fill {#000000} -arrow first -arrowshape {6 6 2}
+ $canvas create text 130 30 -fill {#000000} -anchor w \
+ -text [mc "Log. 0"] -font $::smallfont
+ }
+
+ ## Create GUI for the specified tab
+ # @parm String page - Tab ID
+ # @return void
+ public method Graph_create_tab {page} {
+ switch -- $page {
+ {state} { ;# Tab: True state
+ if {!$graph_state_created} {
+ set graph_state_created 1
+ $graph_state CreateGraphGUI
+ }
+ }
+ {latches} { ;# Tab: Port Latches
+ if {!$graph_latches_created} {
+ set graph_latches_created 1
+ $graph_latches CreateGraphGUI
+ }
+ }
+ {output} { ;# Tab: True Output
+ if {!$graph_output_created} {
+ set graph_output_created 1
+ $graph_output CreateGraphGUI
+ }
+ }
+ }
+ }
+
+ ## Set current active page
+ # @parm String page - Tab ID
+ # @return void
+ public method Graph_set_active_page {page} {
+ set active_page $page
+ Graph_create_tab $page
+ $pages_manager raise $page
+
+ # Adjust buttons on the top
+ foreach w [list $state_but $latches_but $output_but] {
+ $w configure -style Flat.TButton
+ }
+ switch -- $page {
+ {state} { ;# Tab: True state
+ $state_but configure -style Graph_ActiveTab.TButton
+ }
+ {latches} { ;# Tab: Port Latches
+ $latches_but configure -style Graph_ActiveTab.TButton
+ }
+ {output} { ;# Tab: True Output
+ $output_but configure -style Graph_ActiveTab.TButton
+ }
+ }
+ }
+
+ ## Draw interrupt line
+ # @parm String = {} - If "nohistory" the history of interrupt lines will not be modified
+ # @return void
+ public method graph_draw_interrupt_line args {
+ if {!$gui_initialized} {CreateGraphGUI}
+ create_all_graph_widgets
+
+ $graph_state graph_draw_interrupt_line $args
+ $graph_latches graph_draw_interrupt_line $args
+ $graph_output graph_draw_interrupt_line $args
+ }
+
+ ## Draw new port states in the graph
+ # @parm String target - Target Graph, one of {S L O}
+ # @parm List values - Values to display ...
+ # @return void
+ public method graph_new_output_state {target values} {
+ if {!$gui_initialized} {CreateGraphGUI}
+ create_all_graph_widgets
+
+ switch -- $target {
+ {S} { ;# Tab: True state
+ $graph_state graph_new_output_state $values
+ }
+ {L} { ;# Tab: Port Latches
+ $graph_latches graph_new_output_state $values
+ }
+ {O} { ;# Tab: True Output
+ $graph_output graph_new_output_state $values
+ }
+ }
+ }
+
+ ## Adjust magnification buttons to the current magnification level
+ # @return void
+ private method adjust_mag_buttons {} {
+ # The lowest possible magnification level
+ if {!$magnification} {
+ $zoom_in_button configure -state normal
+ $zoom_out_button configure -state disabled
+ # The highest possible magnification level
+ } elseif {$magnification == 3} {
+ $zoom_in_button configure -state disabled
+ $zoom_out_button configure -state normal
+ # Something in the middle
+ } else {
+ $zoom_in_button configure -state normal
+ $zoom_out_button configure -state normal
+ }
+ }
+
+ ## Switch between ON and OFF
+ # @return void
+ public method graph_change_status_on {} {
+ set drawing_on [expr {!$drawing_on}]
+ graph_commit_state_on_off
+ }
+
+ ## Commit new ON/OFF state
+ # @return void
+ public method graph_commit_state_on_off {} {
+ create_all_graph_widgets
+
+ $graph_state commit_state_on_off $drawing_on
+ $graph_latches commit_state_on_off $drawing_on
+ $graph_output commit_state_on_off $drawing_on
+
+ adjust_mag_buttons
+ adjust_on_off_button
+ }
+
+ ## Adjust apparence of all "ON/OFF" buttons in the PALE system
+ # @return void
+ private method adjust_on_off_button {} {
+ $this pale_on_off $drawing_on
+
+ # ON
+ if {$drawing_on} {
+ $start_stop_button configure -style GreenBg.TButton -text "ON"
+ $grid_button configure -state normal
+ $clear_marks_button configure -state normal
+
+ # OFF
+ } else {
+ $start_stop_button configure -style RedBg.TButton -text "OFF"
+
+ $zoom_in_button configure -state disabled
+ $zoom_out_button configure -state disabled
+ $grid_button configure -state disabled
+ $clear_marks_button configure -state disabled
+ }
+ }
+
+ ## Adjust apparence of all "Grid" buttons in the PALE system
+ # @return void
+ private method adjust_grid_button {} {
+ # Adjust button in button bar and canvas popup menu
+ switch -- $grid_mode {
+ {b} {set image {grid0}}
+ {n} {set image {grid1}}
+ {y} {set image {grid2}}
+ {x} {set image {grid3}}
+ }
+ $grid_button configure -image ::ICONS::16::$image
+
+ }
+
+ ## Zoom in/out
+ # @parm Int by - Steps
+ # @return void
+ public method graph_switch_grid_mode {by} {
+ create_all_graph_widgets
+
+ # Determinate number of the current grid mode
+ set i [lsearch {b n y x} $grid_mode]
+ # Increment by '$by'
+ incr i $by
+ while {$i > 3} {
+ incr i -4
+ }
+ while {$i < 0} {
+ incr i 4
+ }
+ # Set new grid mode
+ set grid_mode [lindex {b n y x} $i]
+ adjust_grid_button
+
+ $graph_state graph_switch_grid_mode $grid_mode
+ $graph_latches graph_switch_grid_mode $grid_mode
+ $graph_output graph_switch_grid_mode $grid_mode
+ }
+
+ ## Zoom out
+ # @return void
+ public method graph_zoom_out {} {
+ if {!$magnification} {return}
+ incr magnification -1
+ commit_magnification
+ }
+
+ ## Zoom in
+ # @return void
+ public method graph_zoom_in {} {
+ if {$magnification == 3} {return}
+ incr magnification
+ commit_magnification
+ }
+
+ ## Commit new magnification level
+ # @return void
+ private method commit_magnification {} {
+ create_all_graph_widgets
+
+ $graph_state commit_magnification $magnification
+ $graph_latches commit_magnification $magnification
+ $graph_output commit_magnification $magnification
+
+ # Adjust states of magnification buttons
+ adjust_mag_buttons
+ }
+
+ ## Clear graph marks in the the current graph
+ # @return void
+ public method graph_clear_marks {} {
+ switch -- $active_page {
+ {state} { ;# Tab: True state
+ $graph_state graph_clear_marks
+ }
+ {latches} { ;# Tab: Port Latches
+ $graph_latches graph_clear_marks
+ }
+ {output} { ;# Tab: True Output
+ $graph_output graph_clear_marks
+ }
+ }
+ }
+
+ ## Clear all graphs
+ # @return void
+ public method clear_graph {} {
+ create_all_graph_widgets
+
+ $graph_state clear_graph
+ $graph_latches clear_graph
+ $graph_output clear_graph
+ }
+
+ ## Create GUI of all graphs
+ # @return void
+ private method create_all_graph_widgets {} {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ if {!$graph_state_created} {
+ $graph_state CreateGraphGUI
+ }
+ if {!$graph_latches_created} {
+ $graph_latches CreateGraphGUI
+ }
+ if {!$graph_output_created} {
+ $graph_output CreateGraphGUI
+ }
+ }
+
+ ## Get graph configuration values -- for project save
+ # @return List - Configuration list
+ public method graph_get_config {} {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ create_all_graph_widgets
+
+ return [list $grid_mode $magnification $drawing_on \
+ [$graph_state graph_get_marks] \
+ [$graph_latches graph_get_marks] \
+ [$graph_output graph_get_marks] \
+ $active_page \
+ ]
+ }
+
+ ## Try to restore graph state before the given number of program steps
+ # @parm Int bits - Number of steps to take back
+ # @return void
+ public method graph_stepback {bits} {
+ if {!$gui_initialized} {CreateGraphGUI}
+ if {!$drawing_on} {return}
+
+ create_all_graph_widgets
+
+ $graph_state graph_stepback $bits
+ $graph_latches graph_stepback $bits
+ $graph_output graph_stepback $bits
+ }
+
+ ## React to MCU change
+ # @return void
+ public method graph_change_mcu {} {
+ if {$graph_state_created} {
+ $graph_state change_mcu
+ }
+ if {$graph_latches_created} {
+ $graph_latches change_mcu
+ }
+ if {$graph_output_created} {
+ $graph_output change_mcu
+ }
+ }
+}
diff --git a/lib/bottompanel/graph_wdg.tcl b/lib/bottompanel/graph_wdg.tcl
new file mode 100755
index 0000000..bcb2d62
--- /dev/null
+++ b/lib/bottompanel/graph_wdg.tcl
@@ -0,0 +1,1115 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2008 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Graph widget for showing port states
+# --------------------------------------------------------------------------
+
+class GraphWidget {
+ ## COMMON
+ common step_y 13 ;# Int: Vertical distance between graph rows
+ common half_edge 5 ;# Int: Half length of bit edge
+ common full_edge 10 ;# Int: Full length of bit edge
+
+ # Big font (vertical header)
+ common big_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 -weight bold \
+ ]
+ # Small font (horizontal header)
+ common small_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 -weight bold \
+ ]
+ # Font for booleans values for each port
+ common bool_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 -weight bold \
+ ]
+ # Definition of graph popup menu
+ common GRAPHMENU {
+ {command {ON/OFF} {} 0 "graph_change_status_on"
+ {} "Enable/Disable graph"}
+ {separator}
+ {command {Change grid} {} 1 "graph_switch_grid_mode 1"
+ {} "Change grid morfology"}
+ {separator}
+ {command {Zoom in} {} 1 "graph_zoom_in"
+ {viewmag_in} "Change bit length on X axis to a lower value"}
+ {command {Zoom out} {} 1 "graph_zoom_out"
+ {viewmag_out} "Change bit length on X axis to a higher value"}
+ {separator}
+ {command {Remove marks} {} 1 "graph_clear_marks"
+ {editdelete} "Clear user marks"}
+ }
+
+ # Variables related to object initialization
+ private variable gui_initialized 0 ;# Bool: GUI created
+ private variable _parent ;# Parent widget
+ private variable parent ;# Innert parent widget
+
+ private variable canvasWidget ;# ID of the canvas widget
+ private variable grid_mode {b} ;# Current grid mode (one of {b n x y})
+ private variable drawing_on 1 ;# Bool: Graph enabled
+ private variable magnification 0 ;# Magnification level (0..3)
+ private variable graph_elements ;# Array: IDs of graph elements (green and red lines)
+ private variable intr_lines {} ;# List of IDs of interrupt lines
+ private variable marks {} ;# List of IDs mark rectangulars
+ private variable mark_flags {} ;# List of Boolean mark flags
+ private variable state_history {} ;# History of X bits (for changing magnification level and stepback)
+ private variable intr_history {} ;# History of X interrupt flags
+ private variable previous_state ;# Array: previous state of each bit
+ private variable menu {} ;# ID of canvas popup menu
+ private variable step_x ;# Number of pixels required for draw one bit
+ private variable scrollable_frame ;# Widget: Scrollable area (parent for all other widgets)
+ private variable horizontal_scrollbar ;# Widget: Horizontal scrollbar for scrollable area
+ private variable number_of_ports ;# Int: Number of MCU's ports (see engine proc. get_ports_info)
+ private variable port_numbers ;# List: Numbers of implemented ports (e.g. {0 3})
+ private variable port_length_in_px ;# Length of one port segment in PX
+ private variable port_graph_length ;# Same as port_length_in_px but only visible area
+ private variable history_max_length ;# Maximum history depth
+
+ private variable Super ;# Object: Super
+
+
+ ## Prepare object for creating its GUI
+ # @parm Widget Parent - GUI parent widget
+ # @parm List _data_list - Configuration data list
+ # @return void
+ constructor {Parent super} {
+ set _parent $Parent
+ set Super $super
+ set gui_initialized 0
+ }
+
+ ## Object destructor
+ destructor {
+ if {$gui_initialized} {
+ menu_Sbar_remove $menu
+ }
+ }
+
+ ## React to MCU change
+ # @return void
+ public method change_mcu {} {
+ if {!$gui_initialized} {return}
+
+ foreach wdg [winfo children $_parent] {
+ destroy $wdg
+ }
+ set gui_initialized 0
+ CreateGraphGUI
+ }
+
+ ## Initialize graph
+ # @return void
+ public method CreateGraphGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Determinate number of ports and port indexes
+ set number_of_ports [$Super get_ports_info]
+ set port_numbers [lindex $number_of_ports 1]
+ set number_of_ports [lindex $number_of_ports 0]
+
+ set port_length_in_px [expr {840 / $number_of_ports}]
+ set port_graph_length [expr {$port_length_in_px - 15}]
+ set history_max_length [expr {$port_graph_length / 5}]
+
+ # Create scrollable area
+ set scrollable_frame [ScrollableFrame $_parent.scrollable_frame \
+ -xscrollcommand "$this graph_gui_scroll_set" \
+ ]
+ set horizontal_scrollbar [ttk::scrollbar $_parent.horizontal_scrollbar \
+ -orient horizontal -command "$scrollable_frame xview" \
+ ]
+ pack $scrollable_frame -fill both -side bottom -expand 1
+ set parent [$scrollable_frame getframe]
+
+ # Create canvas widget
+ set canvasWidget [canvas $parent.canvas \
+ -height 120 -width 860 -bd 0 \
+ -highlightthickness 0 \
+ ]
+
+ # Create graph headers
+ for {set i 0; set y 17} {$i < 8} {incr i; incr y $step_y} {
+ $canvasWidget create text 10 $y -text $i -font $small_font -anchor n -fill {#0000FF} -tags background
+ }
+ for {set i 0} {$i < $number_of_ports} {incr i} {
+ set x [expr {$i * $port_length_in_px + $port_length_in_px / 2 + 20}]
+ $canvasWidget create text $x 7 \
+ -text "P[lindex $port_numbers $i]" \
+ -font $big_font -fill {#0000FF} -tags background
+ }
+ # Create separators
+ $canvasWidget create line 20 0 20 120 -fill {#000000} -tags background
+ $canvasWidget create line 0 15 860 15 -fill {#000000} -tags background
+ for {set i 1} {$i <= $number_of_ports} {incr i} {
+ set x [expr {$i * $port_length_in_px + 20}]
+ $canvasWidget create line $x 0 $x 120 -fill {#000000} -tags background
+ incr x -$step_y
+ $canvasWidget create line $x 0 $x 120 -fill {#888888} -tags background
+ }
+
+ # Initialize array of graph elements and previous states
+ for {set i 0} {$i < 40} {incr i} {
+ set graph_elements($i) {}
+ set previous_state($i) 1
+ }
+
+ # Create canvas popup menu
+ set menu $canvasWidget.menu
+ menuFactory $GRAPHMENU $menu 0 "$Super " 0 {}
+
+
+ # Set event bindings for the canvas widget
+ bind $canvasWidget <Motion> "$this graph_highlight %x %y"
+ bind $canvasWidget <Leave> "$this graph_unhighlight"
+ bind $canvasWidget <ButtonRelease-3> "$this graph_popup_menu %X %Y"
+ bind $canvasWidget <Button-1> "$this graph_place_mark %x %y"
+
+ # Pack the canvas widget
+ set marks [string repeat {{} } [expr {$history_max_length + 1}]]
+ pack $canvasWidget -fill none -expand 0 -anchor nw -side left
+
+ # Commit magnification level
+ commit_magnification $magnification
+
+ # Commit ON/OFF state
+ commit_state_on_off $drawing_on
+
+ # Create graph grid
+ graph_switch_grid_mode $grid_mode
+ }
+
+ ## Draw interrupt line
+ # @parm String = {} - If "nohistory" the history of interrupt lines will not be modified
+ # @return void
+ public method graph_draw_interrupt_line args {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ # Check if graph is enabled
+ if {!$drawing_on} {return}
+
+ # Adjust history
+ if {$args != {nohistory}} {
+ if {[llength $intr_history]} {
+ lset intr_history end 1
+ } {
+ lappend intr_history 1
+ }
+ }
+
+ # Create interrupt lines
+ set lines {}
+ for {set col 0} {$col < $number_of_ports} {incr col} {
+ set x [expr {$col * $port_length_in_px + ([llength $graph_elements(0)] * $step_x) + 20}]
+ lappend lines [$canvasWidget create line $x 16 $x 120 \
+ -fill {#DDAA00} -tags graph -width 2 -dash ,]
+ }
+
+ # Adjust list of canvas elements related to this line
+ if {$args != {nohistory}} {
+ if {[llength $intr_lines]} {
+ lset intr_lines end $lines
+ } {
+ lappend intr_lines $lines
+ }
+ }
+ }
+
+ ## Draw new port states in the graph
+ # A) With history enabled:
+ # @parm String - Hexadecimal value of P0
+ # @parm String - Hexadecimal value of P1
+ # @parm String - Hexadecimal value of P2
+ # @parm String - Hexadecimal value of P3
+ # @parm String - Hexadecimal value of P4
+ # B) With disabled:
+ # @parm List - {# {P0_hex P1_hex P2_hex P3_hex P4_hex}}
+ # @return void
+ public method graph_new_output_state args {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ # Check if graph is enabled
+ if {!$drawing_on} {return}
+
+ # Determinate number of bits per block and the current position
+ set treshold [expr {$port_graph_length / $step_x}]
+ set position [llength $graph_elements(0)]
+
+ # If graph is full -> remove last elements and move the graph
+ if {$position == $treshold} {
+ # Remove elemets
+ for {set i 0} {$i < ($number_of_ports * 8)} {incr i} {
+ foreach elm [lindex $graph_elements($i) 0] {
+ $canvasWidget delete $elm
+ }
+ set graph_elements($i) [lreplace $graph_elements($i) 0 0]
+ }
+ foreach elm [lindex $intr_lines 0] {
+ $canvasWidget delete $elm
+ }
+ set intr_lines [lreplace $intr_lines 0 0]
+ # Adjust position index
+ incr position -1
+ # Move graph
+ $canvasWidget move graph -$step_x 0
+ }
+
+ # Adjust history (cannot be longer than 38)
+ if {[llength $intr_history] > $history_max_length} {
+ set intr_history [lreplace $intr_history 0 0]
+ set state_history [lreplace $state_history 0 0]
+ }
+
+ # Adjust history
+ set args [join $args {}]
+ if {[lindex $args 0] != {#}} {
+ lappend state_history [list {#} $args]
+ lappend intr_history 0
+ } {
+ set args [lindex $args 1]
+ }
+ lappend intr_lines {}
+
+ # Adjust arguments
+ set ports {}
+ foreach idx $port_numbers {
+ lappend ports [lindex $args $idx]
+ }
+
+ # Create new elements
+ set p_idx 0 ;# Port index (not port number)
+ set idx 0 ;# Bit index
+ $canvasWidget delete booleans ;# Clear boolean values
+ foreach num_x $ports {
+ set num [list 0 0 0 0 0 0 0 0]
+ for {set i 0; set j 7} {$i < 8} {incr i; incr j -1} {
+ lset num $j [lindex $num_x $i]
+ }
+
+ # Draw bits
+ foreach bit $num {
+ draw_bit $idx $position $bit
+ incr idx
+ }
+ # Draw booleans
+ write_boolean $p_idx $num
+ incr p_idx
+ }
+ }
+
+ ## Write boolean values for the given port
+ # @parm Int port_idx - Port number
+ # @parm Int val - Port value
+ # @return void
+ private method write_boolean {port_idx val} {
+ set x [expr {($port_idx + 1) * $port_length_in_px + 13}]
+
+ for {set i 0; set y 17} {$i < 8} {incr i; incr y $step_y} {
+ switch -- [lindex $val $i] {
+ {1} {
+ set txt {H}
+ set clr {#FF0000}
+ }
+ {0} {
+ set txt {L}
+ set clr {#00FF00}
+ }
+ {|} {
+ set txt {-}
+ set clr {#FF8800}
+ }
+ {?} {
+ set txt {-}
+ set clr {#888888}
+ }
+ {X} {
+ set txt {-}
+ set clr {#8800FF}
+ }
+ {-} {
+ set txt {?}
+ set clr {#AAAA00}
+ }
+ {=} {
+ set txt {L}
+ set clr {#FF00AA}
+ }
+ }
+
+ $canvasWidget create text $x $y \
+ -text $txt \
+ -font $bool_font \
+ -anchor n \
+ -fill $clr \
+ -tags booleans
+ }
+ }
+
+ ## Draw one bit to the graph
+ # @parm Int idx - Bit index (0..39)
+ # @parm Int pos - Target position
+ # @parm Char bool - Bit value
+ # @return void
+ private method draw_bit {idx pos bool} {
+ # Local variables
+ set prev $previous_state($idx) ;# Previous state of the bit
+ set offset_y [expr {($idx % 8) * $step_y + 18}] ;# Y offset
+ set lines {} ;# List of line IDs
+ # X offset
+ set offset_x [expr {
+ ($idx / 8) * $port_length_in_px + ($pos * $step_x) + 20
+ }]
+
+ # Determinate length of line elements acording to the current magnification level
+ switch -- $magnification {
+ {0} {
+ set line_len 3
+ set enge_diff 0
+ set enge_inc0 0
+ set enge_inc1 0
+ }
+ {1} {
+ set line_len 4
+ set enge_diff 1
+ set enge_inc0 1
+ set enge_inc1 1
+ }
+ {2} {
+ set line_len 6
+ set enge_diff 1
+ set enge_inc0 2
+ set enge_inc1 1
+ }
+ {3} {
+ set line_len 8
+ set enge_diff 2
+ set enge_inc0 2
+ set enge_inc1 2
+ }
+ }
+
+ # Logical one forced to zero (e.g. by NPN transistor)
+ if {$bool == {=}} {
+ set bool 0
+ set zero_color {#FF00AA}
+ } {
+ set zero_color {#FF0000}
+ }
+
+ ## Draw graph line(s)
+
+ # High frequency pulse
+ if {$bool == {|}} {
+ # Draw transition from the previous value
+ switch -- $prev {
+ {0} { ;# From logical 0
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+ }
+ {1} { ;# From logical 1
+ }
+ {?} { ;# From no voltage
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+ }
+ {-} { ;# From undeterminable state
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+ }
+ }
+
+ if {$magnification == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + 1}] $offset_y \
+ [expr {$offset_x + 1}] [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+
+ lappend lines [$canvasWidget create line \
+ [expr {$offset_x + 1}] [expr {$offset_y + $half_edge}] \
+ [expr {$offset_x + 1}] [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + 3}] [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + 3}] [expr {$offset_y + $half_edge}] \
+ -fill {#00FF00} -tags graph]
+
+ lappend lines [$canvasWidget create line \
+ [expr {$offset_x + 4}] [expr {$offset_y + $half_edge}] \
+ [expr {$offset_x + 4}] [expr {$offset_y}] \
+ -fill $zero_color -tags graph]
+ } else {
+ switch -- $magnification {
+ {1} {
+ set line_len 3
+ set enge_diff 0
+ set enge_inc0 0
+ set enge_inc1 0
+ }
+ {2} {
+ set line_len 4
+ set enge_diff 1
+ set enge_inc0 1
+ set enge_inc1 1
+ }
+ {3} {
+ set line_len $half_edge
+ set enge_diff 1
+ set enge_inc0 2
+ set enge_inc1 1
+ }
+ }
+
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $line_len}] $offset_y\
+ -fill $zero_color -tags graph]
+ incr offset_x $line_len
+ lappend lines [$canvasWidget create line\
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] \
+ [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph \
+ ]
+ incr offset_x $enge_inc0
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line\
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] \
+ [expr {$offset_y + 5}] \
+ -fill {#00FF00} -tags graph \
+ ]
+ incr offset_x $enge_inc1
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $line_len + 1}] $offset_y \
+ -fill {#00FF00} -tags graph]
+
+ incr offset_x $line_len
+ incr offset_x
+ lappend lines [$canvasWidget create line\
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] \
+ [expr {$offset_y - $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ incr offset_x $enge_inc0
+ incr offset_y -$half_edge
+ lappend lines [$canvasWidget create line\
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] \
+ [expr {$offset_y - $half_edge}] \
+ -fill $zero_color -tags graph]
+ incr offset_x $enge_inc1
+ incr offset_y -$half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $line_len}] $offset_y \
+ -fill $zero_color -tags graph]
+ }
+
+ # Access to external memory
+ } elseif {$bool == {X}} {
+ lappend lines [$canvasWidget create rectangle \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -width 0 -tags graph]
+ lappend lines [$canvasWidget create rectangle \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \
+ -fill {#00FF00} -width 0 -tags graph]
+
+
+ set bool $prev
+
+ # Underminable state
+ } elseif {$bool == {-}} {
+ # Draw transition from the previous value
+ switch -- $prev {
+ {0} { ;# From logical zero
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ }
+ {1} { ;# From logical one
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ }
+ {|} { ;# From high frequency pulse
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ }
+ }
+
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $line_len}] [expr {$offset_y + int(rand() * $half_edge)}] \
+ [expr {$offset_x + $line_len + $enge_inc0}] $offset_y \
+ [expr {$offset_x + $line_len + $enge_inc0 + $enge_inc1}] [expr {$offset_y - int(rand() * $half_edge)}] \
+ [expr {$offset_x + 2*$line_len + $enge_inc0 + $enge_inc1}] $offset_y \
+ -fill {#FF8800} -tags graph]
+
+ # "Undeterminable state" -> "Zero"
+ } elseif {$prev == {-} && $bool == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \
+ -fill {#00FF00} -tags graph]
+
+ # "Undeterminable state" -> "One"
+ } elseif {$prev == {-} && $bool == 1} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+
+ # No voltage
+ } elseif {$bool == {?}} {
+ # Draw transition from the previous value
+ switch -- $prev {
+ {0} { ;# From logical zero
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ }
+ {1} { ;# From logical one
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ }
+ {|} { ;# From high frequency pulse
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ }
+ }
+
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] $offset_y \
+ -fill {#888888} -tags graph -width 2]
+
+ # "No voltage" -> "Zero"
+ } elseif {$prev == {?} && $bool == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \
+ -fill {#00FF00} -tags graph]
+
+ # "No voltage" -> "One"
+ } elseif {$prev == {?} && $bool == 1} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + 0}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + 0}] \
+ -fill $zero_color -tags graph]
+
+ # "High freq. pulse" -> "Zero"
+ } elseif {$prev == {|} && $bool == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + 0}] \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ lappend lines [$canvasWidget create line \
+ $offset_x [expr {$offset_y + $half_edge}] \
+ $offset_x [expr {$offset_y + $full_edge}] \
+ [expr {$offset_x + $step_x}] [expr {$offset_y + $full_edge}] \
+ -fill {#00FF00} -tags graph]
+
+ # "High freq. pulse" -> "One"
+ } elseif {$prev == {|} && $bool == 1} {
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] $offset_y \
+ -fill $zero_color -tags graph]
+
+ # 1 -> 1
+ } elseif {$prev == 1 && $bool == 1} {
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] $offset_y \
+ -fill $zero_color -tags graph]
+
+ # 1 -> 0
+ } elseif {$prev == 1 && $bool == 0} {
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \
+ -fill $zero_color -tags graph]
+ incr offset_x $line_len
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] [expr {$offset_y + $half_edge}] \
+ -fill $zero_color -tags graph]
+ incr offset_x $enge_inc0
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] [expr {$offset_y + 5}] \
+ -fill {#00FF00} -tags graph]
+ incr offset_x $enge_inc1
+ incr offset_y $half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \
+ -fill {#00FF00} -tags graph]
+
+ # 0 -> 1
+ } elseif {$prev == 0 && $bool == 1} {
+ incr offset_y $full_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \
+ -fill {#00FF00} -tags graph]
+ incr offset_x $line_len
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] [expr {$offset_y - $half_edge}] \
+ -fill {#00FF00} -tags graph]
+ incr offset_x $enge_inc0
+ incr offset_y -$half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $enge_diff}] [expr {$offset_y - $half_edge}] \
+ -fill $zero_color -tags graph]
+ incr offset_x $enge_inc1
+ incr offset_y -$half_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y [expr {$offset_x + $line_len}] $offset_y \
+ -fill $zero_color -tags graph]
+
+ # 0 -> 0
+ } else {
+ incr offset_y $full_edge
+ lappend lines [$canvasWidget create line \
+ $offset_x $offset_y \
+ [expr {$offset_x + $step_x}] $offset_y \
+ -fill {#00FF00} -tags graph]
+ }
+
+ # Adjust array of graph elements and previous states
+ lappend graph_elements($idx) $lines
+ set previous_state($idx) $bool
+ }
+
+ ## Iterate over avaliable grid modes
+ # @parm Int by - Iterate by
+ # @return void
+ public method graph_switch_grid_mode {_grid_mode} {
+ set grid_mode $_grid_mode
+
+ # Adjust button in button bar and canvas popup menu
+ switch -- $grid_mode {
+ {b} {set image {grid0}}
+ {n} {set image {grid1}}
+ {y} {set image {grid2}}
+ {x} {set image {grid3}}
+ }
+ $menu entryconfigure [::mc "Change grid"] -image ::ICONS::16::$image
+ # Redraw grid
+ adjust_grid
+ }
+
+ ## Adjust grid morfology to the current grid mode
+ # @return void
+ private method adjust_grid {} {
+ # Remove the current grid
+ catch {
+ $canvasWidget delete grid
+ }
+ # Create new grid
+ switch -- $grid_mode {
+ {b} {
+ draw_y_grid
+ draw_x_grid
+ }
+ {n} {}
+ {y} {draw_y_grid}
+ {x} {draw_x_grid}
+ }
+ }
+
+ ## Draw vertical grid lines
+ # @return void
+ private method draw_y_grid {} {
+ # Iterate over graph blocks
+ for {set i 0} {$i < $number_of_ports} {incr i} {
+ # Determinate horizontal boundaries
+ set xoff [expr {$i * $port_length_in_px + 20 + $step_x}]
+ set xend [expr {($i + 1) * $port_length_in_px + 5}]
+ # Draw vertical lines
+ for {set x $xoff} {$x < $xend} {incr x $step_x} {
+ $canvasWidget create line $x 16 $x 120 -fill {#AAAAAA} -tags grid -dash .
+ }
+ }
+ }
+
+ ## Draw horizontal grid lines
+ # @return void
+ private method draw_x_grid {} {
+ for {set y 30} {$y < 120} {incr y $step_y} {
+ $canvasWidget create line 0 $y 860 $y -fill {#888888} -tags grid
+ }
+ }
+
+ ## Set graph configuration variables
+ # @parm Char _grid_mode - Grid morfology (one of {'n' 'x' 'y' 'b'})
+ # @parm Int _magnification - Magnification mode (one of {0 1 2 3})
+ # @parm Bool _drawing_on - Widget enabled
+ # @parm List _mark_flags - List of mark flags (e.g {0 0 0 1 1 0})
+ # @return void
+ public method graph_set_data {_grid_mode _magnification _drawing_on _mark_flags} {
+ set grid_mode $_grid_mode
+ set magnification $_magnification
+ set drawing_on $_drawing_on
+ set mark_flags $_mark_flags
+ }
+
+ ## Get mark flags
+ # @return String - String of boolean flags
+ public method graph_get_marks {} {
+ return [join $mark_flags {}]
+ }
+
+ ## Adjust graph to the current magnification level
+ # @return void
+ public method commit_magnification {_magnification} {
+ set magnification $_magnification
+
+ # Determinate one bit X axis step
+ set step_x [expr {$magnification * 5 + 5}]
+
+ clear_graph keephistory ;# Clear graph
+ adjust_grid ;# Adjust graph grid
+ # Remove user marks
+ catch {
+ $canvasWidget delete mark
+ }
+
+ # Restore graph content from the history (voltage levels and interrupt lines)
+ set length [expr {$port_graph_length / $step_x - 1}]
+ foreach state [lrange $state_history end-$length end] \
+ intr [lrange $intr_history end-$length end] \
+ {
+ graph_new_output_state $state
+ if {$intr == 1} {
+ graph_draw_interrupt_line nohistory
+ }
+ }
+
+ # Restore user marks
+ set x_off [expr {21 - $step_x}]
+ set i -1
+ foreach mark [lrange $mark_flags 0 $length] {
+ incr i
+ incr x_off $step_x
+ if {!$mark} {continue}
+
+ set x $x_off
+ set lines [list]
+ for {set j 0} {$j < $number_of_ports} {incr j} {
+ lappend lines [$canvasWidget create rectangle \
+ $x 16 [expr {$x + $step_x - 1}] 120 \
+ -fill {#AA88FF} -tags mark -width 0]
+ incr x $port_length_in_px
+ }
+ lset marks $i $lines
+ }
+ }
+
+ ## Remove all graph elements (voltage levels)
+ # @parm String - If "keephistory" then do not clear history
+ # @return void
+ public method clear_graph args {
+ if {!$gui_initialized} {CreateGraphGUI}
+
+ catch {
+ $canvasWidget delete graph
+ }
+ catch {
+ $canvasWidget delete highlight
+ }
+ catch {
+ $canvasWidget delete booleans
+ }
+ for {set i 0} {$i < 40} {incr i} {
+ set graph_elements($i) {}
+ }
+ set intr_lines {}
+
+ if {$args != {keephistory}} {
+ set state_history {}
+ set intr_history {}
+ for {set i 0} {$i < 40} {incr i} {
+ set previous_state($i) 1
+ }
+ }
+ }
+
+ ## Turn graph ON/OFF
+ # @return void
+ public method graph_change_status_on {} {
+ $Super graph_commit_state_on_off $drawing_on
+ }
+
+ ## Adjust object to the current value of flag 'drawing_on'
+ # @return void
+ public method commit_state_on_off {_drawing_on} {
+ if {!$gui_initialized} {CreateGraphGUI}
+ set drawing_on $_drawing_on
+
+ # Enable widgets
+ if {$drawing_on} {
+ $menu entryconfigure [::mc "Remove marks"] -state normal
+ $menu entryconfigure [::mc "Change grid"] -state normal
+ $canvasWidget configure -state normal
+
+ # Disable widgets, clear graph and clear history
+ } else {
+ $menu entryconfigure [::mc "Remove marks"] -state disabled
+ $menu entryconfigure [::mc "Change grid"] -state disabled
+ $menu entryconfigure [::mc "Zoom in"] -state disabled
+ $menu entryconfigure [::mc "Zoom out"] -state disabled
+ $canvasWidget configure -state disabled
+ clear_graph
+ }
+ }
+
+ ## Highlight graph segment
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method graph_highlight {x y} {
+ # Remove previous highlight
+ graph_unhighlight
+
+ # Check for allowed coordinate range
+ if {$y < 17 || $x < 21} {return}
+ set x [expr {($x - 20) % $port_length_in_px}]
+ if {$x >= $port_graph_length - ($port_graph_length % $step_x)} {return}
+
+ incr x [expr {-($x % $step_x)}]
+ incr x 21
+
+ # Draw highlight rectangulars
+ for {set i 0} {$i < $number_of_ports} {incr i} {
+ $canvasWidget create rectangle \
+ $x 16 [expr {$x + $step_x - 1}] 120 \
+ -fill {#88FFFF} -tags highlight -width 0
+ incr x $port_length_in_px
+ }
+
+ set y [expr {$y - (($y - 17) % $step_y)}]
+
+ $canvasWidget create rectangle \
+ 0 $y 860 [expr {$y + $step_y}] \
+ -fill {#88FFFF} -tags highlight -width 0
+
+ # Set tag priorities
+ catch {
+ $canvasWidget lower highlight mark
+ }
+ catch {
+ $canvasWidget lower highlight grid
+ }
+ catch {
+ $canvasWidget lower highlight graph
+ }
+ catch {
+ $canvasWidget lower highlight booleans
+ }
+ catch {
+ $canvasWidget lower highlight background
+ }
+ }
+
+ ## Remove highlightion
+ # @return void
+ public method graph_unhighlight {} {
+ catch {
+ $canvasWidget delete highlight
+ }
+ }
+
+ ## Popup canvas menu
+ # @parm Int X - Absolute X coordinate
+ # @parm Int Y - Absolute X coordinate
+ # @return void
+ public method graph_popup_menu {X Y} {
+ tk_popup $menu $X $Y
+ }
+
+ ## Place mark in the graph
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method graph_place_mark {x y} {
+ # Check for allowed coordinate range
+ if {$y < 17 || $x < 21} {return}
+ set x [expr {($x - 20) % $port_length_in_px}]
+ if {$x >= $port_graph_length - ($port_graph_length % $step_x)} {return}
+
+ incr x [expr {-($x % $step_x)}]
+ set idx [expr {$x / $step_x}]
+
+ # Create mark
+ if {[lindex $mark_flags $idx] != 1} {
+ incr x 21
+ set lines {}
+ for {set i 0} {$i < $number_of_ports} {incr i} {
+ lappend lines [$canvasWidget create rectangle \
+ $x 16 [expr {$x + $step_x - 1}] 120 \
+ -fill {#AA88FF} -tags mark -width 0]
+ incr x $port_length_in_px
+ }
+ catch {
+ $canvasWidget raise mark highlight
+ }
+ catch {
+ $canvasWidget lower mark grid
+ }
+ catch {
+ $canvasWidget lower mark graph
+ }
+ lset marks $idx $lines
+ lset mark_flags $idx 1
+
+ # Remove mark
+ } {
+ catch {
+ foreach elm [lindex $marks $idx] {
+ $canvasWidget delete $elm
+ }
+ }
+ lset marks $idx {}
+ lset mark_flags $idx 0
+ }
+ }
+
+ ## Remove all user marks from the graph
+ # @return void
+ public method graph_clear_marks {} {
+ catch {
+ $canvasWidget delete mark
+ }
+ set marks [string repeat {{} } [expr {$history_max_length + 1}]]
+ set mark_flags [string repeat {0 } [expr {$history_max_length + 1}]]
+ }
+
+ ## Adjust scrollbar for scrollable area
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method graph_gui_scroll_set {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $horizontal_scrollbar]} {
+ pack forget $horizontal_scrollbar
+ update
+ }
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $horizontal_scrollbar]} {
+ pack $horizontal_scrollbar -fill x -side top -before $scrollable_frame
+ }
+ $horizontal_scrollbar set $frac0 $frac1
+ update
+ }
+ }
+
+ ## Try to restore graph state before the given number of program steps
+ # @parm Int bits - Number of steps to take back
+ # @return void
+ public method graph_stepback {bits} {
+ if {!$gui_initialized} {CreateGraphGUI}
+ if {!$drawing_on} {return}
+
+ # Remove elemets
+ incr bits -1
+ for {set i 0} {$i < ($number_of_ports * 8)} {incr i} {
+ foreach elm [lrange $graph_elements($i) end-$bits end] {
+ foreach e $elm {
+ $canvasWidget delete $e
+ }
+ }
+ foreach elm [lrange $intr_lines end-$bits end] {
+ foreach e $elm {
+ $canvasWidget delete $e
+ }
+ }
+ set graph_elements($i) [lreplace $graph_elements($i) end-$bits end]
+ }
+ set intr_lines [lreplace $intr_lines end-$bits end]
+
+ # Adjust history
+ set intr_history [lreplace $intr_history end-$bits end]
+ set state_history [lreplace $state_history end-$bits end]
+
+ # Return graph to state before $bits steps
+ set last_state [lindex $state_history {end 1}]
+ if {[llength $last_state]} {
+ set ports {}
+ foreach idx $port_numbers {
+ lappend ports [lindex $last_state $idx]
+ }
+
+ set p_idx 0 ;# Port index (not port number)
+ set idx 0 ;# Bit index
+ $canvasWidget delete booleans ;# Clear boolean values
+ foreach num $ports {
+ foreach bit $num {
+ set previous_state($idx) $bit
+ incr idx
+ }
+ # Draw booleans
+ write_boolean $p_idx $num
+ incr p_idx
+ }
+ } else {
+ clear_graph
+ }
+ }
+}
diff --git a/lib/bottompanel/messages.tcl b/lib/bottompanel/messages.tcl
new file mode 100755
index 0000000..51c96ce
--- /dev/null
+++ b/lib/bottompanel/messages.tcl
@@ -0,0 +1,632 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements messages text for the bottom panel of the project tab
+# --------------------------------------------------------------------------
+
+class Messages {
+
+ ## COMMON
+ common set_shortcuts {} ;# Currently set shortcut bindigs for messages text
+ common shortcuts_cat {messages} ;# Key shortcut categories related to messages text
+ # Normal font for messages text
+ common messages_normal_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12]
+ # Bold font for messages text
+ common messages_bold_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold]
+ # Definition of popup menu for messages text
+ common MESSAGESMENU {
+ {command {Select all} {Ctrl+A} 0 "select_all_messages_text"
+ {} "Select all text in this TextBox"}
+ {command {Copy} {Ctrl+C} 0 "copy_messages_text"
+ {editcopy} "Copy selected text into clipboard"}
+ {command {Clear} {$messages:clear_mess} 1 "clear_messages_text"
+ {editdelete} "Clear all messages"}
+ {separator}
+ {command {Find} {$messages:mess_find} 0 "messages_text_find_dialog"
+ {find} {}}
+ {command {Find next} {$messages:mess_find_n} 5 "messages_text_find_next"
+ {down0} {}}
+ {command {Find previous} {$messages:mess_find_p} 8 "messages_text_find_prev"
+ {up0} {}}
+ }
+
+ private variable main_frame ;# Widget: Main frame
+ private variable messages_text ;# Widget: text widget
+ private variable menu {} ;# Widget: popup menu
+ private variable hyperlink_line_start ;# TextIndex: Active hyperlink line start index
+
+ # Variables related to object initialization
+ private variable parent ;# Widget: parent widget
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+
+ # Variables related to search bar
+ private variable search_frame ;# Widget: Search bar frame
+ private variable last_find_index {} ;# String: Index of last found occurence of the search string
+ private variable search_string ;# String: Search string
+ private variable search_string_length ;# Int: Length of the search string
+ private variable search_entry ;# Widget: Search bar entry box
+ private variable search_find_next ;# Widget: Button "Next"
+ private variable search_find_prev ;# Widget: Button "Prev"
+
+ constructor {} {
+ }
+
+ destructor {
+ # Remove status bar help for popup menus
+ if {$menu != {}} {
+ menu_Sbar_remove $menu
+ }
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - GUI parent widget
+ # @return void
+ public method PrepareMessages {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method MessagesTabRaised {} {
+ focus $messages_text
+ }
+
+ ## Create GUI of messages tab
+ # @return void
+ public method CreateMessagesGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ ## Create GUI of main frame
+ set main_frame [frame $parent.main_frame]
+ # Create messages text and its scrollbar
+ set messages_text [text $main_frame.messages_text \
+ -state disabled -cursor xterm \
+ -yscrollcommand "$main_frame.msg_text_scrl set" \
+ -font $messages_normal_font -wrap word \
+ -tabstyle wordprocessor \
+ ]
+ set messages_text_scrl [ttk::scrollbar $main_frame.msg_text_scrl \
+ -command "$messages_text yview" -orient vertical \
+ ]
+ # Text tags for messages text
+ $messages_text tag configure error \
+ -foreground #FF0000 \
+ -underline 1 \
+ -font $messages_bold_font
+ $messages_text tag configure error_nu \
+ -foreground #FF0000 \
+ -underline 0 \
+ -font $messages_bold_font
+ $messages_text tag configure warning \
+ -foreground #FF8800 \
+ -underline 1 \
+ -font $messages_bold_font
+ $messages_text tag configure warning_nu \
+ -foreground #FF8800 \
+ -underline 0 \
+ -font $messages_bold_font
+ $messages_text tag configure successful \
+ -foreground #00DD00 \
+ -font $messages_bold_font
+ $messages_text tag configure hyper_link_over \
+ -foreground #0055FF -underline 0 \
+ -font $messages_bold_font
+ $messages_text tag raise hyper_link_over
+
+ $messages_text tag bind error <ButtonPress-1> "$this messages_text_anchor %x %y"
+ $messages_text tag bind error <Enter> "$this messages_text_hyperlink_enter %x %y"
+ $messages_text tag bind error <Leave> "$this messages_text_hyperlink_leave"
+ $messages_text tag bind error <Motion> "$this messages_text_hyperlink_motion %x %y"
+ $messages_text tag bind warning <ButtonPress-1> "$this messages_text_anchor %x %y"
+ $messages_text tag bind warning <Enter> "$this messages_text_hyperlink_enter %x %y"
+ $messages_text tag bind warning <Leave> "$this messages_text_hyperlink_leave"
+ $messages_text tag bind warning <Motion> "$this messages_text_hyperlink_motion %x %y"
+ # Popup menu for messages text
+ set menu $messages_text.messages_text_menu
+ messages_text_makePopupMenu
+ # Bindings for messages text
+ bind $messages_text <ButtonPress-1> "focus $messages_text"
+ bind $messages_text <Control-a> "$this select_all_messages_text"
+ bind $messages_text <ButtonRelease-3> "tk_popup $menu %X %Y; break"
+ bind $messages_text <Key-Menu> "$this messages_text_key_menu; break"
+ # Pack parts of main frame
+ pack $messages_text -fill both -expand 1 -side left
+ pack $messages_text_scrl -fill y -side right
+ pack $main_frame -fill both -expand 1
+
+ ## Create GUI components in search bar frame
+ set search_frame [frame $parent.search_frame]
+ # Search entry box
+ set search_entry [ttk::entry $search_frame.entry \
+ -width 30 \
+ -validate all \
+ -validatecommand "$this messages_text_search %P" \
+ ]
+ bind $search_entry <Key-Escape> "$this messages_text_hide_find_dialog"
+ # Button: "Next"
+ set search_find_next [ttk::button $search_frame.find_next_but \
+ -image ::ICONS::16::down0 \
+ -style Flat.TButton \
+ -command "$this messages_text_find_next" \
+ -state disabled \
+ ]
+ DynamicHelp::add $search_frame.find_next_but \
+ -text [mc "Find next occurence of search string"]
+ # Button: "Prev"
+ set search_find_prev [ttk::button $search_frame.find_prev_but \
+ -image ::ICONS::16::up0 \
+ -style Flat.TButton \
+ -command "$this messages_text_find_prev" \
+ -state disabled \
+ ]
+ DynamicHelp::add $search_frame.find_prev_but \
+ -text [mc "Find previous occurence of search string"]
+ # Button: "Close"
+ pack [ttk::button $search_frame.close_but \
+ -image ::ICONS::16::button_cancel \
+ -style Flat.TButton \
+ -command "$this messages_text_hide_find_dialog" \
+ ] -side left
+ DynamicHelp::add $search_frame.close_but \
+ -text [mc "Hide search bar"]
+ # Separator
+ pack [ttk::separator $search_frame.sep \
+ -orient vertical \
+ ] -fill y -padx 5 -side left -pady 2
+ # Label: "Find"
+ pack [label $search_frame.find_lbl \
+ -text [mc "Find:"] \
+ ] -side left
+ # Pack entry and buttons next and prev
+ pack $search_entry -side left
+ pack $search_find_next -side left -padx 5
+ pack $search_find_prev -side left
+ # Checkbutton: "Match case"
+ pack [checkbutton $search_frame.match_case_chb \
+ -text [mc "Match case"] \
+ -variable ::Todo::match_case \
+ -command "$this messages_text_perform_search 1 1.0" \
+ ] -side left -padx 5
+
+
+ messages_text_shortcuts_reevaluate
+ unset parent
+ }
+
+ ## Select all text in messages text
+ # @return void
+ public method select_all_messages_text {} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+ $messages_text tag add sel 1.0 end
+ }
+
+ ## Copy selected text in messages text into clipboard
+ # @return void
+ public method copy_messages_text {} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+ clipboard clear
+ if {[llength [$messages_text tag nextrange sel 1.0]]} {
+ clipboard append [$messages_text get sel.first sel.last]
+ } {
+ clipboard append [$messages_text get 1.0 end]
+ }
+ }
+
+ ## Create bindings for defined key shortcuts for messages text
+ # @return void
+ public method messages_text_shortcuts_reevaluate {} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+
+ # Unset previous configuration
+ foreach key $set_shortcuts {
+ bind $messages_text <$key> {}
+ }
+ set set_shortcuts {}
+
+ # Iterate over shortcuts definition
+ foreach block ${::SHORTCUTS_LIST} {
+ # Determinate category
+ set category [lindex $block 0]
+ if {[lsearch $shortcuts_cat $category] == -1} {continue}
+
+ # Determinate definition list and its length
+ set block [lreplace $block 0 2]
+ set len [llength $block]
+
+ # Iterate over definition list and create bindings
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ # Determinate key sequence
+ set key [lindex $block $i]
+ if {[catch {
+ set key $::SHORTCUTS_DB($category:$key)
+ }]} then {
+ continue
+ }
+ if {$key == {}} {continue}
+
+ # Create and register new binding
+ lappend set_shortcuts $key
+ set cmd [subst [lindex $block [list $j 1]]]
+ append cmd {;break}
+ bind $messages_text <$key> $cmd
+ bind $search_entry <$key> $cmd
+ }
+ }
+ }
+
+ ## Define popup menu for messages text
+ # @return void
+ public method messages_text_makePopupMenu {} {
+ if {!$gui_initialized} {return}
+ if {[winfo exists $menu]} {
+ destroy $menu
+ }
+ menuFactory $MESSAGESMENU $menu 0 "$this " 0 {}
+ $menu entryconfigure [::mc "Find next"] -state disabled
+ $menu entryconfigure [::mc "Find previous"] -state disabled
+ }
+
+ ## Handles event: 'Menu' on messages text -- invoke popup menu
+ # @return void
+ public method messages_text_key_menu {} {
+ $messages_text see insert
+ set bbox [$messages_text bbox [$messages_text index insert]]
+ tk_popup $menu \
+ [expr {[winfo rootx $messages_text] + [lindex $bbox 0] + 10}] \
+ [expr {[winfo rooty $messages_text] + [lindex $bbox 1] + 10}]
+ }
+
+ ## Clear all content of messages text
+ # @return void
+ public method clear_messages_text {} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+
+ $messages_text configure -state normal
+ $messages_text delete 0.0 end
+ $messages_text configure -state disabled
+ }
+
+ ## Goto line (in editor) which is somehow related to some tag in messages text
+ # @parm int x - relative x coordinate in messages text widget
+ # @parm int y - relative y coordinate in messages text widget
+ # @return void
+ public method messages_text_anchor {x y} {
+ # Determinate line number for editor
+ set idx [$messages_text index @$x,$y]
+ set line [$messages_text get "$idx linestart" "$idx lineend"]
+ # Focus on editor and goto that line
+
+ # Message from As31 assembler
+ if {[regexp {^(Error)|(Warning)\, line \d+} $line line]} {
+ if {![regexp {\d+$} $line lineNum]} {
+ set lineNum 0
+ }
+
+ if {$lineNum} {
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto $lineNum
+ }
+
+ # Message from ASEM-51 assembler
+ } elseif {[regexp {^([^\(\)]+\(\d+(\,\d+)?\)\: \w+)} $line line]} {
+ if {![regexp {\(\d+(\,\d+)?\):} $line lineNum]} {
+ set lineNum 0
+ } {
+ set lineNum [string range $lineNum 1 end-2]
+ set lineNum [lindex [split $lineNum {,}] 0]
+ }
+ if {[regexp {^.+\(\d+(\,\d+)?\):} $line target_filename]} {
+ set target_filename [regsub {\(\d+(\,\d+)?\):$} $target_filename {}]
+ set current_filename [lindex [$this editor_procedure {} getFileName {}] 1]
+ if {$target_filename != $current_filename} {
+ if {![$this fucus_specific_editor $target_filename 0]} {
+ return
+ }
+ }
+ }
+ if {$lineNum} {
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto "$lineNum"
+ }
+
+ # GNU error message (from SDCC or ASL)
+ } elseif {[regexp {\:\d+\:} $line linenum]} {
+ if {[regexp {[^\:]+\:} $line target_filename]} {
+ set target_filename [string trim [string range $target_filename 0 {end-1}]]
+ set current_filename [lindex [$this editor_procedure {} getFileName {}] 1]
+ if {$target_filename != $current_filename} {
+ if {![$this fucus_specific_editor $target_filename 0]} {
+ return
+ }
+ }
+ }
+
+ set linenum [string trim $linenum {:}]
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto $linenum
+
+ # Message from MCU8051IDE assembler
+ } elseif {[regexp {at \d+ in [^\:]+\:} $line line]} {
+ if {[regexp { in [^\:]+\:} $line target_filename]} {
+ set target_filename [string trim [string range $target_filename 4 {end-1}] "\""]
+ set current_filename [lindex [$this editor_procedure {} getFileName {}] 1]
+ if {$target_filename != $current_filename} {
+ if {![$this fucus_specific_editor $target_filename 0]} {
+ return
+ }
+ }
+ }
+
+ regexp {\d+} $line lineNum
+ $this editor_procedure {} focus_in {}
+ $this editor_procedure {} goto $lineNum
+ }
+ }
+
+ ## Append text at the end of messages text
+ # @parm String txt - Text to append
+ # @return Bool - True if error occured
+ public method messages_text_append {txt} {
+ if {!$gui_initialized} {CreateMessagesGUI}
+
+ # Enable the messages text widget
+ $messages_text configure -state normal
+
+ set ern 0 ;# The text is some error, but text should not be underlined and linked to certain line
+ set err 0 ;# The text is some error
+ set war 0 ;# The text is some warning which points to specific line in source code
+ set warn 0 ;# The text is some warning
+ set suc 0 ;# The text is success message
+
+ foreach text [split $txt "\n"] {
+ set ern 0
+ set err 0
+ set war 0
+ set warn 0
+ set suc 0
+
+ # Determinate number of the last line in the widget
+ set row [expr {int([$messages_text index end]) - 1}]
+
+ ## Determinate what kind of text will be inserted
+
+ # check for error which points to specific line in source code
+ if {[regexp {^(\|EL\|.*)|^(Compilation error at \d+ in [^\:]+\:)|^(Syntax error at \d+ in [^\:]+\:)|^(Error at\s+\d+ in [^\:]+\:)|^(.+:\d+: .*error.*)|^(.+\(\d+(\,\d+)?\): \w+.*)|^(Error\, line \d+)} $text error]} {
+ set len [string length $error]
+ set err 1
+
+ # check for an error
+ } elseif {[regexp {^(\|EN\|.*)|^(File access error:)|^(FAILED)|^(Compilation FAILED)|^(Pre-processing FAILED !)|^(Error:)|(^@@@@@ .+ @@@@@$)|(^.*returned errorcode.*)|^(Cannot open input file)|^(Cannot open file)|^(Errors in pass1, assembly aborted)|^(Errors in pass2, assembly aborted)} $text error]} {
+ set len [string length $error]
+ set ern 1
+
+ # check for warning which points to specific line in source code
+ } elseif {[regexp {^(\|WL\|.*)|^(Notice at \d+ in [^\:]+\:)|^(Warning at \d+ in [^\:]+\:)|^(.+:\d+: warning.*)|^(Warning\, line \d+)} $text warning]} {
+ set len [string length $warning]
+ set war 1
+
+ # check for a warning
+ } elseif {[regexp {^(\|WN\|.*)|^(.*: Warning:.*)|^(Warning:)} $text warning]} {
+ set len [string length $warning]
+ set warn 1
+
+ # check for success
+ } elseif {[regexp {^(\|SN\|.*)|^((Dec|C)ompilation successful)|(Successful)|(Starting compiler ...)} $text success]} {
+ set len [string length $success]
+ set suc 1
+
+ # check for error which points to specific line in source code
+ } elseif {[regexp {^(\|EL\|.*)|^(.+:\d+: .*)} $text error]} {
+ set len [string length $error]
+ set err 1
+ }
+
+ regsub {^(\|[EWS][LN]\|)} $text {} text
+
+ # Insert specified text
+ $messages_text insert end $text
+ $messages_text insert end "\n"
+
+
+ # Insert appropriate text tags
+ if {$err || $ern || $war || $warn || $suc} {
+ # Insert error tag
+ if {$ern} {
+ set tag {error_nu}
+ # Insert error tag
+ } elseif {$err} {
+ set tag {error}
+ # Insert warning tag
+ } elseif {$warn} {
+ set tag {warning_nu}
+ # Insert warning tag
+ } elseif {$war} {
+ set tag {warning}
+ # Insert success tag
+ } elseif {$suc} {
+ set tag successful
+ }
+ $messages_text tag add $tag $row.0 $row.$len
+ }
+ }
+
+ $messages_text see end
+ $messages_text configure -state disabled
+
+ return [expr {$err || $ern}]
+ }
+
+ ## Hide search bar
+ # @return void
+ public method messages_text_hide_find_dialog {} {
+ if {[winfo ismapped $search_frame]} {
+ pack forget $search_frame
+ }
+ }
+
+ ## Show search bar
+ # @return void
+ public method messages_text_find_dialog {} {
+ if {![winfo ismapped $search_frame]} {
+ pack $search_frame -before $main_frame -side top -anchor w
+ $search_entry delete 0 end
+ focus -force $search_entry
+ } {
+ focus -force $search_entry
+ }
+ }
+
+ ## Search for the given string within the text
+ # @parm String string - Text to find
+ # @return Bool - Always 1
+ public method messages_text_search {string} {
+ if {$string == {}} {
+ $search_entry configure -style TEntry
+ $search_find_next configure -state disabled
+ $search_find_prev configure -state disabled
+ $menu entryconfigure [::mc "Find next"] -state disabled
+ $menu entryconfigure [::mc "Find previous"] -state disabled
+ return 1
+ }
+ set search_string $string
+ messages_text_perform_search 1 1.0
+
+ return 1
+ }
+
+ ## Perform search for $search_string in the text widget
+ # @parm Bool forw__back - 1 == Search forwards; 0 == Search backard
+ # @parm String from - Start index
+ # @return void
+ public method messages_text_perform_search {forw__back from} {
+ if {$search_string == {}} {return}
+
+ if {$forw__back} {
+ set direction {-forwards}
+ } {
+ set direction {-backwards}
+ }
+ if {${::Todo::match_case}} {
+ set last_find_index [$messages_text search $direction -- $search_string $from]
+ } {
+ set last_find_index [$messages_text search $direction -nocase -- $search_string $from]
+ }
+ if {$last_find_index == {}} {
+ $search_entry configure -style StringNotFound.TEntry
+ $search_find_next configure -state disabled
+ $search_find_prev configure -state disabled
+ $menu entryconfigure [::mc "Find next"] -state disabled
+ $menu entryconfigure [::mc "Find previous"] -state disabled
+ } {
+ $search_entry configure -style StringFound.TEntry
+ $search_find_next configure -state normal
+ $search_find_prev configure -state normal
+ $menu entryconfigure [::mc "Find next"] -state normal
+ $menu entryconfigure [::mc "Find previous"] -state normal
+
+ set search_string_length [string length $search_string]
+ $messages_text see $last_find_index
+ catch {
+ $messages_text tag remove sel 0.0 end
+ }
+ $messages_text tag add sel $last_find_index $last_find_index+${search_string_length}c
+ }
+ }
+
+ ## Find next occurence of the search string
+ # @return void
+ public method messages_text_find_next {} {
+ if {![winfo ismapped $search_frame]} {
+ pack $search_frame -before $main_frame -side top -anchor w
+ }
+ if {$last_find_index == {}} {
+ return
+ }
+ messages_text_perform_search 1 $last_find_index+${search_string_length}c
+ }
+
+ ## Find previous occurence of the search string
+ # @return void
+ public method messages_text_find_prev {} {
+ if {![winfo ismapped $search_frame]} {
+ pack $search_frame -before $main_frame -side top -anchor w
+ }
+ if {$last_find_index == {}} {
+ return
+ }
+ messages_text_perform_search 0 $last_find_index
+ }
+
+ ## Enter hyperlink
+ # @parm Int x - Relative pointer position
+ # @parm Int x - Relative pointer position
+ # @return void
+ public method messages_text_hyperlink_enter {x y} {
+ set hyperlink_line_start [$messages_text index [list @$x,$y linestart]]
+ hyperlink_active
+ }
+
+ ## Leave hyperlink
+ # @return void
+ public method messages_text_hyperlink_leave {} {
+ $messages_text config -cursor xterm
+ $messages_text tag remove hyper_link_over 0.0 end
+ }
+
+ ## Enter pointer motion
+ # @parm Int x - Relative pointer position
+ # @parm Int x - Relative pointer position
+ # @return void
+ public method messages_text_hyperlink_motion {x y} {
+ set line_start [$messages_text index [list @$x,$y linestart]]
+ if {$hyperlink_line_start == $line_start} {
+ return
+ }
+ set hyperlink_line_start $line_start
+ $messages_text tag remove hyper_link_over 0.0 end
+ hyperlink_active
+ }
+
+ ## Highlight hyperlink on line $hyperlink_line_start
+ # @return void
+ private method hyperlink_active {} {
+ set range [$messages_text tag nextrange error $hyperlink_line_start [list $hyperlink_line_start lineend]]
+ if {![llength $range]} {
+ set range [$messages_text tag nextrange warning $hyperlink_line_start [list $hyperlink_line_start lineend]]
+ }
+ if {![llength $range]} {
+ return
+ }
+ $messages_text config -cursor hand2
+ $messages_text tag add hyper_link_over [lindex $range 0] [lindex $range 1]
+ }
+}
diff --git a/lib/bottompanel/terminal.tcl b/lib/bottompanel/terminal.tcl
new file mode 100755
index 0000000..6c373f8
--- /dev/null
+++ b/lib/bottompanel/terminal.tcl
@@ -0,0 +1,135 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides terminal emulator for bottom notebook
+# --------------------------------------------------------------------------
+
+class Terminal {
+ # Terminal emulator configuration
+ common configuration
+ common configuration_def [subst {
+ bg #FFFFFF
+ fg #000000
+ font_size 12
+ font_family {$::DEFAULT_FIXED_FONT}
+ }]
+
+ private variable terminal_counter 0 ;# Int: Counter of terminal emulator instances
+ private variable terminal_frame ;# Widget: ID of terminal container frame
+ private variable wrapper_frame ;# Widget: Wrapper frame for $terminal_frame
+ private variable parent ;# Widget: Parent frame
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+ private variable terminal_pid {} ;# Int: PID of terminal emulator
+
+ destructor {
+ terminal_kill_childern
+ }
+
+ ## Prepare this tab for GUI creation
+ # @parm Widget _parent -
+ # @return void
+ public method PrepareTerminal {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method TerminalTabRaised {} {
+ focus $terminal_frame
+ }
+
+ ## Create GUI
+ # @return void
+ public method CreateTerminalEmulGUI {} {
+ if {$gui_initialized || !${::PROGRAM_AVALIABLE(urxvt)}} {return}
+ set gui_initialized 1
+
+ set wrapper_frame [frame $parent.wrapper_frame -relief sunken -bd 2]
+ pack $wrapper_frame -fill both -expand 1
+ terminal_recreate_terminal
+ unset parent
+ }
+
+ ## Internal procedure -- (re)create frame with terminal emulator
+ # @return void
+ public method terminal_recreate_terminal {} {
+ if {![winfo exists $wrapper_frame]} {return}
+ set terminal_frame [frame $wrapper_frame.terminal_frame_${terminal_counter} -container 1]
+ bind $terminal_frame <Destroy> "$this terminal_recreate_terminal"
+
+ set pwd [pwd]
+ if {[catch {
+ cd [$this cget -projectPath]
+ }]} {
+ cd ~
+ }
+ if {[catch {
+ set terminal_pid [exec -- urxvt \
+ -embed [expr [winfo id $terminal_frame]] \
+ -sr -b 0 -w 0 -bg ${configuration(bg)} \
+ -fg ${configuration(fg)} \
+ -fn "xft:$configuration(font_family):pixelsize=$configuration(font_size)" & \
+ ]
+ } result]} {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to find urxvt"] \
+ -message [mc "Unable to execute program \"urxvt\", terminal emulator is eiter not avaliable or badly configured."]
+ puts stderr $result
+ }
+ cd $pwd
+ pack $terminal_frame -fill both -expand 1
+ incr terminal_counter
+ }
+
+ ## Restart terminal emulator
+ # @return void
+ public method terminal_restart {} {
+ if {!$gui_initialized} {return}
+ if {!${::PROGRAM_AVALIABLE(urxvt)}} {return}
+ catch {
+ exec kill $terminal_pid
+ }
+ }
+
+ ## Kill terminal emulator
+ # @return void
+ public method terminal_kill_childern {} {
+ if {$gui_initialized} {
+ if {[info exists terminal_frame] && [winfo exists $terminal_frame]} {
+ bind $terminal_frame <Destroy> {}
+ }
+ catch {
+ exec kill $terminal_pid
+ }
+ }
+ }
+}
+
+# Initialize NS variables
+array set ::Terminal::configuration ${::Terminal::configuration_def}
diff --git a/lib/bottompanel/todo.tcl b/lib/bottompanel/todo.tcl
new file mode 100755
index 0000000..6a7d8ff
--- /dev/null
+++ b/lib/bottompanel/todo.tcl
@@ -0,0 +1,1496 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides autonome GUI component intented for writing ToDo list
+# --------------------------------------------------------------------------
+
+class Todo {
+ common buttonActiveBg {#2222FF} ;# Color for button representing currently active text tags
+ common buttonSemiActBg {#8888FF} ;# - || - semi active tags
+
+ # Normal font for messages text
+ common todo_normal_font [font create \
+ -family ${Editor::fontFamily} \
+ -size -${Editor::fontSize} \
+ ]
+ common normal_font [font create \
+ -family {helvetica} \
+ -size -12 -weight {normal} \
+ ]
+ common bold_font [font create \
+ -family {helvetica} \
+ -size -12 -weight {bold} \
+ ]
+ # List of used text tags
+ common textTags {
+ tag_bold tag_italic tag_overstrike tag_underline
+ }
+ # List of XML tags for text tags (above)
+ common xmlTags {
+ b i s u
+ }
+ # List "tagging" buttons
+ common tagButtons {
+ button_bold button_italic button_strike button_under
+ }
+ # List of self closing tags
+ common selfCtags {bookmark}
+ common set_shortcuts {} ;# Currently set shortcut bindigs
+ common shortcuts_cat {todo} ;# Key shortcut categories related to this segment
+ # ID of bookmark image
+ common bookmarkImage ok
+ # Definition of the popup menu
+ common TODOMENU {
+ {command {Undo} {Ctrl+Z} 0 "undo" {undo}
+ "Undo last operaton"}
+ {command {Redo} {Ctrl+Shift+Z} 2 "redo" {redo}
+ "Take back last undo operation"}
+ {separator}
+ {command {Cut} {Ctrl+X} 2 "cut" {editcut} {}}
+ {command {Copy} {Ctrl+C} 0 "copy" {editcopy} {}}
+ {command {Paste} {Ctrl+V} 0 "paste" {editpaste} {}}
+ {command {Clear} {} 1 "clear" {editdelete} {}}
+ {separator}
+ {command {Select all} {Ctrl+A} 0 "selectall" {} {}}
+ {separator}
+ {command {Find} {$todo:todo_find} 0 "find_dialog" {find} {}}
+ {command {Find next} {$todo:todo_find_n} 5 "find_next" {down0} {}}
+ {command {Find previous} {$todo:todo_find_p} 8 "find_prev" {up0} {}}
+ {separator}
+ {command {Bold text} {$todo:bold} 0 "bold" {text_bold}
+ "Use bold font"}
+ {command {Italic text} {$todo:italic} 0 "italic" {text_italic}
+ "Use italic font"}
+ {command {Striketrought text} {$todo:strike} 0 "strike" {text_strike}
+ "Use striketrought font"}
+ {command {Underline text} {$todo:under} 1 "under" {text_under}
+ "Use underline font"}
+ {separator}
+ {command {Erase tags} {$todo:edrase} 0 "eraser" {eraser}
+ "Clear rich text tags"}
+ {command {Insert OK image} {$todo:insert} 1 "bookmark" {ok}
+ "Insert image \"Ok\""}
+ }
+
+ # Variables related to object initialization
+ private variable input_text ;# String: initial content of the text widget
+ private variable gui_initialized 0 ;# Bool: GUI created
+
+ # Other variables
+ private variable main_frame ;# ID of main frame (text_widget; scrollbar; button_frame)
+ private variable text_widget ;# ID of the text widget
+ private variable scrollbar ;# ID of scrollbar
+ private variable button_frame ;# ID of button frame (on left)
+ private variable parent_container ;# ID of parent contaner (some frame)
+ private variable button_bold ;# ID of button "Bold"
+ private variable button_italic ;# ID of button "Italic"
+ private variable button_strike ;# ID of button "Striketrought"
+ private variable button_under ;# ID of button "Underline"
+ private variable active_tags {} ;# Currently active tags
+ private variable menu {} ;# ID of popup menu
+
+ private variable editor_count 0 ;# Int: Counter of editor instances
+ private variable file_notes_pagesManager ;# Widget: Pages Manager for the file notes
+ private variable LIST_file_notes {} ;# List of Widget: Text widgets with the file notes
+ private variable LIST_file_notes_name {} ;# List of Widget: Label with the file name
+ private variable file_notes ;# Widget: File specific notepad
+ private variable file_notes_name ;# Widget: Label above file specific notepad (file name)
+ private variable file_notes_pages
+
+ private variable notes_invisible_frm ;# Widget: Frame to show when file notes is hidden
+ private variable paned_win ;# Widget: Paned window containing "File notes" and "Notes"
+ private variable right_pane ;# Widget: Right part of the $paned_win
+ private variable left_pane ;# Widget: Left part of the $paned_win
+
+ # Bool: Paned window redraw procedure is in progress
+ private variable redraw_pane_in_progress 0
+ # Bool: File Notes is visible
+ private variable notes_visible [lindex $::CONFIG(FILE_NOTES) 0]
+ # Int: File notes panel size
+ private variable panel_size [lindex $::CONFIG(FILE_NOTES) 1]
+ # Int: File notes panel size (value before it was hidden)
+ private variable panel_size_last [lindex $::CONFIG(FILE_NOTES) 1]
+
+ # Variables related to search bar
+ private variable search_frame ;# Widget: Search bar frame
+ private variable last_find_index ;# String: Index of last found occurence of the search string
+ private variable search_string ;# String: Search string
+ private variable search_string_length ;# Int: Length of the search string
+ private variable search_entry ;# Widget: Search bar entry box
+ private variable search_find_next ;# Widget: Button "Next"
+ private variable search_find_prev ;# Widget: Button "Prev"
+
+ ## Object constructor
+ constructor {} {
+ # Configure specific ttk styles
+ ttk::style configure Todo_Active.TButton \
+ -background $buttonActiveBg \
+ -padding 0 \
+ -relief flat
+ ttk::style map Todo_Active.TButton \
+ -relief [list active raised] \
+ -background [list disabled {#EEEEEE} active $buttonActiveBg]
+
+ ttk::style configure Todo_SemiAct.TButton \
+ -background $buttonSemiActBg \
+ -padding 0 \
+ -relief flat
+ ttk::style map Todo_SemiAct.TButton \
+ -relief [list active raised] \
+ -background [list disabled {#EEEEEE} active $buttonSemiActBg]
+ }
+
+ ## Object destructor
+ destructor {
+ # Remove dynamic help on status bar
+ if {[winfo exists $menu]} {
+ menu_Sbar_remove $menu
+ }
+ }
+
+ ## Get configuration list for file specific notepad
+ # @return void
+ public method get_file_notes_config {} {
+ if {$panel_size < $panel_size_last} {
+ set panel_size_max $panel_size_last
+ } {
+ set panel_size_max $panel_size
+ }
+ return [list $notes_visible $panel_size_max]
+ }
+
+ ## Get contents of file specific notepad
+ # @parm Int = <current> - Index in $LIST_file_notes
+ # @return void
+ public method get_file_notes_data args {
+ CreateTodoGUI
+
+ if {$args == {}} {
+ return [$file_notes get 1.0 {end-1l lineend}]
+ } {
+ set w [lindex $LIST_file_notes $args]
+ if {$w == {}} {
+ return {}
+ } {
+ return [$w get 1.0 {end-1l lineend}]
+ }
+ }
+ }
+
+ ## Set contents of file specific notepad
+ # @parm String data - Text
+ # @return void
+ public method set_file_notes_data {data} {
+ CreateTodoGUI
+
+ $file_notes delete 0.0 end
+ $file_notes insert end $data
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget parentContainer - parent contaner (some frame)
+ # @parm String inputText - initial content of the text widget
+ # @return void
+ public method PrepareTodo {parentContainer _input_text} {
+ set parent_container $parentContainer
+ set input_text $_input_text
+ set gui_initialized 0
+ }
+
+ ## Inform this tab than it has became active
+ # @return void
+ public method TodoTabRaised {} {
+ focus $text_widget
+ after idle "update; catch {$this todo_panel_redraw_pane}"
+ }
+
+ ## Add file specific notepad for a newly created editor
+ # @parm String data - Text of the notes
+ # @return void
+ public method todo_add_Editor {data} {
+ CreateTodoGUI
+
+ # Create a new page in the pages manager for the file specific notepad
+ set frm [$file_notes_pagesManager add $editor_count]
+
+ # Create top and bottom frame
+ set tf [frame $frm.t]
+ set bf [frame $frm.b]
+
+ # Create widgets for the top frame
+ pack [label $tf.hl -text [mc "Notes for file:"] -font $normal_font] -side left
+ set file_notes_name [label $tf.file_name -font $bold_font]
+ pack $file_notes_name -side left
+ pack [ttk::button $tf.hide_button \
+ -image ::ICONS::16::2rightarrow \
+ -command "$this todo_file_notes_show_hide 0" \
+ -style Flat.TButton \
+ ] -side right
+
+ # Create widgets for the bottom frame
+ set file_notes [text $bf.text \
+ -font $todo_normal_font -undo 1 -bg white \
+ -selectbackground {#AAFFAA} -selectborderwidth 1 \
+ -selectforeground {#000000} -highlightthickness 0 \
+ -yscrollcommand "$bf.scrollbar set" \
+ -wrap word -width 1 -height 1 -tabstyle wordprocessor \
+ ]
+ pack $file_notes -fill both -expand 1 -side left
+ pack [ttk::scrollbar $bf.scrollbar \
+ -command "$file_notes yview" \
+ -orient vertical \
+ ] -fill y -side right
+
+ # Pack frames
+ pack $tf -side top -anchor nw -fill x
+ pack $bf -side bottom -fill both -expand 1
+
+ # Register the newly created widgets
+ lappend file_notes_pages $editor_count
+ lappend LIST_file_notes $file_notes
+ lappend LIST_file_notes_name $file_notes_name
+
+ set_file_notes_data $data
+ incr editor_count
+ }
+
+ ## Redraw panel (move pane sash) acorning to current value of $PanelSize
+ # @return void
+ public method todo_panel_redraw_pane {} {
+ if {!$gui_initialized} {return}
+
+ if {$redraw_pane_in_progress} {
+ after 50 "$this todo_panel_redraw_pane"
+ return
+ }
+ set redraw_pane_in_progress 1
+
+ update
+ $paned_win sash place 0 [expr {${::WIN_GEOMETRY_width} - $panel_size}] 0
+ update
+
+ set redraw_pane_in_progress 0
+ }
+
+ ## Set panel width acording to current sash position
+ # @return void
+ public method todo_panel_set_size {} {
+ set panel_size [lindex [$paned_win sash coord 0] 0]
+ set panel_size [expr {${::WIN_GEOMETRY_width} - $panel_size}]
+ }
+
+ ## Show or hide the file specific notepad
+ # @parm Bool show__hide - 1 == Show; 0 == Hide
+ # @return void
+ public method todo_file_notes_show_hide {show__hide} {
+ CreateTodoGUI
+ set notes_visible $show__hide
+
+ # Show
+ if {$notes_visible} {
+ pack forget $notes_invisible_frm
+ pack $file_notes_pagesManager -fill both -expand 1
+ $paned_win paneconfigure $right_pane -minsize 200
+ set panel_size $panel_size_last
+
+ # Hide
+ } {
+ pack forget $file_notes_pagesManager
+ pack $notes_invisible_frm -fill y -anchor nw
+ $paned_win paneconfigure $right_pane -minsize 20
+ set panel_size_last $panel_size
+ set panel_size 60
+ }
+
+ todo_panel_redraw_pane
+ }
+
+ ## Remove file specific notes
+ # @parm Int idx - Editor index
+ # @return void
+ public method todo_remove_editor {idx} {
+ CreateTodoGUI
+
+ $file_notes_pagesManager delete [lindex $file_notes_pages $idx]
+ set file_notes_pages [lreplace $file_notes_pages $idx $idx]
+ set LIST_file_notes [lreplace $LIST_file_notes $idx $idx]
+ set LIST_file_notes_name [lreplace $LIST_file_notes_name $idx $idx]
+ }
+
+ ## Switch file specific notes to another editor
+ # @parm Int idx - Editor index
+ # @return void
+ public method todo_switch_editor {idx} {
+ CreateTodoGUI
+
+ set file_notes_name [lindex $LIST_file_notes_name $idx]
+ set file_notes [lindex $LIST_file_notes $idx]
+ $file_notes_pagesManager raise [lindex $file_notes_pages $idx]
+ }
+
+ ## Change file name shown in the file specific notes to another string
+ # @parm Int idx - Editor index
+ # @parm String newname - New file name
+ # @return void
+ public method todo_change_filename {idx newname} {
+ $file_notes_name configure -text $newname
+ }
+
+ ## Swithc some variables related to the file specific notes to another editor
+ # @parm Inr idx - Editor index
+ # @return void
+ public method todo_switch_editor_vars {idx} {
+ CreateTodoGUI
+
+ set file_notes_name [lindex $LIST_file_notes_name $idx]
+ set file_notes [lindex $LIST_file_notes $idx]
+ }
+
+ ## Set text for thec urrent file specific notepad
+ # @parm String text - The text
+ # @return void
+ public method todo_file_notes_set_text {text} {
+ $file_notes delete 0.0 end
+ $file_notes insert end $text
+ }
+
+ ## Get text from the file specific notepad
+ # @return void
+ public method todo_file_notes_get_text {} {
+ return [$file_notes get 0.0 end]
+ }
+
+ ## Initialize todo text
+ # @return void
+ public method CreateTodoGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ set paned_win [panedwindow $parent_container.paned_win \
+ -sashwidth 4 -showhandle 0 -opaqueresize 1 -orient horizontal \
+ ]
+ bind $paned_win <ButtonRelease-1> "$this todo_panel_set_size"
+
+ set left_pane [frame $paned_win.l]
+ set right_pane [frame $paned_win.r]
+
+ $paned_win add $left_pane
+ $paned_win add $right_pane
+
+ $paned_win paneconfigure $left_pane -minsize 200
+ $paned_win paneconfigure $right_pane -minsize 200
+
+
+ #
+ # RIGHT PART
+ #
+
+ set file_notes_pagesManager [PagesManager $right_pane.pmgr -background {#eeeeee}]
+ $file_notes_pagesManager compute_size
+
+ set notes_invisible_frm [frame $right_pane.notes_invisible_frm]
+ pack [ttk::button $notes_invisible_frm.hide_button \
+ -image ::ICONS::16::2leftarrow \
+ -command "$this todo_file_notes_show_hide 1" \
+ -style Flat.TButton \
+ ] -anchor nw
+
+ todo_file_notes_show_hide $notes_visible
+
+ #
+ # LEFT PART
+ #
+
+ # Create GUI components in main frame
+ set main_frame [frame $left_pane.main_frame]
+ set text_widget [text $main_frame.todo_text \
+ -yscrollcommand "$main_frame.todo_text_scrl set" \
+ -font $todo_normal_font -undo 1 -bg white \
+ -selectbackground {#AAFFAA} -selectborderwidth 1 \
+ -selectforeground {#000000} -highlightthickness 0 \
+ -wrap word -width 1 -height 1 -tabstyle wordprocessor \
+ ]
+ set scrollbar [ttk::scrollbar $main_frame.todo_text_scrl \
+ -command "$text_widget yview" \
+ -orient vertical \
+ ]
+ set button_frame [frame $main_frame.todo_text_bframe]
+
+ # Pack GUI of main frame
+ pack $button_frame -side left -anchor n
+ pack $text_widget -fill both -expand 1 -side left
+ pack $scrollbar -fill y -side right
+
+ ## Create GUI components in search bar frame
+ set search_frame [frame $left_pane.search_frame]
+ # Search entry box
+ set search_entry [ttk::entry $search_frame.entry \
+ -width 30 \
+ -validate all \
+ -validatecommand "$this TodoProc_search %P" \
+ ]
+ bind $search_entry <Key-Escape> "$this TodoProc_hide_find_dialog"
+ # Button: "Next"
+ set search_find_next [ttk::button $search_frame.find_next_but \
+ -image ::ICONS::16::down0 \
+ -command "$this TodoProc_find_next" \
+ -state disabled \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $search_frame.find_next_but \
+ -text [mc "Find next occurence of search string"]
+ # Button: "Prev"
+ set search_find_prev [ttk::button $search_frame.find_prev_but \
+ -image ::ICONS::16::up0 \
+ -command "$this TodoProc_find_prev" \
+ -state disabled \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $search_frame.find_prev_but \
+ -text [mc "Find previous occurence of search string"]
+ # Button: "Close"
+ pack [ttk::button $search_frame.close_but \
+ -image ::ICONS::16::button_cancel \
+ -command "$this TodoProc_hide_find_dialog" \
+ -style Flat.TButton \
+ ] -side left
+ DynamicHelp::add $search_frame.close_but \
+ -text [mc "Hide search bar"]
+ # Separator
+ pack [ttk::separator $search_frame.sep \
+ -orient vertical \
+ ] -fill y -padx 5 -side left -pady 2
+ # Label: "Find"
+ pack [label $search_frame.find_lbl \
+ -text [mc "Find:"] \
+ ] -side left
+ # Pack entry and buttons next and prev
+ pack $search_entry -side left
+ pack $search_find_next -side left -padx 5
+ pack $search_find_prev -side left
+ # Checkbutton: "Match case"
+ pack [checkbutton $search_frame.match_case_chb \
+ -text [mc "Match case"] \
+ -variable ::Todo::match_case \
+ -command "$this TodoProc_perform_search 1 1.0" \
+ ] -side left -padx 5
+
+ # Pack main frame
+ pack $main_frame -fill both -expand 1
+
+ # Adjust text widget parameters
+ TodoProc_write_text_from_sgml $input_text
+ unset input_text
+ $text_widget edit modified 0
+ $text_widget edit reset
+
+ # create events bindings
+ foreach key [bind Text] {
+ bind $text_widget $key {continue}
+ }
+ bind $text_widget <<Undo>> "$this TodoProc_undo; break"
+ bind $text_widget <<Redo>> "$this TodoProc_redo; break"
+ foreach key {
+ <Key-End> <Key-Home>
+ <Key-Down> <Key-Up>
+ <Key-Right> <Key-Left>
+ <Key-Next> <Key-Prior>
+ } {
+ bind $text_widget $key "
+ [bind Text $key]
+ $this recalc_left_panel insert
+ break"
+ }
+ bind $text_widget <KeyRelease> "break"
+ bind $text_widget <KeyPress> "$this TodoProc_Key %A; break"
+ bind $text_widget <ButtonPress-1> "$this TodoProc_leftClick %x %y"
+ bind $text_widget <ButtonRelease-1> "$this TodoProc_leftRelease"
+ bind $text_widget <ButtonRelease-3> "$this TodoProc_popupMenu %X %Y %x %y; break"
+ bind $text_widget <Key-Menu> "$this TodoProc_Key_Menu; break"
+ TodoProc_shortcuts_reevaluate
+
+ ## Create button bar
+ # Button "Bold"
+ set button_bold [ttk::button $button_frame.todo_text_bB \
+ -image ::ICONS::16::text_bold \
+ -command "$this TodoProc_bold" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $button_bold -text [mc "Bold font"]
+ setStatusTip -widget $button_bold \
+ -text {Use bold font}
+ # Button "Italic"
+ set button_italic [ttk::button $button_frame.todo_text_bI \
+ -image ::ICONS::16::text_italic \
+ -command "$this TodoProc_italic" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $button_italic \
+ -text [mc "Italic text"]
+ setStatusTip -widget $button_italic \
+ -text {Use italic font}
+ # Button "Striketrought"
+ set button_strike [ttk::button $button_frame.todo_text_bS \
+ -image ::ICONS::16::text_strike \
+ -command "$this TodoProc_strike" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $button_strike \
+ -text [mc "Striketrought font"]
+ setStatusTip -widget $button_strike -text {Use striketrought font}
+ # Button "Underline"
+ set button_under [ttk::button $button_frame.todo_text_bU \
+ -image ::ICONS::16::text_under \
+ -command "$this TodoProc_under" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $button_under \
+ -text [mc "Underline font"]
+ setStatusTip -widget $button_under \
+ -text {Use underline font}
+
+ # pack these buttons
+ foreach wdg $tagButtons {
+ pack [subst "\$$wdg"]
+ }
+ # Button "Eraser"
+ pack [ttk::button $button_frame.todo_text_bE \
+ -image ::ICONS::16::eraser \
+ -command "$this TodoProc_eraser" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $button_frame.todo_text_bE \
+ -text [mc "Erase text tags"]
+ setStatusTip -widget $button_frame.todo_text_bE \
+ -text {Remove formating tags within selected area}
+ # Button "Bookmark"
+ pack [ttk::button $button_frame.todo_text_bBm \
+ -image ::ICONS::16::$bookmarkImage \
+ -command "$this TodoProc_bookmark" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $button_frame.todo_text_bBm \
+ -text [mc "Insert OK image"]
+ setStatusTip -widget $button_frame.todo_text_bBm \
+ -text [mc "Insert \"Ok\" image at the current cursor position"]
+
+ # create popup menu
+ set menu $text_widget.todo_menu
+ TodoProc_makePopupMenu
+
+ # Create text tags and set main font
+ todo_refresh_font_settings
+
+ pack $paned_win -fill both -expand 1
+ }
+
+ ## Recreate all text tags and font font for the text widget
+ # @return void
+ public method todo_refresh_font_settings {} {
+ if {!$gui_initialized} {CreateTodoGUI}
+ $text_widget configure -font [font create \
+ -family ${Editor::fontFamily} \
+ -size -${Editor::fontSize} \
+ ]
+ todo_create_tags
+ }
+
+ ## Create bindings for defined key shortcuts
+ # @return void
+ public method TodoProc_shortcuts_reevaluate {} {
+ if {!$gui_initialized} {CreateTodoGUI}
+
+ # Unset previous configuration
+ foreach key $set_shortcuts {
+ bind $text_widget <$key> {}
+ }
+ set set_shortcuts {}
+
+ # Iterate over shortcuts definition
+ foreach block ${::SHORTCUTS_LIST} {
+ # Determinate category
+ set category [lindex $block 0]
+ if {[lsearch $shortcuts_cat $category] == -1} {continue}
+
+ # Determinate definition list and its length
+ set block [lreplace $block 0 2]
+ set len [llength $block]
+
+ # Iterate over definition list and create bindings
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ # Determinate key sequence
+ set key [lindex $block $i]
+ if {[catch {
+ set key $::SHORTCUTS_DB($category:$key)
+ }]} then {
+ continue
+ }
+ if {$key == {}} {continue}
+
+ # Create and register new binding
+ lappend set_shortcuts $key
+ set cmd [subst [lindex $block [list $j 1]]]
+ append cmd {;break}
+ bind $text_widget <$key> $cmd
+ bind $search_entry <$key> $cmd
+ }
+ }
+ }
+
+ ## Create popup menu
+ # @return void
+ public method TodoProc_makePopupMenu {} {
+ if {!$gui_initialized} {return}
+ if {[winfo exists $menu]} {
+ destroy $menu
+ }
+ menuFactory $TODOMENU $menu 0 "$this TodoProc_" 0 {}
+ $menu entryconfigure [::mc "Find next"] -state disabled
+ $menu entryconfigure [::mc "Find previous"] -state disabled
+ }
+
+ ## Create text tags in todo text widget
+ # @return void
+ private method todo_create_tags {} {
+ # Tag "Bold"
+ $text_widget tag configure tag_bold \
+ -font [font create -size -${Editor::fontSize} \
+ -weight bold -family ${Editor::fontFamily} \
+ ]
+ # Tag "Italic"
+ $text_widget tag configure tag_italic \
+ -font [font create -size -${Editor::fontSize} \
+ -slant italic -family ${Editor::fontFamily} \
+ ]
+ # Tag "Underline"
+ $text_widget tag configure tag_underline -underline 1
+ # Tag "Overstrike"
+ $text_widget tag configure tag_overstrike -overstrike 1
+ }
+
+ ## Invoke the popup menu
+ # @parm Int X - Absolute x coordinate
+ # @parm Int Y - Absolute y coordinate
+ # @parm Int x - Relative x coordinate
+ # @parm Int y - Relative y coordinate
+ # @return void
+ public method TodoProc_popupMenu {X Y x y} {
+ popup_menu_disena
+ tk_popup $menu $X $Y
+ $text_widget mark set insert @$x,$y
+ }
+
+ ## Handles event: 'Menu' -- invoke popup menu
+ # @return void
+ public method TodoProc_Key_Menu {} {
+ popup_menu_disena
+ $text_widget see insert
+ set bbox [$text_widget bbox [$text_widget index insert]]
+ tk_popup $menu \
+ [expr {[winfo rootx $text_widget] + [lindex $bbox 0] + 10}] \
+ [expr {[winfo rooty $text_widget] + [lindex $bbox 1] + 10}]
+ }
+
+ ## Enable/Disable popup menu items acording to state of the text widget
+ # Auxiliary procedure for 'TodoProc_popupMenu' and 'TodoProc_Key_Menu'
+ # @return void
+ private method popup_menu_disena {} {
+ set state [$text_widget cget -state]
+ if {[llength [$text_widget tag nextrange sel 1.0]]} {
+ if {$state != {disabled}} {
+ $menu entryconfigure [::mc "Cut"] -state normal
+ }
+ $menu entryconfigure [::mc "Copy"] -state normal
+ } {
+ $menu entryconfigure [::mc "Cut"] -state disabled
+ $menu entryconfigure [::mc "Copy"] -state disabled
+ }
+ foreach entry {Undo Redo Paste Clear} {
+ $menu entryconfigure [::mc $entry] -state $state
+ }
+ }
+
+ ## Write text to the text widget from SGML formated data
+ # @parm String inputData - SGML data
+ # @return void
+ public method TodoProc_write_text_from_sgml {inputData} {
+ if {!$gui_initialized} {CreateTodoGUI}
+
+ # Replace all \r\n shit with LF
+ regsub -all {(\r)|(\r\n)} $inputData "\n" inputData
+
+ # Insert plain text
+ set plainText [regsub -all {<[^<>]*>} $inputData {}]
+ regsub -all {&lt;} $plainText {<} plainText
+ regsub -all {&gt;} $plainText {>} plainText
+ $text_widget insert end $plainText
+
+ # Convert entities to spaces
+ regsub -all {&lt;} $inputData { } inputData
+ regsub -all {&gt;} $inputData { } inputData
+
+ ## Parse pair tags
+ set lastStartIdx 0
+ set lastEndIdx 0
+ foreach xmltag $xmlTags texttag $textTags {
+
+ # modify input data for later processing
+ set data $inputData
+ foreach tag $xmlTags {
+ if {$tag == $xmltag} {continue}
+ regsub -all "<$tag>" $data {} data
+ regsub -all "</$tag>" $data {} data
+ regsub -all "<bookmark/>" $data {} data
+ }
+
+ # Translate XML tags to Tk's native text tags
+ set StartRow 1
+ set EndCol 0
+ while 1 {
+ set SRow 0
+ set ERow 0
+ set tagLength [string length "<$xmltag>"]
+
+ set startIdx [string first "<$xmltag>" $data]
+ if {$startIdx == -1} {break}
+
+ set LFidx 0
+ set LastLFidx $LFidx
+ while 1 {
+ set LFidx [string first "\n" $data $LFidx]
+ if {($LFidx >= $startIdx) || ($LFidx == -1)} {
+ set correction 0
+ if {$SRow == 0} {
+ set correction $EndCol
+ incr correction
+ }
+ set StartCol [expr {$startIdx - $LastLFidx - 1 + $correction}]
+ set StartRow [expr {$StartRow + $SRow}]
+ break
+ } {
+ set LastLFidx $LFidx
+ incr SRow
+ incr LFidx
+ }
+ }
+ set EndRow $StartRow
+
+ set data [string range $data [expr {$tagLength + $startIdx}] end]
+ set endIdx [string first "</$xmltag>" $data]
+ if {$endIdx == -1} {break}
+
+ set LFidx 0
+ set LastLFidx $LFidx
+ while 1 {
+ set LFidx [string first "\n" $data $LFidx]
+ if {($LFidx >= $endIdx) || ($LFidx == -1)} {
+ set correction 0
+ if {$ERow == 0} {set correction $StartCol}
+ set EndCol [expr {$endIdx - $LastLFidx - $ERow + $correction}]
+ set EndRow [expr {$EndRow + $ERow}]
+ break
+ } {
+ set LastLFidx $LFidx
+ incr ERow
+ incr LFidx
+ }
+ }
+ set data [string range $data [expr {$tagLength + $endIdx + 1}] end]
+
+ if {($StartRow == $EndRow) && ($StartCol >= $EndCol)} {break}
+ $text_widget tag add $texttag $StartRow.$StartCol $EndRow.$EndCol
+ set StartRow $EndRow
+ }
+ }
+
+ ## Parse non pair tags
+
+ # modify input data for later processing
+ set data $inputData
+ regsub -all {<[^<>]*[^/]>} $data {} data
+ append data "\n"
+
+ foreach tag $selfCtags {
+ set Row 1
+ set Col 0
+ while 1 {
+ set tagIdx [string first "<$tag" $data]
+ set tagEndIdx [string first "/>" $data]
+ if {($tagEndIdx < $tagIdx) || ($tagIdx == -1)} {break}
+
+ set tagEndIdx [expr {$tagEndIdx + 2}]
+ set rowTmp 0
+ set LFidx 0
+ set LastLFidx $LFidx
+
+ while 1 {
+ set LFidx [string first "\n" $data $LFidx]
+
+ if {$LFidx >= $tagIdx} {
+ set correction 0
+ if {$rowTmp == 0} {set correction [expr {$Col + 2}]}
+ set Col [expr {$tagIdx - $LastLFidx - 1 + $correction}]
+ set Row [expr {$Row + $rowTmp}]
+ break
+ } {
+ set LastLFidx $LFidx
+ incr rowTmp
+ incr LFidx
+ }
+ }
+
+ set data [string range $data $tagEndIdx end]
+
+ switch $tag {
+ {bookmark} {
+ $text_widget delete $Row.$Col $Row.$Col+1c
+ $text_widget image create $Row.$Col -image ::ICONS::16::$bookmarkImage
+ }
+ }
+ }
+ }
+ }
+
+ ## Return content of text widget formated as SGML
+ # @return String - SGML code
+ public method TodoProc_read_text_as_sgml {} {
+ if {!$gui_initialized} {return $input_text}
+
+ # Determinate end index
+ set textEnd [$text_widget index end]
+ set textEnd [expr {int($textEnd)}]
+
+ # Determinate length of each line
+ set lineIndex(1) -1
+ set sum -1
+ for {set i 1; set i0 2} {$i < $textEnd} {incr i; incr i0} {
+ set lineend [$text_widget index "$i.0 lineend"]
+ regexp {\d+$} $lineend lineend
+ incr sum [expr {$lineend + 1}]
+ set lineIndex($i0) $sum
+ }
+
+ # Determinate tag indexes
+ set tagList {}
+ foreach xmltag $xmlTags texttag $textTags {
+ set ranges [$text_widget tag ranges $texttag]
+
+ set i 0
+ set index {}
+ while 1 {
+ set index [lindex $ranges $i]
+ if {$index == {}} {break}
+ lappend tagList "$index $xmltag"
+ incr i
+ lappend tagList "[lindex $ranges $i] /$xmltag"
+ incr i
+ }
+ }
+
+ # Extract plain text data from the text widget
+ set data [$text_widget get 1.0 end]
+
+ # Determinate images indexes and adjust lines idxs
+ set imageIdxs {}
+ foreach imageName [$text_widget image names] {
+ lappend imageIdxs [$text_widget index $imageName]
+ }
+ set imageIdxs [lsort -command "$this read_text_as_sgml_aux_compare 0" $imageIdxs]
+
+ set lastRow 0
+ set col 0
+ set row 0
+ set index 0
+ foreach imageIdx $imageIdxs {
+
+ scan $imageIdx %d.%d row col
+ set index [expr {$lineIndex($row) + $col}]
+ set data [string replace $data $index $index "[string index $data $index] "]
+
+ if {$row == $lastRow} {
+ regexp {\d+$} $imageIdx col
+
+ incr colCorrection -1
+ incr col $colCorrection
+
+ set imageIdx "$row.$col"
+ } {
+ set lastRow $row
+ set colCorrection 0
+ }
+
+ lappend tagList "$imageIdx bookmark/"
+ }
+
+ # Special reverse sorting of tag list
+ set tagList [lsort -command "$this read_text_as_sgml_aux_compare 1" -index 0 $tagList]
+
+ # Traslate angle brackets to some special characters
+ regsub -all {<} $data "\a" data ;# '<' -> alert
+ regsub -all {>} $data "\b" data ;# '>' -> backspace
+
+ # Insert SGML tags into plain text data
+ foreach xmlTagIdx $tagList {
+ set index [lindex $xmlTagIdx 0]
+ set tag [lindex $xmlTagIdx 1]
+
+ scan $index %d.%d row col
+ set index [expr {$lineIndex($row) + $col}]
+
+ if {$index == -1} {
+ incr index
+ set char [string index $data $index]
+ set data [string replace $data $index $index "<$tag>$char"]
+ } {
+ set char [string index $data $index]
+ set data [string replace $data $index $index "$char<$tag>"]
+ }
+ }
+
+ # Traslate angle brackets back
+ regsub -all {\a} $data {\&lt;} data ;# alert -> '&lt;'
+ regsub -all {\b} $data {\&gt;} data ;# backspace -> '&gt;
+
+ regsub -all -line {[  \t]+$} $data {} data
+ regsub -all {<[^<>]+>\n</[^<>]+>} $data "\n" data
+
+ # return final SGML
+ return $data
+ }
+
+ ## Special comparation for text indexes
+ # @parm Bool reverse - Invert result
+ # @parm TextIndex first - Firts index
+ # @parm TextIndex second - Second index
+ # @return Int - result, one of {-1 0 1}
+ public method read_text_as_sgml_aux_compare {reverse first second} {
+
+ # Set return values
+ if {$reverse} {
+ set A -1
+ set B 1
+ } {
+ set A 1
+ set B -1
+ }
+
+ # Determinate First/End Row/Column
+ regexp {^\d+} $first FR ;# First Row
+ regexp {\d+$} $first FC ;# First Column
+ regexp {^\d+} $second ER ;# End Row
+ regexp {\d+$} $second EC ;# End Column
+
+ # Perform comparation
+ if {$FR > $ER} {
+ return $A
+ } elseif {$FR == $ER} {
+ if {$FC > $EC} {
+ return $A
+ } elseif {$FC == $EC} {
+ return 0
+ } {
+ return $B
+ }
+ } else {
+ return $B
+ }
+ }
+
+ ## Get content of text widget as plain text
+ # @return String - result
+ public method read_plain_text {} {
+ if {!$gui_initialized} {CreateTodoGUI}
+ return [$text_widget get 1.0]
+ }
+
+ ## Switch to bold font
+ # @return void
+ public method TodoProc_bold {} {
+ addRemoveTag tag_bold $button_bold
+ }
+
+ ## Switch to italic font
+ # @return void
+ public method TodoProc_italic {} {
+ addRemoveTag tag_italic $button_italic
+ }
+
+ ## Switch to striketrought font
+ # @return void
+ public method TodoProc_strike {} {
+ addRemoveTag tag_overstrike $button_strike
+ }
+
+ ## Switch to underline font
+ # @return void
+ public method TodoProc_under {} {
+ addRemoveTag tag_underline $button_under
+ }
+
+ ## Erase tags
+ # @parm List idxs = {} - Indexes of selected area
+ # @parm Bool reset = 1 - Reset font settings on left panel
+ # @return Bool - result
+ public method TodoProc_eraser args {
+ if {$args == {}} {
+ set idxs [getSelectionIdx]
+ set reset 1
+ set active_tags {}
+ } {
+ set idxs [lindex $args 0]
+ set reset [lindex $args 1]
+ }
+ if {$idxs == {}} {
+ set active_tags {}
+ reset_left_panel
+ return 0
+ }
+ foreach tag $textTags {
+ $text_widget tag remove $tag [lindex $idxs 0] [lindex $idxs 1]
+ }
+ if {$reset} {reset_left_panel}
+ return 1
+ }
+
+ ## Select all text in the text widget
+ # @return void
+ public method TodoProc_selectAll {} {
+ $text_widget tag add sel 1.0 end
+ }
+
+ ## Insert bookmark image at current cursor position
+ # @return void
+ public method TodoProc_bookmark {} {
+ set idx [$text_widget index insert]
+ $text_widget image create $idx -image ::ICONS::16::$bookmarkImage
+ }
+
+ ## Take back last operation
+ # @return void
+ public method TodoProc_undo {} {
+ catch {
+ $text_widget edit undo
+ }
+ }
+
+ ## Take back last undo
+ # @return void
+ public method TodoProc_redo {} {
+ catch {
+ $text_widget edit redo
+ }
+ }
+
+ ## Cut selected text
+ # @return void
+ public method TodoProc_cut {} {
+ if {![llength [$text_widget tag nextrange sel 1.0]]} {return}
+ clipboard clear
+ clipboard append [$text_widget get sel.first sel.last]
+ $text_widget delete sel.first sel.last
+ }
+
+ ## Copy selected text to clipboard
+ # @return void
+ public method TodoProc_copy {} {
+ if {![llength [$text_widget tag nextrange sel 1.0]]} {return}
+ clipboard clear
+ clipboard append [$text_widget get sel.first sel.last]
+ }
+
+ ## Paste text from clipboard
+ # @return void
+ public method TodoProc_paste {} {
+ if {[catch {
+ set data [clipboard get]
+ }]} {
+ return
+ }
+ catch {$text_widget delete sel.first sel.last}
+ $text_widget insert insert $data
+ }
+
+ ## Clear all text
+ # @return void
+ public method TodoProc_clear {} {
+ if {!$gui_initialized} {CreateTodoGUI}
+ catch {$text_widget delete 1.0 end}
+ }
+
+ ## Select all text
+ # @return void
+ public method TodoProc_selectall {} {
+ catch {$text_widget tag add sel 1.0 end}
+ }
+
+ ## Handles key press
+ # @parm String key - ID of pressed key
+ # @return void
+ public method TodoProc_Key {key} {
+
+ # Skip values with no meaning
+ if {[string length $key] != 1} {return}
+
+ # Delete seleced text
+ catch {
+ $text_widget delete sel.first sel.last
+ }
+
+ # Get text index before change
+ regexp {\d+$} [$text_widget index insert] col0
+ incr col0
+
+ # Change content of the text widget
+ $text_widget insert insert $key
+
+ # Get text index after change
+ regexp {\d+$} [$text_widget index insert] col1
+
+ # Apply active tags
+ if {$col0 == $col1} {
+ foreach tag $active_tags {
+ $text_widget tag add $tag {insert-1c} insert
+ }
+ }
+ }
+
+ ## Manage left panel, must be called after each click to the text widget
+ # @parm Int x - relative x coordinate
+ # @parm Int y - relative y coordinate
+ # @return void
+ public method TodoProc_leftClick {x y} {
+ recalc_left_panel [$text_widget index @$x,$y]
+ }
+
+ ## Determinate active tags in the selected area, should be called after each LeftRelease
+ # @return Bool - result
+ public method TodoProc_leftRelease {} {
+
+ # Determinate start and end index of selected region
+ set idxs [getSelectionIdx]
+ # If nothing selected -> return False
+ if {$idxs == {}} {return 0}
+
+ # Local variables
+ regexp {^\d+} [lindex $idxs 0] StartRow ;# Row of start index
+ regexp {^\d+} [lindex $idxs 1] EndRow ;# Row of end index
+ regexp {\d+$} [lindex $idxs 0] StartCol ;# Column of start index
+ regexp {\d+$} [lindex $idxs 1] EndCol ;# Column of end index
+
+ # Object variables
+ set active_tags {} ;# Curretly active tags
+ set semiActiveTags {} ;# Currently semi-active tags
+
+ # Iterate over rows of selected region
+ for {set row $StartRow} {$row <= $EndRow} {incr row} {
+
+ # Iterate over columns of selected reegion
+ for {set col $StartCol} {$col <= $EndCol} {incr col} {
+
+ # Determinate list of active tags at the current index
+ set tags [$text_widget tag names $row.$col-1c]
+
+ # Append these tags to content of object variable active_tags
+ foreach tag $tags {
+ if {$tag == {sel}} {
+ continue
+ }
+ if {[lsearch $active_tags $tag] == -1 && [lsearch $semiActiveTags $tag] == -1} {
+ lappend active_tags $tag
+ }
+ }
+
+ # Determinate semi-active tags
+ foreach tag $active_tags {
+ if {[lsearch $tags $tag] == -1} {
+ set i [lsearch $active_tags $tag]
+ set repleceTag [lindex $active_tags $i]
+ lappend semiActiveTags $tag
+ set active_tags [lreplace $active_tags $i $i]
+ }
+ }
+ }
+ }
+
+ # Restore highlight of left panel buttons
+ reset_left_panel
+ foreach tag $active_tags {
+ set_button_bg_by_tag_name $tag 1
+ }
+ foreach tag $semiActiveTags {
+ set_button_bg_by_tag_name $tag 2
+ }
+
+ # done ...
+ return 1
+ }
+
+ ## Set background color for button related to given text tag acording to given state
+ # @parm String tag - name of text tag
+ # @parm Int state - state number (0 == passive; 1 == active; 2 == semi-active)
+ # @return void
+ private method set_button_bg_by_tag_name {tag state} {
+ switch $tag {
+ {tag_bold} "setButtonBg $button_bold $state"
+ {tag_italic} "setButtonBg $button_italic $state"
+ {tag_overstrike} "setButtonBg $button_strike $state"
+ {tag_underline} "setButtonBg $button_under $state"
+ }
+ }
+
+ ## Reevaluate background color for each button on left panel
+ # @parm TextIndex index - index in the text widget
+ # @return void
+ public method recalc_left_panel {index} {
+
+ # Determinate list of active tags
+ set active_tags [$text_widget tag names $index-1c]
+ # Remove tag sel from the list
+ set i [lsearch -ascii -exact $active_tags {sel}]
+ if {$i != -1} {
+ set active_tags [lreplace $active_tags $i $i]
+ }
+ # No active tags -> reset panel and return
+ if {$active_tags == {}} {
+ reset_left_panel
+ return
+ }
+
+ # Determinate list of buttons related to active tags
+ set affected {}
+ foreach tag $active_tags {
+ switch $tag {
+ {tag_bold} { ;# Bold font
+ if {[lsearch $affected button_bold] != -1} {continue}
+ lappend affected button_bold
+ }
+ {tag_italic} { ;# Italic font
+ if {[lsearch $affected button_italic] != -1} {continue}
+ lappend affected button_italic
+ }
+ {tag_overstrike} { ;# Overstrike font
+ if {[lsearch $affected button_strike] != -1} {continue}
+ lappend affected button_strike
+ }
+ {tag_underline} { ;# Underline font
+ if {[lsearch $affected button_under] != -1} {continue}
+ lappend affected button_under
+ }
+ }
+ }
+
+ # Set background color for each button on left panel
+ foreach button $tagButtons {
+
+ # Determinate ID of button widget
+ set buttonWdg [subst "\$$button"]
+
+ # Determinate state number and set Bg
+ if {[lsearch $affected $button] != -1} {
+ setButtonBg $buttonWdg 1
+ } {
+ setButtonBg $buttonWdg 0
+ }
+ }
+ }
+
+ ## Set default background color for each button on the left panel
+ # @return void
+ private method reset_left_panel {} {
+ foreach button $tagButtons {
+ setButtonBg [subst "\$$button"] 0
+ }
+ }
+
+ ## Set background color for given button acording to given state
+ # @parm Widget button - ID of button to modify
+ # @parm Int state - state number (0 == passive; 1 == active; 2 == semi-active)
+ # @return void
+ private method setButtonBg {button state} {
+ switch $state {
+ 0 {set style {Flat.TButton}}
+ 1 {set style {Todo_Active.TButton}}
+ 2 {set style {Todo_SemiAct.TButton}}
+ }
+
+ $button configure -style $style
+ }
+
+ ## Use given text tag (for selection or next characters)
+ # @parm String tagName - name of text tag
+ # @parm Widget buttonName - ID of button related to that tag
+ # @return void
+ private method addRemoveTag {tagName buttonName} {
+ # Index of given tag in list of active tags
+ set tagIdx [lsearch $active_tags $tagName]
+
+ # Tag is inactive -> add the tag
+ if {$tagIdx == -1} {
+ setButtonBg $buttonName 1
+ lappend active_tags $tagName
+
+ # Tag is active -> remove the tag
+ } {
+ setButtonBg $buttonName 0
+ set active_tags [lreplace $active_tags $tagIdx $tagIdx]
+ }
+
+ # Modify selected area
+ set idxs [getSelectionIdx]
+ if {$idxs != {}} {
+ TodoProc_eraser $idxs 0
+ foreach tag $active_tags {
+ setTagAtSel $tag $idxs
+ }
+ }
+ }
+
+ ## Set given text tag for area determinated by given indexes
+ # @parm String tagName - name of text tag to set
+ # @parm List idxs = {} - target area {first_idx last_idx}
+ # @return Bool - result
+ private method setTagAtSel {tagName idxs} {
+ if {$idxs == {}} {return 0}
+ $text_widget tag add $tagName [lindex $idxs 0] [lindex $idxs 1]
+ return 1
+ }
+
+ ## Get list of indexes of selected area
+ # @return List - text indexes '{first last}' or '{}'
+ private method getSelectionIdx {} {
+ # Try to determinate indexes
+ catch {
+ set start [$text_widget index sel.first]
+ set end [$text_widget index sel.last]
+ }
+ # Return result
+ if {[info exists start]} {
+ return "$start $end"
+ } {
+ return {}
+ }
+ }
+
+ ## Hide search bar
+ # @return void
+ public method TodoProc_hide_find_dialog {} {
+ if {[winfo ismapped $search_frame]} {
+ pack forget $search_frame
+ }
+ }
+
+ ## Show search bar
+ # @return void
+ public method TodoProc_find_dialog {} {
+ if {![winfo ismapped $search_frame]} {
+ pack $search_frame -before $main_frame -side top -anchor w
+ $search_entry delete 0 end
+ focus -force $search_entry
+ } {
+ focus -force $search_entry
+ }
+ }
+
+ ## Search for the given string within the text
+ # @parm String string - Text to find
+ # @return Bool - Always 1
+ public method TodoProc_search {string} {
+ if {$string == {}} {
+ $search_entry configure -style TEntry
+ $search_find_next configure -state disabled
+ $search_find_prev configure -state disabled
+ $menu entryconfigure [::mc "Find next"] -state disabled
+ $menu entryconfigure [::mc "Find previous"] -state disabled
+ return 1
+ }
+ set search_string $string
+ TodoProc_perform_search 1 1.0
+
+ return 1
+ }
+
+ ## Perform search for $search_string in the text widget
+ # @parm Bool forw__back - 1 == Search forwards; 0 == Search backard
+ # @parm String from - Start index
+ # @return void
+ public method TodoProc_perform_search {forw__back from} {
+ if {$search_string == {}} {return}
+
+ if {$forw__back} {
+ set direction {-forwards}
+ } {
+ set direction {-backwards}
+ }
+ if {${::Todo::match_case}} {
+ set last_find_index [$text_widget search $direction -- $search_string $from]
+ } {
+ set last_find_index [$text_widget search $direction -nocase -- $search_string $from]
+ }
+ if {$last_find_index == {}} {
+ $search_entry configure -style StringNotFound.TEntry
+ $search_find_next configure -state disabled
+ $search_find_prev configure -state disabled
+ $menu entryconfigure [::mc "Find next"] -state disabled
+ $menu entryconfigure [::mc "Find previous"] -state disabled
+ } {
+ $search_entry configure -style StringFound.TEntry
+ $search_find_next configure -state normal
+ $search_find_prev configure -state normal
+ $menu entryconfigure [::mc "Find next"] -state normal
+ $menu entryconfigure [::mc "Find previous"] -state normal
+
+ set search_string_length [string length $search_string]
+ $text_widget see $last_find_index
+ catch {
+ $text_widget tag remove sel 0.0 end
+ }
+ $text_widget tag add sel $last_find_index $last_find_index+${search_string_length}c
+ }
+ }
+
+ ## Find next occurence of the search string
+ # @return void
+ public method TodoProc_find_next {} {
+ if {![winfo ismapped $search_frame]} {
+ pack $search_frame -before $main_frame -side top -anchor w
+ }
+ if {$last_find_index == {}} {
+ return
+ }
+ TodoProc_perform_search 1 $last_find_index+${search_string_length}c
+ }
+
+ ## Find previous occurence of the search string
+ # @return void
+ public method TodoProc_find_prev {} {
+ if {![winfo ismapped $search_frame]} {
+ pack $search_frame -before $main_frame -side top -anchor w
+ }
+ if {$last_find_index == {}} {
+ return
+ }
+ TodoProc_perform_search 0 $last_find_index
+ }
+}
diff --git a/lib/cli.tcl b/lib/cli.tcl
new file mode 100755
index 0000000..d423339
--- /dev/null
+++ b/lib/cli.tcl
@@ -0,0 +1,725 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Handle options given by command line interface
+# --------------------------------------------------------------------------
+
+
+# SET COMMMAND LINE OPTIONS TO DEFAULTS
+# --------------------------------------
+set CLI_OPTION(notranslation) 0 ;# Disable i18n
+set CLI_OPTION(quiet) 0 ;# Don't display status of initialization progress on startup
+set CLI_OPTION(nosplash) 0 ;# Don't show splash screen
+set CLI_OPTION(nocolor) 0 ;# Disable color output
+set CLI_OPTION(defaults) 0 ;# Start with default settings
+set CLI_OPTION(minimalized) 0 ;# Start with minimalized window
+set CLI_OPTION(ignore_last) 0 ;# Start with an empty session
+set CLI_OPTION(check_libraries) 0 ;# Check if all nessery Tcl libraries are avaible
+set CLI_OPTION(reset_settings) 0 ;# Reset all user settings to defaults
+set CLI_OPTION(help) 0 ;# Show help message and exit
+set CLI_OPTION(convert) 0 ;# Convert one file to another format
+set CLI_OPTION(no_opt) 0 ;# Disable optimalizations
+set CLI_OPTION(comp_quiet) 0 ;# Suppress compiler console output
+set CLI_OPTION(no_sim) 0 ;# Do not generate SIM file
+set CLI_OPTION(no_bin) 0 ;# Do not generate binary object code
+set CLI_OPTION(no_lst) 0 ;# Do not generate code listing
+set CLI_OPTION(no_hex) 0 ;# Do not generate IHEX8 object code
+set CLI_OPTION(warning_level) 0 ;# Compiler warning level
+set CLI_OPTION(input_output) {} ;# List of file to convert: [0] == input file; [1] == output file
+set CLI_OPTION(compile) {} ;# Compile this asm file and exit
+set CLI_OPTION(open_project) {} ;# Open only project specified by this var if any
+set CLI_OPTION(config_file) {} ;# Specify path to file containg user settings
+set CLI_OPTION(autoindent) {} ;# Specify path to file to indent
+set CLI_OPTION(iram-size) {} ;# Size of internal data memory
+set CLI_OPTION(xram-size) {} ;# Size of external data memory
+set CLI_OPTION(code-size) {} ;# Size of program memory
+set CLI_OPTION(disassemble) {} ;# IHEX8 file to disassemble
+set CLI_OPTION(no-plugins) 0 ;# Disable plugins
+
+
+# ------------------------------------------------------------------------------
+# Microsoft Windows OS specific code
+# ------------------------------------------------------------------------------
+if {$::MICROSOFT_WINDOWS} {
+ # Windows has no terminal control codes (at least I am not aware of them)
+ set CLI_OPTION(nocolor) 1
+}
+# ------------------------------------------------------------------------------
+
+
+# DEFINE FUNCTIONS
+# ------------------
+
+## Only print version information and exit program
+ # @return void
+proc CLI_display_version_and_exit {} {
+ # Load ToolKit
+ if {[catch {package require Tk}]} {
+ libraryLoadFailed {Tk}
+ }
+
+ # Get rid of main window
+ wm withdraw .
+
+ # Display the message
+ puts "\n${::SHORTNAME}:"
+ puts "\tProgram version:\t${::VERSION}"
+ puts "\tTcl version:\t\t${::tcl_version}"
+ puts "\tTk version:\t\t${::tk_version}"
+ exit
+}
+
+## Helper procedure for CLI options --iram-size, --xram-size and --code-size
+ # @parm String option - Command line option without leading dashes (eg. xram-size)
+ # @parm String value - Value taken from CLI
+ # @parm String maximum_in_hex - Maximum value in hexadecimal (eg. 0x10000)
+ # @parm String memtype - Memory type (eg. "external data")
+ # @return void
+proc CLI_set_memory_limit {option value maximum_in_hex memtype} {
+ set arg [string tolower $value]
+ if {[string index $arg end] == {k}} {
+ set arg [string replace $arg end end]
+ set kilo 1
+ } {
+ set kilo 0
+ }
+ if {![string is digit -strict $arg]} {
+ puts stderr "Expected integer after --$option"
+ exit 1
+ }
+ if {$kilo} {
+ set arg [expr {$arg * 1024}]
+ }
+ if {$arg > $maximum_in_hex} {
+ puts stderr "Maximum acceptable size of $memtype memory is $maximum_in_hex ([expr $maximum_in_hex])"
+ exit 1
+ }
+ set CLI_OPTION($option) $arg
+}
+
+## Handle options --hex2bin, --bin2hex, --sim2hex, --sim2bin and --normalize-hex
+ # @parm Int i - index in $argv
+ # @parm Int type - requested type of conversion
+ # 1 - hex2bin
+ # 2 - bin2hex
+ # 3 - sim2hex
+ # 4 - sim2bin
+ # 5 - normalize-hex
+ # @return void
+proc CLI_convert {i type} {
+ global argc ;# Arguments count
+ global argv ;# Arguments list
+
+ # Check if there are all nessesary values available
+ if {($i + 2) >= $argc} {
+ puts "${::APPNAME}"
+ puts stderr "\tERROR: You must specify input and output file"
+ exit 1
+ }
+
+ # Set CLI options array
+ set ::CLI_OPTION(input_output) {}
+ set ::CLI_OPTION(convert) $type
+ lappend ::CLI_OPTION(input_output) [lindex $argv [expr {$i + 1}]]
+ lappend ::CLI_OPTION(input_output) [lindex $argv [expr {$i + 2}]]
+
+ # Check for validity of given data
+
+ # * input file must be readable
+ set file [lindex $argv [expr {$i + 1}]]
+ if {[file isdirectory $file] || ![file exists $file] || (!$::MICROSOFT_WINDOWS && ![file readable $file])} {
+ puts "${::APPNAME}"
+ puts stderr "\tERROR: Unable to read file '[lindex $argv [expr {$i + 1}]]'"
+ exit 1
+ }
+ # * output file must be writable if exists
+ set file [lindex $argv [expr {$i + 2}]]
+ if {[file exists $file]} {
+ if {
+ [file isdirectory $file] ||
+ ![file writable $file]
+ } {
+ puts "${::APPNAME}"
+ puts stderr "\tERROR: Unable to write to file '$file'"
+ exit 1
+ }
+ }
+}
+
+## Get next argument (some file) and store it in the given variable
+ # @parm Int i - Index of the current command line argument
+ # @parm String option - Command line option (for error message)
+ # @parm String key - Key in array 'CLI_OPTION'
+ # @return void
+proc CLI_next_arg {i option key} {
+ global argc ;# Arguments count
+ global argv ;# Arguments list
+
+ # Check if the next argument (some file) is available
+ incr i
+ if {$i >= $argc} {
+ puts "${::APPNAME}"
+ puts stderr "\tERROR: Expected filename after $option"
+ exit 1
+ }
+
+ # Set CLI option
+ set ::CLI_OPTION($key) [file normalize [lindex $argv $i]]
+
+ # Check if the specified file does exist
+ if {
+ [file isdirectory $::CLI_OPTION($key)] ||
+ ![file exists $::CLI_OPTION($key)] ||
+ (!$::MICROSOFT_WINDOWS && ![file readable $::CLI_OPTION($key)])]
+ } {
+ puts "${::APPNAME}"
+ puts stderr "\tERROR: Unable to read file '$::CLI_OPTION($key)'"
+ exit 1
+ }
+}
+
+# PARSE COMMAND LINE OPTIONS
+# --------------------------
+
+if {$argc} {
+ # iterate over all given arguments
+ for {set i 0} {$i < $argc} {incr i} {
+ set arg [lindex $argv $i]
+
+ # decide what to do with each of them
+ switch -- $arg {
+
+ {--help} { ;# Display help message only
+ set CLI_OPTION(help) 1
+ }
+ {-h} { ;# Display help message only
+ set CLI_OPTION(help) 1
+ }
+ {--quiet} { ;# Don't display initialization progress on startup
+ set CLI_OPTION(quiet) 1
+ }
+ {--no-translation} { ;# Disable i18n
+ set CLI_OPTION(notranslation) 1
+ }
+ {--no-i18n} { ;# Disable i18n
+ set CLI_OPTION(notranslation) 1
+ }
+ {-q} { ;# Don't display initialization progress on startup
+ set CLI_OPTION(quiet) 1
+ }
+ {--nosplash} { ;# Don't show splash screen
+ set CLI_OPTION(nosplash) 1
+ }
+ {--nocolor} { ;# Disable color output
+ set CLI_OPTION(nocolor) 1
+ }
+ {-n} { ;# Disable color output
+ set CLI_OPTION(nocolor) 1
+ }
+ {--version} { ;# Display version information
+ CLI_display_version_and_exit
+ }
+ {-V} { ;# Display version information
+ CLI_display_version_and_exit
+ }
+ {--defaults} { ;# Start with default settings
+ set CLI_OPTION(defaults) 1
+ }
+ {--minimalized} { ;# Start with minimalized window
+ set CLI_OPTION(minimalized) 1
+ }
+ {--check-libraries} { ;# Check if all nessery Tcl libraries are avaible
+ set CLI_OPTION(check_libraries) 1
+ }
+ {--ignore-last-session} { ;# Start with and empty session
+ set CLI_OPTION(ignore_last) 1
+ }
+ {--open-project} { ;# Open only this project
+ CLI_next_arg $i {--open-project} {open_project}
+ incr i
+ }
+ {--config-file} { ;# Specify path to file containg user settings
+ CLI_next_arg $i {--config-file} {config_file}
+ incr i
+ }
+ {--compile} { ;# Compile asm file and exit
+ CLI_next_arg $i {--compile} {compile}
+ incr i
+ }
+ {--reset-user-settings} { ;# Reset all user settings to defaults
+ set CLI_OPTION(reset_settings) 1
+ }
+ {--hex2bin} { ;# Convert Intel Hex 8 file to binary file
+ CLI_convert $i 1
+ incr i 2
+ }
+ {--bin2hex} { ;# Convert binary file to Intel Hex 8 file
+ CLI_convert $i 2
+ incr i 2
+ }
+ {--sim2hex} { ;# Convert simulator file to Intel Hex 8 file
+ CLI_convert $i 3
+ incr i 2
+ }
+ {--sim2bin} { ;# Convert simulator file to binary file
+ CLI_convert $i 4
+ incr i 2
+ }
+ {--normalize-hex} { ;# Normalize IHEX8 file
+ CLI_convert $i 5
+ incr i 2
+ }
+ {--auto-indent} { ;# Reformat indention
+ CLI_next_arg $i {--auto-indent} {autoindent}
+ incr i
+ }
+ {--iram-size} { ;# Set size of internal data memory
+ incr i
+ CLI_set_memory_limit {iram-size} [lindex $argv $i] 0x100 {internal data}
+ }
+ {--xram-size} { ;# Set size of external data memory
+ incr i
+ CLI_set_memory_limit {xram-size} [lindex $argv $i] 0x10000 {external data}
+ }
+ {--code-size} { ;# Set size of program memory
+ incr i
+ CLI_set_memory_limit {code-size} [lindex $argv $i] 0x10000 {code}
+ }
+ {--no-opt} { ;# Disable optimalizations
+ set CLI_OPTION(no_opt) 1
+ }
+ {--comp-quiet} { ;# Suppress compiler console output
+ set CLI_OPTION(comp_quiet) 1
+ }
+ {--no-sim} { ;# Do not generate SIM file
+ set CLI_OPTION(no_sim) 1
+ }
+ {--no-bin} { ;# Do not generate binary object code
+ set CLI_OPTION(no_bin) 1
+ }
+ {--no-lst} { ;# Do not generate code listing
+ set CLI_OPTION(no_lst) 1
+ }
+ {--no-hex} { ;# Do not generate IHEX8 object code
+ set CLI_OPTION(no_hex) 1
+ }
+ {--warning-level} { ;# Compiler warning level
+ incr i
+ set arg [lindex $argv $i]
+ if {$arg != {0} && $arg != {1} && $arg != {2} && $arg != {3}} {
+ puts stderr "Bad value for option --warning-level, possible values are {0 1 2 3}"
+ exit 1
+ }
+ set CLI_OPTION(warning_level) $arg
+ }
+ {--disassemble} { ;# Disaseble IHEX8 code
+ CLI_next_arg $i {--disassemble} {disassemble}
+ incr i
+ }
+ {--no-plugins} { ;# Disable plugins
+ set CLI_OPTION(no-plugins) 1
+ }
+ default { ;# Unknown option -- terminate program
+ puts stderr "Unknown command line option: '$arg'"
+ exit 1
+ }
+ }
+ }
+}
+
+# HANDLE CLI OPTIONS WHICH REQUIRE INSTANT RESPONSE
+# --------------------------------------------------
+
+# Display help message and exit
+if {$CLI_OPTION(help)} {
+ puts "\n${::APPNAME}"
+ puts "IDE for MSC-51 based microcontrolers.\n"
+ if {$CLI_OPTION(nocolor)} {
+ puts "Options:"
+ set clr_end {}
+ set clr_opt {}
+ set clr_arg {}
+ } {
+ puts "\033\[1mOptions:\033\[m"
+ set clr_end "\033\[m"
+ set clr_opt "\033\[32m"
+ set clr_arg "\033\[33;1m"
+ }
+ puts "\t${clr_opt}--no-translation${clr_end},\tDisplay program language translation\n\t${clr_opt}--no-i18n${clr_end}"
+ puts "\t${clr_opt}--help${clr_end}, ${clr_opt}-h${clr_end}\t\tDisplay this message"
+ puts "\t${clr_opt}--quiet${clr_end}, ${clr_opt}-q${clr_end}\t\tDon't display status of initialization progress on startup"
+ puts "\t${clr_opt}--no-plugins${clr_end}\t\tDisable plugins"
+ puts "\t${clr_opt}--nosplash${clr_end}\t\tDon't show splash screen"
+ puts "\t${clr_opt}--nocolor${clr_end}, ${clr_opt}-n${clr_end}\t\tDisable color output"
+ puts "\t${clr_opt}--version${clr_end}, ${clr_opt}-V${clr_end}\t\tDisplay version information"
+ puts "\t${clr_opt}--defaults${clr_end}\t\tStart with default settings (low level GUI settings (panel sizes ...))"
+ puts "\t${clr_opt}--minimalized${clr_end}\t\tStart with minimalized window"
+ puts "\t${clr_opt}--config-file ${clr_arg}filename${clr_end}\tSpecify path to file containg user settings"
+ puts "\t${clr_opt}--check-libraries${clr_end}\tCheck if all nessesary Tcl libraries are avaible"
+ puts "\t${clr_opt}--ignore-last-session${clr_end}\tStart with an empty session (no project will be opened at startup)"
+ puts "\t${clr_opt}--open-project ${clr_arg}project${clr_end}\tOpen only this project"
+ puts "\t${clr_opt}--reset-user-settings${clr_end}\tReset all user settings to defaults"
+ puts ""
+ puts "\t${clr_opt}--auto-indent ${clr_arg}input${clr_end}\tReformat indention in source code"
+ puts "\t${clr_opt}--hex2bin ${clr_arg}input output${clr_end}\tConvert Intel Hex 8 file to binary file"
+ puts "\t${clr_opt}--bin2hex ${clr_arg}input output${clr_end}\tConvert binary file to Intel Hex 8 file"
+ puts "\t${clr_opt}--sim2hex ${clr_arg}input output${clr_end}\tConvert ${::APPNAME} simulator file to Intel Hex 8 file"
+ puts "\t${clr_opt}--sim2bin ${clr_arg}input output${clr_end}\tConvert ${::APPNAME} simulator file to binary file"
+ puts "\t${clr_opt}--normalize-hex ${clr_arg}input${clr_end}\tNormalize IHEX8 file"
+ puts ""
+ puts "\t${clr_opt}--disassemble ${clr_arg}hex_file${clr_end}\tDisaseble IHEX8 code to ${clr_arg}hex_file.asm${clr_end}"
+ puts "\t${clr_opt}--compile ${clr_arg}asm_file${clr_end}\tCompile asm file and exit"
+ puts "\t${clr_opt}--iram-size ${clr_arg}size${clr_end}\tSet size of internal data memory\t(eg. 1K or 1024) (default: 0x100)"
+ puts "\t${clr_opt}--code-size ${clr_arg}size${clr_end}\tSet size of program memory\t\t(eg. 1K or 1024) (default: 0x10000)"
+ puts "\t${clr_opt}--xram-size ${clr_arg}size${clr_end}\tSet size of external data memory\t(eg. 1K or 1024) (default: 0x10000)"
+ puts "\t${clr_opt}--no-opt${clr_end}\t\tDisable optimalizations"
+ puts "\t${clr_opt}--comp-quiet${clr_end}\t\tSuppress compiler console output"
+ puts "\t${clr_opt}--no-sim${clr_end}\t\tDo not generate SIM file (for MCU 8051 IDE simulator)"
+ puts "\t${clr_opt}--no-bin${clr_end}\t\tDo not generate binary object code"
+ puts "\t${clr_opt}--no-lst${clr_end}\t\tDo not generate code listing"
+ puts "\t${clr_opt}--no-hex${clr_end}\t\tDo not generate IHEX8 object code"
+ puts "\t${clr_opt}--warning-level ${clr_arg}N${clr_end}\tSet compiler warning level"
+ puts "\t\t${clr_arg}3${clr_end} - Nothing"
+ puts "\t\t${clr_arg}2${clr_end} - Errros only"
+ puts "\t\t${clr_arg}1${clr_end} - Errors + Warnings"
+ puts "\t\t${clr_arg}0${clr_end} - All (Default)"
+ puts ""
+ exit
+}
+
+# Convert some file to another
+if {$CLI_OPTION(convert)} {
+ puts "${::APPNAME}"
+
+ # Import required code
+ package require md5 2.0.1
+ source "${::LIB_DIRNAME}/lib/Math.tcl"
+ source "${::LIB_DIRNAME}/lib/ihextools.tcl"
+
+ # Set input and output file names
+ set input [lindex $CLI_OPTION(input_output) 0]
+ set output [lindex $CLI_OPTION(input_output) 1]
+
+ # Make backup for target file if that file does already exist
+ if {[file exists $output]} {
+ puts "Creating backup for $output -> $output~"
+ file rename -force $output "$output~"
+ }
+ puts "Converting ..."
+
+ # Open input and output file
+ set input [open $input {r}]
+ set output [open $output {w} 420]
+ fconfigure $input -translation binary
+ fconfigure $output -translation binary
+
+ # Decide what to do
+ switch -- $CLI_OPTION(convert) {
+ 1 { ;# Hex -> Bin
+ ::IHexTools::load_hex_data [read $input]
+ if {!${::IHexTools::error_count}} {
+ puts -nonewline $output [::IHexTools::get_bin_data]
+ }
+ }
+ 2 { ;# Bin -> Hex
+ ::IHexTools::load_bin_data [read $input]
+ if {!${::IHexTools::error_count}} {
+ puts -nonewline $output [::IHexTools::get_hex_data]
+ }
+ }
+ 3 { ;# Sim -> Hex
+ ::IHexTools::load_sim_data [read $input]
+ if {!${::IHexTools::error_count}} {
+ puts -nonewline $output [::IHexTools::get_hex_data]
+ }
+ }
+ 4 { ;# Sim -> Bin
+ ::IHexTools::load_sim_data [read $input]
+ if {!${::IHexTools::error_count}} {
+ puts -nonewline $output [::IHexTools::get_bin_data]
+ }
+ }
+ 5 { ;# Hex -> Hex
+ ::IHexTools::load_hex_data [read $input]
+ if {!${::IHexTools::error_count}} {
+ puts -nonewline $output [::IHexTools::get_hex_data]
+ }
+ }
+ default { ;# Something went wrong
+ puts stderr "FATAL INTERNAL ERROR - invalid value of \$CLI_OPTION(convert)"
+ exit 1
+ }
+ }
+
+ if {${::IHexTools::error_count}} {
+ puts "FAILED !"
+ puts ${::IHexTools::error_string}
+ } {
+ puts "Successful"
+ }
+
+ exit
+}
+
+if {$CLI_OPTION(autoindent) != {}} {
+ puts "${::APPNAME}"
+
+ # Import nessesary code
+ package require md5 2.0.1
+ source "${::LIB_DIRNAME}/X.tcl"
+ source "${::LIB_DIRNAME}/syntaxhighlight.tcl"
+
+ # Make backup for target file if that file does already exist
+ if {[file exists $CLI_OPTION(autoindent)]} {
+ puts "Creating backup for $CLI_OPTION(autoindent) -> $CLI_OPTION(autoindent)~"
+ file rename -force $CLI_OPTION(autoindent) "$CLI_OPTION(autoindent)~"
+
+ # Ensure than the file is writable
+ if {![file writable $CLI_OPTION(autoindent)]} {
+ puts "Error: Cannot write to the given file"
+ exit 1
+ }
+ }
+ puts "Formating ..."
+
+ # Load and reformat file content
+ set ::X::reformat_code_abort 0
+ set ::X::compilation_progress 0
+ set file [open $CLI_OPTION(autoindent) r]
+ set data [::X::reformat_code_core [read $file]]
+ close $file
+
+ # Save file
+ set file [open $CLI_OPTION(autoindent) w 420]
+ puts -nonewline $file $data
+ close $file
+
+ # Done ...
+ puts "Done"
+ exit
+}
+
+# Disassemble code
+if {$CLI_OPTION(disassemble) != {}} {
+ # Import required sources
+ source "${::LIB_DIRNAME}/lib/Math.tcl" ;# Special mathematical operations
+ source "${::LIB_DIRNAME}/compiler/compiler.tcl" ;# 8051 Assemly language compiler
+ source "${::LIB_DIRNAME}/lib/ihextools.tcl" ;# Tools for manipulating with IHEX8
+
+ # Other compiler settings
+ set Compiler::Settings::NOCOLOR $CLI_OPTION(nocolor)
+
+ # Open source and destination files
+ if {[catch {
+ set src_file [open $CLI_OPTION(disassemble) {r}]
+ set trg_file [open [file rootname $CLI_OPTION(disassemble)].asm w 420]
+ }]} {
+ puts stderr "Unable to open either \"$CLI_OPTION(disassemble)\" or \"[file rootname $CLI_OPTION(disassemble)].asm\""
+ exit 1
+ }
+
+ # Initialize disassembler
+ puts ""
+ ::IHexTools::load_hex_data [read $src_file]
+ if {!${::IHexTools::error_count} && !${::IHexTools::abort}} {
+ puts -nonewline $trg_file [disassembler::compile [::IHexTools::get_hex_data]]
+ }
+
+ # Write error messages
+ if {${::IHexTools::error_count}} {
+ puts ${::IHexTools::error_string}
+ if {$CLI_OPTION(nocolor)} {
+ puts "Decompilation FAILED"
+ } {
+ puts "\033\[31;1mDecompilation FAILED\033\[m"
+ }
+ }
+
+ if {$CLI_OPTION(nocolor)} {
+ puts "Result stored in \"[file rootname $CLI_OPTION(disassemble)].asm\"\n"
+ } {
+ puts "Result stored in \"\033\[34;1m[file rootname $CLI_OPTION(disassemble)].asm\033\[m\"\n"
+ }
+
+ # Close source and destination files
+ close $src_file
+ close $trg_file
+
+ exit
+}
+
+# Compile asm source and exit
+if {$CLI_OPTION(compile) != {}} {
+ # Import required sources
+ package require md5 2.0.1
+ source "${::LIB_DIRNAME}/lib/Math.tcl" ;# Special mathematical operations
+ source "${::LIB_DIRNAME}/compiler/compiler.tcl" ;# 8051 Assemly language compiler
+ source "${::LIB_DIRNAME}/lib/ihextools.tcl" ;# Tools for manipulating with IHEX8
+
+ # Determinate working directory and input file
+ set directory [file dirname $CLI_OPTION(compile)]
+ set filename [regsub {\.[^\.]*$} [file tail $CLI_OPTION(compile)] {}]
+ set extension [string replace [file extension $CLI_OPTION(compile)] 0 0]
+
+ # Set memory limits
+ if {$CLI_OPTION(iram-size) != {}} {
+ set Compiler::Settings::iram_size $CLI_OPTION(iram-size)
+ }
+ if {$CLI_OPTION(code-size) != {}} {
+ set Compiler::Settings::code_size $CLI_OPTION(code-size)
+ }
+ if {$CLI_OPTION(xram-size) != {}} {
+ set Compiler::Settings::xram_size $CLI_OPTION(xram-size)
+ }
+
+ # Enable / Disable optimalizations
+ if {$CLI_OPTION(no_opt)} {
+ set Compiler::Settings::optim_ena 0
+ }
+ # Suppress compiler console output
+ set Compiler::Settings::QUIET $CLI_OPTION(comp_quiet)
+ # Compiler warning level
+ set Compiler::Settings::WARNING_LEVEL $CLI_OPTION(warning_level)
+ # Do not generate SIM file
+ set Compiler::Settings::CREATE_SIM_FILE [expr {!$CLI_OPTION(no_sim)}]
+ # Do not generate binary object code
+ set Compiler::Settings::CREATE_BIN_FILE [expr {!$CLI_OPTION(no_bin)}]
+ # Do not generate IHEX8 object code
+ if {$CLI_OPTION(no_hex)} {
+ set Compiler::Settings::_object 2
+ }
+ # Do not generate code listing
+ if {$CLI_OPTION(no_lst)} {
+ set Compiler::Settings::_print 2
+ }
+ # Other compiler settings
+ set Compiler::Settings::NOCOLOR $CLI_OPTION(nocolor)
+
+ # Initialize compiler
+ set result [Compiler::compile $directory $directory $filename $extension]
+
+ # Exit acording to compilation result
+ exit [expr {!$result}]
+}
+
+# Check if all nessery Tcl libraries are avaible
+if {$CLI_OPTION(check_libraries)} {
+
+ # Local varibale
+ set librariesToCheck [llength $LIBRARIES_TO_LOAD] ;# Number of libs to check
+ set failsVer 0 ;# Number of libraries which didn't pass version check
+ set failsLib 0 ;# Number of libraries which could not be found
+ set failsTotal 0 ;# Number of fails tottaly
+
+ puts "$APPNAME\n"
+ puts "\tChecking libraries..."
+
+ # Iterate over list of needed libraries
+ for {set i 0} {$i < $librariesToCheck} {incr i} {
+ # Local variables
+ set library [lindex $LIBRARIES_TO_LOAD "$i 0"] ;# Library name
+ set version [lindex $LIBRARIES_TO_LOAD "$i 1"] ;# Library version
+
+ # Print what library is currently being checked
+ if {$CLI_OPTION(nocolor)} {
+ puts "\t\t[expr {$i + 1}]/$librariesToCheck Checking for library $library"
+ } {
+ puts "\t\t\033\[33m[expr {$i + 1}]/$librariesToCheck\033\[m \033\[37mChecking for library\033\[m \033\[32m$library\033\[m"
+ }
+
+ # Perform presence check and diplay result
+ puts -nonewline "\t\t\tLibrary present\t... "
+ flush stdout
+ if {[catch {package require $library}]} {
+ if {$CLI_OPTION(nocolor)} {
+ puts "NO !"
+ } {
+ puts "\033\[31;01mNO !\033\[m"
+ }
+ incr failsLib
+ } {
+ if {$CLI_OPTION(nocolor)} {
+ puts "YES"
+ } {
+ puts "\033\[32;01mYES\033\[m"
+ }
+ }
+
+ # Perform version check and diplay result
+ if {$CLI_OPTION(nocolor)} {
+ puts -nonewline "\t\t\tVersion $version\t... "
+ } {
+ puts -nonewline "\t\t\tVersion \033\[36m$version\033\[m\t... "
+ }
+ flush stdout
+ if {[catch {package require $library $version}]} {
+ if {$CLI_OPTION(nocolor)} {
+ puts "NO !"
+ } {
+ puts "\033\[31;01mNO !\033\[m"
+ }
+ incr failsVer
+ } {
+ if {$CLI_OPTION(nocolor)} {
+ puts "YES"
+ } {
+ puts "\033\[32;01mYES\033\[m"
+ }
+ }
+ }
+
+ # Determinate number of total fails
+ if {$failsVer > $failsLib} {
+ set failsTotal $failsVer
+ } {
+ set failsTotal $failsLib
+ }
+
+ # Print final results
+ puts "\n\tRESULTS:"
+ if {$failsTotal} {
+ # FAILED
+ if {$CLI_OPTION(nocolor)} {
+ puts "\t\tNumber of fails: $failsTotal"
+ puts "\t\tPROGRAM WILL NOT RUN, please install the missing libraries"
+ } {
+ puts "\t\tNumber of fails: \033\[31m$failsTotal\033\[m"
+ puts "\t\t\033\[31;01mPROGRAM WILL NOT RUN\033\[m, please install the missing libraries"
+ }
+ } {
+ # SUCCESSFUL
+ if {$CLI_OPTION(nocolor)} {
+ puts "\t\tNumber of fails: $failsTotal"
+ puts "\t\tEverything seems ok"
+ } {
+ puts "\t\tNumber of fails: \033\[32;01m$failsTotal\033\[m"
+ puts "\t\t\033\[32mEverything seems ok\033\[m"
+ }
+ }
+ puts {}
+
+ # done ...
+ exit
+}
diff --git a/lib/compiler/assembler.tcl b/lib/compiler/assembler.tcl
new file mode 100755
index 0000000..5c41a28
--- /dev/null
+++ b/lib/compiler/assembler.tcl
@@ -0,0 +1,595 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Coverts precompiled source code to IHEX 8 format.
+#
+# This code is part of compiler (see compiler.tcl), precompiled code is
+# generated by precompiler (see precomiler.tcl).
+#
+# --------------------------------------------------------------------------
+# OUTPUT FORMATS:
+# - Intel® HEX 8
+# - Binary string
+# - MCU 8051 IDE Simulator data file
+#
+# --------------------------------------------------------------------------
+# FORMAT DETAILS:
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# MCU 8051 IDE Assembler debug file
+# hash file [hash file [hash file ...]] # comment
+# filenum line address code [code [code ...]] # another comment
+# ...
+# hash - Hexadecimal MD5 hash of source code
+# file - Filename of source code
+# filenum - File number (begining from 0)
+# line - Number of line in source code
+# address - Code address
+# code - Processor code
+#
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Intel HEX 8
+# :LLAAAATTDD->CC
+# ...
+# ...
+# :00000001FF
+# LL - 8-bit length of data field (for instance '11' means 17 bytes)
+# AAAA - 16-bit address
+# TT - 8-bit type:
+# 00 - data
+# 01 - EOF (End Of File), ussualy ':00000001FF'
+# DD-> - X x 8-bit data
+# CC - checksum:
+# 0x100 - LL - AA(h) - AA(l) - TT - DD ...
+# --------------------------------------------------------------------------
+
+namespace eval assembler {
+
+ ## PUBLIC
+ variable hex ;# Output IHEX8 data
+ variable adf ;# Output simulator data
+ variable bin ;# Output binary data
+ variable error_count ;# Errors count
+
+ ## PRIVATE
+ variable fileNumber ;# File number
+ variable lineNumber ;# Number of line currently beeing parsed
+ variable offset ;# Current address
+ variable data_len ;# Data length (for creating IHEX records)
+ variable data_field ;# Data field (for creating IHEX records)
+ variable address ;# Address of begining of IHEX data field
+ variable operands ;# List of operand codes
+ variable opcode ;# OP code of the current instruction
+ variable bin_len ;# Lenght of binary data
+ variable opr_types ;# List of operand types
+ variable included_files ;# List: Unique unsorted list of included files
+ variable working_dir ;# String: Project working directory
+
+
+ # ----------------------------------------------------------------
+ # GENERAL PURPOSE PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Compile the given code
+ # @parm String md5 - Source code MD5 (hexadecimal hash)
+ # @parm String date - Current date
+ # @parm String project_dir - Project directory
+ # @parm String name - Name of source file
+ # @parm List files - List of included files (1st one is primary source file)
+ # @parm List code - Precompiled source code (code generated by preprocessor)
+ # @return Bool - result (1 == success; 0 == fail)
+ proc compile {md5 date project_dir name files code} {
+ variable working_dir $project_dir ;# String: Project working directory
+ variable included_files $files ;# List: Unique unsorted list of included files
+ variable fileNumber 0 ;# File number
+ variable lineNumber 0 ;# Number of line currently beeing parsed
+ variable opcode ;# OP code of the current instruction
+ variable operands ;# List of operand codes
+ variable address ;# Address of begining of IHEX data field
+ variable opr_types ;# List of operand types
+ variable offset 0 ;# Current address
+ variable data_len 0 ;# Data length (for creating IHEX records)
+ variable data_field {} ;# Data field (for creating IHEX records)
+ variable hex {} ;# Output IHEX8 data
+ variable adf {} ;# Output simulator data
+ variable bin {} ;# Output binary data
+ variable error_count 0 ;# Errors count
+ variable bin_len 0 ;# Lenght of binary data
+
+ # Local variables
+ set idx -1 ;# Current line in precompiled code
+ set nolist 0 ;# Bool: Do not crete record in code listing for the current line
+ set pointer 0 ;# Expected address
+
+ # Create header of simulator data
+ if {${::Compiler::Settings::CREATE_SIM_FILE}} {
+ set filename [file join $project_dir $name]
+ set project_dir_len [string length [file normalize $project_dir]]
+ if {[string first $project_dir $name] != -1} {
+ set filename [string replace $filename 0 $project_dir_len]
+ }
+
+ set adf "# Assembler debug file for ${::APPNAME}\n"
+ append adf "# Used assembler: MCU 8051 IDE\n"
+ append adf "# Date: $date\n"
+ set project_dir_len [string length $project_dir]
+ foreach filename $included_files {
+ if {[catch {
+ append adf [::md5::md5 -hex -file $filename]
+ } result]} {
+ append adf 0
+ CompilationError [mc "File access error:\n%s" $result]
+ }
+ if {![string first $project_dir $filename]} {
+ set filename [string replace $filename 0 $project_dir_len]
+ }
+ append adf { "} $filename {" }
+ }
+ }
+
+ # Iterate over precompiled code
+ foreach line $code {
+
+ # Update GUI after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}][mc "Aborted"]
+ free_resources
+ return
+ }
+
+ incr idx
+ set nolist 0
+
+ # Parse line
+ set lineNumber [lindex $line 0] ;# Line in source code (dec)
+ set fileNumber [lindex $line 1] ;# Number of file
+ set address [lindex $line 2] ;# Address (dec)
+ set instruction [lindex $line 3] ;# Instruction name (or directive)
+ set operands [lindex $line 4] ;# List of operands
+ set opr_types [lindex $line 5] ;# List of operand types
+
+ # Directive 'DB'
+ if {$instruction == {db}} {
+ set len 1
+ set opcode [lindex $operands 0]
+ set mask 0
+ set operands {}
+ if {$opcode == { }} {
+ set opcode 32
+ }
+ set opcode [format %X $opcode]
+ set digits [string length $opcode]
+ if {$digits < 2} {
+ set opcode "0$opcode"
+ } elseif {$digits > 2} {
+ CompilationError [mc "Unknown error %s" 100]
+ continue
+ }
+
+ set nolist 1
+ } {
+ # Check for instruction existence
+ if {[notAnInstruction $instruction]} {continue}
+
+ # Find matching operand set
+ set definition [find_instruction_definition $instruction]
+ if {$definition == {}} {continue}
+ set len [lindex $definition 1]
+ set opcode [lindex $definition 2]
+ set mask [lindex $definition 3]
+ }
+
+ # First line
+ if {$pointer == 0} {
+ set offset $address
+ }
+
+ # If data length overlaps 255 or adress is too high -> flush data buffer
+ if {($pointer < $address) || (($data_len + $len) > ${::Compiler::Settings::max_ihex_rec_length})} {
+ write_bin
+ write_hex
+ set data_len 0
+ set offset $address
+ set pointer $address
+
+ # Unexpected adress
+ } elseif {$pointer > $address} {
+ CompilationError [mc "Invalid address at %s" 0x[format %X $address]]
+ set pointer $address
+ continue
+ }
+
+ incr pointer $len ;# Expected address
+ incr data_len $len ;# Data length
+
+ #
+ ## Calculate processor code
+ #
+
+ # Translate operands to 16|12|8-bit hex
+ set operands [oprs2hex]
+
+ # Adjust inctruction OP code acording to the OP code mask and operands
+ if {$mask != 0} {
+ # Determinate length of the first operand
+ set mask_bin [hex2binlist $mask]
+ set opr_len 8
+ foreach bit $mask_bin {
+ if {$bit} {incr opr_len}
+ }
+
+ # Translate OP code to list of booleans
+ set opcode [hex2binlist $opcode]
+ # Determinate the 1st operand
+ set operand0 [NumSystem::hex2bin [lindex $operands 0]]
+
+ # Adjust operand
+ set true_opr_len [string length $operand0]
+ if {$opr_len > $true_opr_len} {
+ set operand0 "[string repeat 0 [expr {$opr_len - $true_opr_len}]]$operand0"
+ } elseif {$opr_len < $true_opr_len} {
+ CompilationError [mc "Unknown error %s" 101]
+ continue
+ }
+ incr opr_len -9
+ set opcode_opr [string range $operand0 0 $opr_len]
+ incr opr_len
+ set operand0 [string range $operand0 $opr_len end]
+
+ # Adjust OP code
+ set idx 0
+ foreach mask_bit $mask_bin {
+ if {$mask_bit} {
+ set opcode [lreplace $opcode $idx $idx [lindex $opcode_opr $idx]]
+ }
+ incr idx
+ }
+
+ # Finalize
+ set opcode [NumSystem::bin2hex [join $opcode {}]]
+ if {[string length $opcode] == 1} {
+ set opcode "0$opcode"
+ }
+ set operand0 [NumSystem::bin2hex $operand0]
+ if {[string length $operand0] == 1} {
+ set operand0 "0$operand0"
+ }
+ set operands [lreplace $operands 0 0 $operand0]
+ }
+
+ # Write simulator data line
+ write_adf
+
+ # Append processor code to data_field
+ set opcode [string toupper $opcode]
+
+ # Exception for instruction MOV addr, addr (Reverse order of operands)
+ if {$opcode == {85}} {
+ append opcode [lindex $operands 1]
+ append opcode [lindex $operands 0]
+ # Other instructions
+ } {
+ foreach opr $operands {
+ append opcode $opr
+ }
+ }
+ append data_field $opcode
+
+ # Write line to code listing
+ if {!$nolist} {
+ CodeListing::set_opcode $idx $opcode
+ }
+ }
+
+ # Finalize
+ write_bin
+ write_hex
+ if {${::Compiler::Settings::OBJECT}} {
+ append hex {:00000001FF}
+ }
+
+ # Return result
+ if {$error_count} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Free resoureces (should be called after each compilation)
+ # @return void
+ proc free_resources {} {
+ foreach var {
+ hex adf bin
+ lineNumber offset data_len
+ data_field address operands
+ opcode bin_len error_count
+ fileNumber
+ } {
+ set ::assembler::$var {}
+ }
+ }
+
+
+ # ----------------------------------------------------------------
+ # INTERNAL AUXILIARY PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Convert the given hexadecimal value to list of booleans
+ # @parm String value - Hexadecimal number to convert
+ # @return List - Resulting list of booleans (eg. {0 1 0 1 1 1 0 1})
+ proc hex2binlist {value} {
+ set value [NumSystem::hex2bin $value]
+ set len [string length $value]
+ if {$len != 8} {
+ set value "[string repeat 0 [expr {8 - $len}]]$value"
+ }
+ return [split $value {}]
+ }
+
+ ## Write line to simulator data string
+ # @return void
+ proc write_adf {} {
+ variable adf ;# Output simulator data
+ variable fileNumber ;# File number
+ variable lineNumber ;# Number of line currently beeing parsed
+ variable address ;# Address of begining of IHEX data field
+ variable opcode ;# OP code of the current instruction
+ variable operands ;# List of operand codes
+
+ if {!${::Compiler::Settings::CREATE_SIM_FILE}} {return}
+
+ # Convert operands to decimal
+ set new_code {}
+ lappend new_code [expr "0x$opcode"]
+
+ # Exception for instruction MOV addr, addr (Reverse order of operands)
+ if {$opcode == {85} && [llength $operands] == 2} {
+ lappend new_code [expr "0x[lindex $operands 1]"]
+ lappend new_code [expr "0x[lindex $operands 0]"]
+ # Other instructions
+ } {
+ foreach hex $operands {
+ if {[string length $hex] == 4} {
+ lappend new_code [expr "0x[string range $hex 0 1]"]
+ lappend new_code [expr "0x[string range $hex 2 3]"]
+ } {
+ lappend new_code [expr "0x$hex"]
+ }
+ }
+ }
+
+ # Append new value
+ append adf "\n" $fileNumber { } $lineNumber { } $address { } $new_code
+ }
+
+ ## Write data field as binary string
+ # @return void
+ proc write_bin {} {
+ variable offset ;# Current address
+ variable data_field ;# Data field (for creating IHEX records)
+ variable data_len ;# Data length (for creating IHEX records)
+ variable bin ;# Output binary data
+ variable bin_len ;# Lenght of binary data
+
+ if {!${::Compiler::Settings::CREATE_BIN_FILE}} {return}
+
+ # Create padding
+ if {$offset > $bin_len} {
+ set diff [expr {$offset - $bin_len}]
+ append bin [string repeat "\x00" $diff]
+ incr bin_len $diff
+
+ } elseif {$offset < $bin_len} {
+ CompilationError [mc "Unknown error %s" 102]
+ }
+
+ # Write binary data
+ for {set i 0; set j 1} {$i < $data_len} {incr i 2; incr j 2} {
+ set hex [string range $data_field $i $j]
+ append bin [subst "\\x$hex"]
+ incr bin_len
+ }
+ }
+
+ ## Write data field as IHEX record
+ # @return
+ proc write_hex {} {
+ variable data_len ;# Data length (for creating IHEX records)
+ variable offset ;# Current address
+ variable data_field ;# Data field (for creating IHEX records)
+ variable hex ;# Output IHEX8 data
+
+ if {!${::Compiler::Settings::OBJECT}} {return}
+
+ # Create fields length and address
+ set len_field [dec2hex $data_len 2]
+ set addr_field [dec2hex $offset 4]
+
+ # Create IHEX8 record
+ set line ${len_field}
+ append line ${addr_field} {00} ${data_field}
+ set check_field [::IHexTools::getCheckSum $line]
+ append line $check_field
+
+ # Append created record to resulting string
+ append hex {:}
+ append hex $line
+ append hex "\n"
+
+ # Reset data field
+ set data_field {}
+ }
+
+ ## Convert decimal value to hexadecimal string
+ # @parm Int value - Number to convert
+ # @parm Int length - Length of resuting hexadecimal string
+ # @return String - result
+ proc dec2hex {value length} {
+
+ # Convert and determinate length
+ set value [format %X $value]
+ set true_length [string length $value]
+
+ # Adjuts length
+ if {$true_length < $length} {
+ return "[string repeat 0 [expr {$length - $true_length}]]$value"
+ } elseif {$true_length > $length} {
+ incr length -1
+ return [string range $value "end-$length" end]
+ } else {
+ return $value
+ }
+ }
+
+ ## Translate current operands to list of hexadecimal strings
+ # @return List - result (list of two digits pairs)
+ proc oprs2hex {} {
+ variable operands ;# List of operand codes
+ variable opr_types ;# List of operand types
+
+ # Initialize result
+ set new_operands {}
+
+ # Iterate over given operands
+ foreach opr $operands type $opr_types {
+ # Check for variable operand type
+ if {[lsearch ${::CompilerConsts::FixedOperands} [string tolower $opr]] != -1} {continue}
+
+ # Check for validity of the given operand
+ set opr [string trimleft $opr {#@/}]
+ if {![regexp {^\d+$} $opr]} {
+ CompilationError [mc "Invalid operand: '%s'" $opr]
+ break
+ }
+
+ # Convert to hexadecimal string
+ set opr [format %X $opr]
+
+ # Adjust length
+ set opr_len [string length $opr]
+ if {($type == {imm16}) || ($type == {code16})} {
+ if {$opr_len < 4} {
+ set opr "[string repeat 0 [expr {4 - $opr_len}]]$opr"
+
+ } elseif {$opr_len > 4} {
+ CompilationError [mc "Invalid value"]
+ }
+
+ } elseif {$type == {code11}} {
+ if {$opr_len < 3} {
+ set opr "[string repeat 0 [expr {3 - $opr_len}]]$opr"
+
+ } elseif {$opr_len > 3} {
+ CompilationError [mc "Invalid value"]
+ }
+
+ } elseif {$opr_len == 1} {
+ set opr "0$opr"
+ }
+
+ # Append operand to the resulting list
+ lappend new_operands $opr
+ }
+
+ # Return result
+ return $new_operands
+ }
+
+ ## Search for operands definition list of the given instruction (instruction must be valid)
+ # @parm String instruction - Name of instruction to find
+ # @return List - Found operands definition list
+ proc find_instruction_definition {instruction} {
+ variable opr_types ;# List of operand types
+
+ # Iterate over operands definitions
+ foreach definition [lindex $CompilerConsts::InstructionDefinition($instruction) 1] {
+
+ # Determinate operand types
+ set opr_list [lindex $definition 0]
+
+ # Compare the given operand types with definition
+ set match 1
+ foreach given_type $opr_types possible_type $opr_list {
+ if {[lsearch $given_type $possible_type] == -1} {
+ set match 0
+ break
+ }
+ }
+
+ # Return result
+ if {$match} {
+ return $definition
+ }
+ }
+
+ # Nothing found
+ if {!$match} {
+ CompilationError [mc "Invalid operand"]
+ return {}
+ }
+ }
+
+ ## Verify validity of the given instruction (Invokes CompilationError of fail)
+ # @parm String instruction - Instruction to verify
+ # @return Bool - result
+ proc notAnInstruction {instruction} {
+ if {[lsearch ${::CompilerConsts::AllInstructions} $instruction] == -1} {
+ CompilationError [mc "Unknown instruction: %s" $instruction]
+ return 1
+ }
+ return 0
+ }
+
+ ## Compilation error
+ # @parm String errorInfo - Error string
+ # @return void
+ proc CompilationError {errorInfo} {
+ variable working_dir ;# String: Project working directory
+ variable included_files ;# List: Unique unsorted list of included files
+ variable error_count ;# Errors count
+ variable fileNumber ;# File number
+ variable lineNumber ;# Number of line currently beeing parsed
+
+ incr error_count
+ set filename [lindex $included_files $fileNumber]
+ if {![string first $working_dir $filename]} {
+ set filename [string replace $filename 0 [string length $working_dir]]
+ }
+ if {[regexp {\s} $filename]} {
+ set filename "\"$filename\""
+ }
+ set filename [mc " in %s" $filename]
+ if {${::Compiler::Settings::WARNING_LEVEL} < 3} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EL}][mc "Compilation error at line %s: %s" "${lineNumber}${filename}" $errorInfo]
+ } {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[31;1mCompilation error at line \033\[31;1;4m%s\033\[m%s: %s" $lineNumber $filename $errorInfo]
+ }
+ }
+ }
+}
diff --git a/lib/compiler/codelisting.tcl b/lib/compiler/codelisting.tcl
new file mode 100755
index 0000000..1940dc3
--- /dev/null
+++ b/lib/compiler/codelisting.tcl
@@ -0,0 +1,1169 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Hepler namespace to generate code listing.
+# This code is part of compiler (see 'compiler.tcl' and 'assembler.tcl').
+# --------------------------------------------------------------------------
+
+
+namespace eval CodeListing {
+
+ ## Resulting LST code
+ # format: {lineNum address opcode value includeLevel macroLevel {lineContent}}
+ variable lst {}
+ variable Enabled 1 ;# Bool: LIST/NOLIST flag
+ variable pageNum ;# Page number
+ variable pageLines ;# Number of lines at the current page
+ variable header {} ;# Title string
+ variable errors_count 0 ;# Number of errors
+ variable warnings_count 0 ;# Number of warnings
+ variable symbol_table {} ;# Table of symbolic names
+ variable error_summary {} ;# Error summmary string
+ variable new_sync_map {} ;# Tempotary Map of lines in code listing
+ variable sync_map {} ;# Map of lines in code listing
+ variable tmp_lst {} ;# Tempotary LST code
+
+
+ # ----------------------------------------------------------------
+ # GENERAL PURPOSE PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Format resulting code listing
+ # @access public
+ # @return String - code listing
+ proc getListing {} {
+ variable lst ;# Resulting LST code
+ variable error_summary ;# Error summmary string
+ variable errors_count ;# Number of errors
+ variable warnings_count ;# Number of warnings
+ variable symbol_table ;# Table of symbolic names
+ variable header ;# Title string
+ variable pageNum ;# Page number
+ variable pageLines ;# Number of lines at the current page
+
+ # Initialize NS variables
+ set pageNum 1
+ set pageLines 0
+
+ # Validate compiler settings
+ if {${Compiler::Settings::PAGELENGTH} < 5} {
+ set Compiler::Settings::PAGELENGTH 5
+ } elseif {${Compiler::Settings::PAGELENGTH} == 0} {
+ set Compiler::Settings::PAGING 0
+ }
+ if {${Compiler::Settings::PAGEWIDTH} < 68} {
+ set Compiler::Settings::PAGEWIDTH 68
+ } elseif {${Compiler::Settings::PAGEWIDTH} == 0} {
+ set Compiler::Settings::PAGEWIDTH 116
+ }
+
+ # Create page header
+ set header ${Compiler::Settings::INPUT_FILE_NAME}
+ set len [string length ${Compiler::Settings::INPUT_FILE_NAME}]
+ if {$len < 15} {
+ append header [string repeat { } [expr {15 - $len}]]
+ }
+ append header { } ${Compiler::Settings::TITLE}
+
+ set len [string length $header]
+ incr len 23
+
+ # Adjust page header width
+ if {$len > ${Compiler::Settings::PAGEWIDTH}} {
+ set header [string range $header 0 [expr {${Compiler::Settings::PAGEWIDTH} - 24}]]
+ append header {... }
+
+ } elseif {$len < ${Compiler::Settings::PAGEWIDTH}} {
+ set len [expr {${Compiler::Settings::PAGEWIDTH} - $len}]
+ append header [string repeat { } $len]
+ }
+
+ # Create date
+ set len [string length ${Compiler::Settings::DATE}]
+ if {$len > 10} {
+ set Compiler::Settings::DATE [string range 0 7 ${Compiler::Settings::DATE}]
+ append Compiler::Settings::DATE {...}
+
+ } elseif {$len < 10} {
+ set len [expr {10 - $len}]
+ append Compiler::Settings::DATE [string repeat { } $len]
+ }
+
+ append header ${Compiler::Settings::DATE} { PAGE}
+
+ # Create error summary and symbol table
+ create_error_summary
+ if {${Compiler::Settings::SYMBOLS}} {
+ create_symbol_table
+ }
+
+ # Create code listing text
+ format_listing
+
+ append lst "\nASSEMBLY COMPLETE"
+
+ # Append final result
+ if {$errors_count == 1} {
+ append lst ", 1 ERROR FOUND"
+ } elseif {$errors_count > 1} {
+ append lst ", $errors_count ERRORS FOUND"
+ } {
+ append lst ", NO ERRORS FOUND"
+ }
+
+ if {$warnings_count == 1} {
+ append lst ", 1 WARNING"
+ } elseif {$warnings_count > 1} {
+ append lst ", $warnings_count WARNINGS"
+ } {
+ append lst ", NO WARNINGS"
+ }
+
+ # Create final result
+ append lst "\n"
+
+ # Error summary
+ if {($errors_count != 0) || ($warnings_count != 0)} {
+ append lst "\n\n"
+ append lst $error_summary
+ }
+
+ # Symbol table
+ if {${Compiler::Settings::SYMBOLS}} {
+ append lst "\n\n"
+ append lst $symbol_table
+ }
+
+ # restore special characters
+ regsub -all {\\\\} $lst "\\" lst
+ regsub -all {\\\{} $lst "\{" lst
+ regsub -all {\\\}} $lst "\}" lst
+ regsub -all {\\\"} $lst "\"" lst
+
+ # Return result
+ return $lst
+ }
+
+ ## Directive LIST
+ # @access public
+ # @parm Int idx - index where the directive occured
+ # @return void
+ proc directive_list {idx} {
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+ if {${Compiler::Settings::_list} != 0} {return}
+
+ # Adjust code listing
+ set idx [getIdx $idx]
+ increment_sync_map $idx 1
+ set lst [linsert $lst $idx {LIST}]
+ }
+
+ ## Directive NOLIST
+ # @access public
+ # @parm Int idx - index where the directive occured
+ # @return void
+ proc directive_nolist {idx} {
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+ if {${Compiler::Settings::_list} != 0} {return}
+
+ # Adjust code listing
+ set idx [getIdx $idx]
+ incr idx
+ increment_sync_map $idx 1
+ set lst [linsert $lst $idx {NOLIST}]
+ }
+
+ ## Debuging procedure
+ # Write current content of the code listing to stdout (max. 501 lines)
+ # @access public
+ # @return void
+ proc write_lst {} {
+ variable lst ;# Resulting LST code
+ variable sync_map ;# Map of lines in code listing
+
+ set idx 0
+ foreach line $lst {
+ puts "$idx:\t$line"
+ incr idx
+ if {$idx > 500} {break}
+ }
+ }
+
+ ## Initialize code listing
+ # Should be called on preprocessor start up
+ # @access public
+ # @parm String data - input source code
+ # @return void
+ proc create_listing {data} {
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ variable lst ;# Resulting LST code
+ variable sync_map ;# Map of lines in code listing
+ variable error_summary ;# Error summmary string
+ variable symbol_table ;# Table of symbolic names
+ variable Enabled ;# Bool: LIST/NOLIST flag
+
+ # Reset NS variables
+ set lst {}
+ set Enabled 1
+ set sync_map {}
+ set symbol_table {}
+ set error_summary {}
+
+ # Initialize code listing list
+ set idx -1
+ foreach line $data {
+ incr idx
+ lappend lst [list {} {} {} 0 0 [lindex $line 2]]
+ lappend sync_map $idx
+ }
+ }
+
+ ## Import table of symbolic names from preprocessor
+ # @access public
+ # @return void
+ proc import_symbolic_names {} {
+ variable symbol_table ;# Table of symbolic names
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+ if {!${Compiler::Settings::SYMBOLS}} {return}
+
+ # Iterate over definition ists and write them to the table
+ foreach def_list {
+ defined_BIT defined_CODE defined_DATA defined_IDATA
+ defined_XDATA defined_LABEL defined_EQU defined_EQU_SPEC
+ } val_array {
+ const_BIT const_CODE const_DATA const_IDATA
+ const_XDATA labels const_EQU const_EQU_SPEC
+ } type {
+ ADDR ADDR ADDR ADDR
+ ADDR ADDR NUMB SPEC
+ } char {
+ B C D I
+ X C N S
+ } {
+
+ # Get list of defined names
+ set def_list [subst "\$PreProcessor::$def_list"]
+
+ # Write defined names to the table
+ foreach var $def_list {
+ set value [subst "\$PreProcessor::${val_array}($var)"]
+
+ # Handle special constants
+ if {$char == {S}} {
+ lappend symbol_table [list \
+ [string toupper $var] \
+ $char \
+ $type \
+ [string toupper $value] \
+ 1 0]
+
+ # Other constants ...
+ } {
+ lappend symbol_table [list \
+ [string toupper $var] \
+ $char \
+ $type \
+ [get_4hex $value] \
+ 1 0]
+ }
+ }
+ }
+
+ # Write defined variables (directive "SET")
+ foreach var ${PreProcessor::defined_SET} {
+ set value [lindex $PreProcessor::const_SET($var) {end 1}]
+ lappend symbol_table [list [string toupper $var] { } NUMB [get_4hex $value] 1 1]
+ }
+
+ # Write defined special variables (directive "SET")
+ foreach var ${PreProcessor::defined_SET_SPEC} {
+ set value [lindex $PreProcessor::const_SET_SPEC($var) {end 1}]
+ lappend symbol_table [list [string toupper $var] {S} SPEC [string toupper $value] 1 1]
+ }
+
+ # Sort table of symbols by names
+ set symbol_table [lsort -index 0 $symbol_table]
+ }
+
+ ## Set flag used to 1 for symbol writen in table of symbols
+ # @access public
+ # @parm String symbolic_name - Symbol name
+ # @parm String type - Symbol type
+ # @return Bool - result
+ proc symbol_used {symbolic_name type} {
+ variable symbol_table ;# Table of symbolic names
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+ if {!${Compiler::Settings::SYMBOLS}} {return}
+
+ # Find the specified symbol in the table
+ set symbolic_name [string toupper $symbolic_name]
+ set idx -1
+ foreach var $symbol_table {
+ incr idx
+
+ # Symbol found -> set flag used
+ if {[lindex $var 0] == $symbolic_name} {
+ lset symbol_table [list $idx 4] 0
+ return 1
+ }
+ }
+
+ # Symbol not found -> failed
+ return 0
+ }
+
+ ## Write error message to the code listing
+ # @access public
+ # @parm Int idx - Index where the error occured
+ # @parm String info - Error message
+ # @return void
+ proc Error {idx info} {
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Adjust index
+ set idx [getIdx $idx]
+ if {$idx == {}} {
+ puts stderr "Compiler internal failure 0 -- code listing will not be complete"
+ return
+ }
+ incr idx
+ increment_sync_map $idx 1
+
+ # Write the message
+ set lst [linsert $lst $idx [list {****} "ERROR: $info"]]
+ }
+
+ ## Write warning message to the code listing
+ # @access public
+ # @parm Int idx - Index where the warning occured
+ # @parm String info - Warning message
+ # @return void
+ proc Warning {idx info} {
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Adjust index
+ set idx [getIdx $idx]
+ if {$idx == {}} {
+ puts stderr "Compiler internal failure 4 -- code listing will not be complete"
+ return
+ }
+ incr idx
+ increment_sync_map $idx 1
+
+ # Write the message
+ set lst [linsert $lst $idx [list {****} "WARNING: $info"]]
+ }
+
+ ## Directive "$EJECT"
+ # @access public
+ # @parm Int idx - Source index
+ # @return void
+ proc directive_eject {idx} {
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Adjust index
+ set idx [getIdx $idx]
+ if {$idx == {}} {
+ puts stderr "Compiler internal failure 5 -- code listing will not be complete"
+ return
+ }
+ incr idx 2
+ increment_sync_map $idx 1
+
+ # Write the message
+ set lst [linsert $lst $idx EJECT]
+ }
+
+ ## Directive "DB"
+ # @access public
+ # @parm Int idx - Source index
+ # @parm List values - Hexadecimal values (eg. '{FA 4 5 2D C'})
+ # @return void
+ proc db {idx values} {
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Determinate original values
+ set sub_idx [getIdx $idx]
+ if {$sub_idx != {}} {
+ set new_values [lindex $lst [list $sub_idx 1]]
+ } {
+ set new_values {}
+ }
+
+ # Adjust list of values
+ foreach val $values {
+ if {![string is digit -strict $val]} {
+ continue
+ }
+ set val [string trimleft $val 0]
+ if {$val == {}} {
+ set val {00}
+ } else {
+ set val [format %X $val]
+ if {[string length $val] == 1} {
+ set val "0$val"
+ }
+ }
+ append new_values $val
+ }
+
+ # Set OP code for the current line
+ set_opcode $idx $new_values
+ }
+
+ ## Expansion of macro instruction
+ # @access public
+ # @parm Int idx - Source index
+ # @parm String macro_code - Code of the macro instruction
+ # @return void
+ proc macro {idx macro_code} {
+ variable sync_map ;# Map of lines in code listing
+ variable tmp_lst ;# Tempotary LST code
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Create empty space in code listing
+ insert_lines $idx [llength $macro_code]
+
+ # Determinate target index
+ set idx [getIdx $idx]
+ # Initialize auxiliary code listing list
+ set tmp_lst {}
+
+ # Adjust Macro expansion level and Inclusion level
+ set IncLevel [lindex $lst "$idx 3"]
+ set MacLevel [lindex $lst "$idx 4"]
+ if {![regexp {^\d+$} $MacLevel]} {
+ puts stderr "Compiler internal failure 1 -- code listing will not be complete"
+ return
+ }
+ incr MacLevel
+
+ # Adjust code of macro instruction
+ foreach line $macro_code {
+ lappend tmp_lst [list {} {} {} $IncLevel $MacLevel "\t\t$line"]
+ }
+
+ # Set macro expansion level
+ lset lst "$idx 4" $MacLevel
+
+ # Insert code of macro to the current code listing
+ incr idx
+ append tmp_lst { }
+ append tmp_lst [lrange $lst $idx end]
+ set lst [lreplace $lst $idx end]
+
+ append lst { }
+ append lst $tmp_lst
+ set tmp_lst {}
+ }
+
+ ## Adjust current code listing to the fiven code organization
+ # @access public
+ # @parm List organization - new organization (see Preprocessor)
+ # @return void
+ proc org {organization} {
+ variable sync_map ;# Map of lines in code listing
+ variable new_sync_map ;# Tempotary Map of lines in code listing
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Reformat synchronization map
+ set new_sync_map {}
+ foreach org $organization {
+ # Local variables
+ set start [lindex $org 0] ;# Start line
+ set end [lindex $org 1] ;# End line
+
+ append new_sync_map { }
+ append new_sync_map [lrange $sync_map $start $end]
+ set sync_map [lreplace $sync_map $start $end]
+ }
+ if {$sync_map != {}} {
+ append new_sync_map { }
+ append new_sync_map $sync_map
+ }
+
+ set sync_map $new_sync_map
+ }
+
+ ## Set instruction OP code
+ # @access public
+ # @parm Int idx - Source index
+ # @parm String opcode - Haxadecimal OP code
+ # @return void
+ proc set_opcode {idx opcode} {
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Adjust code listing
+ set idx [getIdx $idx]
+
+ if {$idx == {}} {return}
+ if {[catch {
+ lset lst [list $idx 1] $opcode
+ }]} then {
+ puts stderr "Compiler internal failure 2 -- code listing will not be complete"
+ return
+ }
+ }
+
+ ## Set instruction address
+ # @access public
+ # @parm Int idx - Source index
+ # @parm Int addr - Instruction address
+ # @return void
+ proc set_addr {idx addr} {
+ variable lst ;# Resulting LST code
+ variable sync_map ;# Map of lines in code listing
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Adjust code listing
+ set idx [getIdx $idx]
+ if {$idx == {}} {return}
+ if {[catch {
+ lset lst "$idx 0" [get_4hex $addr]
+ }]} then {
+ puts stderr "Compiler internal failure 3 -- code listing will not be complete"
+ return
+ }
+ }
+
+ ## Directive "END"
+ # @access public
+ # @parm Int idx - Source index
+ # @return void
+ proc end_directive {idx} {
+ variable sync_map ;# Map of lines in code listing
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Determinate target index
+ set lst_idx [getIdx $idx]
+ incr lst_idx
+ if {$lst_idx == {}} {return}
+ if {$lst_idx > ([llength $lst] - 1)} {return}
+
+ # Adjust code listing and synchronization map
+ set lst [lreplace $lst $lst_idx end]
+ set sync_map [lreplace $sync_map $idx end]
+ }
+
+ ## Set value for symbol definition
+ # @access public
+ # @parm Int idx - Source index
+ # @parm Int value - Symbol value
+ # @return void
+ proc set_value {idx value} {
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Determinate target index
+ set idx [getIdx $idx]
+ if {$idx == {}} {return}
+
+ # Adjust code listing
+ lset lst "$idx 2" [get_4hex $value]
+ }
+
+ ## Set value for special symbol definition
+ # @access public
+ # @parm Int idx - Source index
+ # @parm Int value - Symbol value
+ # @return void
+ proc set_spec_value {idx value} {
+ # This procedure does nothing and that's what is should do ...
+ }
+
+ ## Directive "INCLUDE"
+ # @access public
+ # @parm Int idx - Source index
+ # @parm String data - Included source code
+ # @return void
+ proc include {idx data} {
+ variable tmp_lst ;# Tempotary LST code
+ variable lst ;# Resulting LST code
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Insert empty lines for the included code
+ insert_lines $idx [expr {[llength $data] - 1}]
+
+ # Determinate target index
+ set idx [getIdx $idx]
+
+ # Adjust macro expansion level and inclusion level
+ set IncLevel [lindex $lst "$idx 3"]
+ set MacLevel [lindex $lst "$idx 4"]
+ incr IncLevel
+
+ # Adjust the given source code
+ set tmp_lst {}
+ foreach line $data {
+ lappend tmp_lst [list {} {} {} $IncLevel $MacLevel [lindex $line 2]]
+ }
+
+ # Reformat code listing
+ incr idx
+ append tmp_lst { }
+ append tmp_lst [lrange $lst $idx end]
+ incr idx -1
+ set lst [lreplace $lst $idx end]
+ append lst { }
+ append lst $tmp_lst
+ set tmp_lst {}
+
+ }
+
+ ## Line removed -- adjust synchronization map
+ # @access public
+ # @parm Int idx - source index
+ # @return void
+ proc delete_line {idx} {
+ variable sync_map ;# Map of lines in code listing
+
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ # Adjust synchronization map
+ if {[catch {
+ set sync_map [lreplace $sync_map $idx $idx]
+ }]} {
+ puts stderr "Still unresolved compiler bug. I am sorry for that, code listing will not be complete. (As far as I know there is only one bug of that kind)"
+ }
+ }
+
+ ## Adjust synchronization map to create spece which cannot contain anything
+ # @access public
+ # @parm Int dest_idx - Target index
+ # @parm Int len - Number of lines
+ # @return void
+ proc insert_empty_lines {dest_idx len} {
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+
+ variable sync_map ;# Map of lines in code listing
+ variable new_sync_map ;# Tempotary Map of lines in code listing
+
+ # Abort if there s nothing to insert
+ if {$len == 0} {return}
+
+ # Create $len empty items in sync map at index $dest_idx
+ set new_sync_map {}
+ set idx -1
+ foreach item $sync_map {
+ incr idx
+
+ lappend new_sync_map $item
+ if {$idx == $dest_idx} {
+ for {set i 0} {$i < $len} {incr i} {
+ lappend new_sync_map {}
+ }
+ }
+ }
+
+ set sync_map $new_sync_map
+ }
+
+ ## Free reserved resources
+ # @access public
+ # @return void
+ proc free_resources {} {
+ variable lst ;# Resulting LST code
+ set lst {}
+ }
+
+
+ # ----------------------------------------------------------------
+ # INTERNAL AUXILIARY PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Reformat internal listing to human readable text
+ # @access private
+ # @return void
+ proc format_listing {} {
+ variable header ;# Title string
+ variable pageNum ;# Page number
+ variable pageLines ;# Number of lines at the current page
+ variable lst ;# Resulting LST code
+ variable Enabled ;# Bool: LIST/NOLIST flag
+
+ # Write page header
+ set result $header
+ append result { } $pageNum "\n"
+
+ # Initialize variables
+ set pageLines 0
+ set lineNum 0
+
+ # Reformat code
+ foreach line $lst {
+ incr lineNum
+
+ # Take case of directives "LIST" and "NOLIST"
+ if {$line == {NOLIST}} {
+ set Enabled 0
+ incr lineNum -1
+ continue
+ } elseif {$line == {LIST}} {
+ set Enabled 1
+ incr lineNum -1
+ continue
+ }
+
+ # Skip line if listing is disabled
+ if {!$Enabled} {
+ continue
+ }
+
+ # Create new page if paging is enabled
+ if {${Compiler::Settings::PAGING}} {
+ incr pageLines
+ if {$pageLines > ${Compiler::Settings::PAGELENGTH}} {
+ incr pageNum
+ set pageLines 1
+ append result "\n\f" $header { } $pageNum "\n\n"
+ }
+ }
+
+
+ # Directive "$EJECT"
+ if {[lindex $line 0] == {EJECT}} {
+ incr pageNum
+ set pageLines 1
+ append result "\n\f" $header { } $pageNum "\n\n"
+ incr lineNum -1
+
+ # Line containing an error message
+ } elseif {[lindex $line 0] == {****}} {
+ append result "****" [lindex $line 1] "\n"
+ incr lineNum -1
+
+ # Normal line
+ } {
+ # Local variables
+ set addr [lindex $line 0] ;# Address field
+ set opcode [lindex $line 1] ;# Instruction OP code
+ set value [lindex $line 2] ;# Value of defined constant
+ set IncLevel [lindex $line 3] ;# Inclusion level
+ set MacLevel [lindex $line 4] ;# Macro expansion level
+ set code [lindex $line 5] ;# Source code
+
+ # Adjust inclusion level
+ if {$IncLevel == 0} {
+ set IncLevel { }
+ } {
+ set IncLevel "=$IncLevel"
+ if {[string length $IncLevel] == 2} {
+ append IncLevel { }
+ }
+ }
+
+ # Adjust macro expansion level
+ if {$MacLevel == 0} {
+ set MacLevel { }
+ } {
+ set MacLevel "+$MacLevel"
+ if {[string length $MacLevel] == 2} {
+ append MacLevel { }
+ }
+ }
+
+ # Adjust line number
+ set line_number $lineNum
+ set len [string length $line_number]
+ if {$len < 5} {
+ set line_number "[string repeat { } [expr {5 - $len}]]$line_number"
+ }
+
+ ## Create filed 0 (address + OP code // constant value)
+ set field0 {}
+
+ # Adjust opcode length (for continuation on the next line)
+ set opcode_len [string length $opcode]
+ if {$opcode_len > 10} {
+ set opcode_continue [string replace $opcode 0 9]
+ set opcode [string range $opcode 0 9]
+ }
+
+ # Only constant value
+ if {$value != {}} {
+ append field0 { } $value { }
+ # Address + OP code
+ } elseif {($opcode != {}) && ($addr != {})} {
+ if {$opcode_len < 10} {
+ append opcode [string repeat { } [expr {10 - $opcode_len}]]
+ }
+ append field0 $addr { } $opcode { }
+ # Empty
+ } else {
+ set field0 [string repeat { } 16]
+ }
+
+ # Composite final line
+ set line {}
+ append line $field0 { } $IncLevel { } $line_number
+ append line { } $MacLevel { } [tabs2spaces $code]
+ append result [string range $line 0 [expr ${Compiler::Settings::PAGEWIDTH} - 1]] "\n"
+
+ # Continue in unfinished opcode
+ if {$opcode_len > 10} {
+ incr opcode_len -10
+ for {set i 0; set j 9} {$i < $opcode_len} {incr i 10; incr j 10} {
+ append result { } [string range $opcode_continue $i $j] "\n"
+ }
+ }
+ }
+ }
+
+ # Restore characters '{' and '}'
+ regsub -all {\a} $result "\{" result
+ regsub -all {\b} $result "\}" result
+ # Remove redutant white space
+ set lst [regsub -all -line {\s+$} $result {}]
+ }
+
+ ## Convert tabulators to spaces
+ # @access private
+ # @parm String data - input data
+ # @return String - output data
+ proc tabs2spaces {data} {
+ set tmp {} ;# Auxiliary variable
+ while 1 {
+ # Search for 1st tabulator
+ set idx [string first "\t" $data]
+
+ # Tabulator not found -> return result
+ if {$idx == -1} {
+ return $data
+ # 1st char
+ } elseif {$idx == 0} {
+ regsub {\t} $data { } data
+ # Somewhere else
+ } else {
+ # Determinate string before tabulator
+ incr idx -1
+ set tmp [string range $data 0 $idx]
+ # Determinate string after tabulator
+ incr idx 2
+ set data [string range $data $idx end]
+ # Determinate number of spaces
+ set len [string length $tmp]
+ set len [expr {8 - ($len % 8)}]
+ # Recomposite source string
+ append tmp [string repeat { } $len]
+ append tmp $data
+ set data $tmp
+ }
+ }
+ }
+
+ ## Create string containing error summary
+ # Modifies content of variables:
+ # - error_summary
+ # - errors_count
+ # - warnings_count
+ # @access private
+ # @return void
+ proc create_error_summary {} {
+ variable lst ;# Resulting LST code
+ variable error_summary ;# Error summmary string
+ variable errors_count ;# Number of errors
+ variable warnings_count ;# Number of warnings
+ variable header ;# Title string
+ variable pageNum ;# Page number
+ variable pageLines ;# Number of lines at the current page
+
+ # Reset error counters
+ set errors_count 0
+ set warnings_count 0
+ # Initialize resulting string
+ set error_summary {}
+
+ # Create new page
+ if {${Compiler::Settings::PAGING}} {
+ incr pageNum
+ set pageLines 0
+ append error_summary "\n\f" $header { } $pageNum "\n\n"
+ }
+
+ append error_summary {ERROR SUMMARY:}
+
+ # Search code for errors and warnings
+ set lineNum -1
+ foreach line $lst {
+ incr lineNum
+
+ # Create new page if nessesary
+ if {${Compiler::Settings::PAGING}} {
+ incr pageLines
+
+ if {$pageLines > ${Compiler::Settings::PAGEWIDTH}} {
+ incr pageNum
+ set pageLines 1
+ append error_summary "\n\f" $header { } $pageNum "\n\n"
+ }
+ }
+
+ # Error/Warning found
+ if {[lindex $line 0] == {****}} {
+
+ if {[lindex $line {1 0}] == {ERROR:}} {
+ incr errors_count
+ } {
+ incr warnings_count
+ }
+
+ # Append error/warning information
+ append error_summary "\n" Line { } $lineNum {, } [lindex $line 1]
+ }
+ }
+ }
+
+ ## Create table of symbolic names
+ # Result is stored in variable symbol_table
+ # @access private
+ # @return void
+ proc create_symbol_table {} {
+ variable symbol_table ;# Table of symbolic names
+ variable header ;# Title string
+ variable pageNum ;# Page number
+ variable pageLines ;# Number of lines at the current page
+
+ # Initialize resulting string
+ set result {}
+
+ # Create new page
+ if {${Compiler::Settings::PAGING}} {
+ incr pageNum
+ set pageLines 0
+ append result "\n\f" $header { } $pageNum "\n\n"
+ }
+ append result {SYMBOL TABLE:}
+
+ # Create string for paddings
+ set padding [string repeat { .} 18]
+
+ # Convert current table to human readable string
+ foreach var $symbol_table {
+
+ # Create new page if nessesary
+ if {${Compiler::Settings::PAGING}} {
+ incr pageLines
+
+ if {$pageLines > ${Compiler::Settings::PAGEWIDTH}} {
+ incr pageNum
+ set pageLines 1
+ append result "\n\f" $header { } $pageNum "\n\n"
+ }
+ }
+
+ # Local variables
+ set rd [lindex $var 5] ;# Bool: redefinable
+ set nu [lindex $var 4] ;# Bool: not used
+ set val [lindex $var 3] ;# Value
+ set name [lindex $var 0] ;# Symbolic name
+ ## Type
+ # NUMB == number
+ # ADDR == address
+ # SPEC == special value
+ set type [lindex $var 2]
+ ## Character
+ # C == code
+ # D == data
+ # B == bit
+ # X == external
+ # S == special value
+ set char [lindex $var 1]
+
+ # Adjust rd
+ if {$rd == 1} {
+ set rd {REDEFINABLE}
+ } {
+ set rd {}
+ }
+
+ # Adjust nu
+ if {$nu == 1} {
+ set nu {NOT USED}
+ } {
+ set nu { }
+ }
+
+ # Adjuts symbolic name
+ set len [string length $name]
+ incr len -1
+ set name [string replace $padding 0 $len $name]
+
+ # Composite final line
+ if {$char != {S}} {
+ set h {H}
+ } {
+ set nu { }
+ set h [string repeat { } [expr {5 - [string length $val]}]]
+ }
+ append result "\n" $name { } $char { } $type { } $val $h { } $nu { } $rd
+ }
+ append result "\n"
+
+ # Remove all redutant white space
+ regsub -all -line {\s+$} $result {} symbol_table
+ }
+
+ ## Increment values in synchronization map
+ # @access private
+ # @parm Int idx - Index where incrementation begins
+ # @parm Int value - Value to increment by
+ # @return void
+ proc increment_sync_map {idx value} {
+ variable sync_map ;# Map of lines in code listing
+ variable new_sync_map ;# Tempotary Map of lines in code listing
+
+ set new_sync_map {}
+ foreach item $sync_map {
+ if {$item >= $idx} {
+ if {$item != {}} {
+ incr item $value
+ }
+ }
+ lappend new_sync_map $item
+ }
+ set sync_map $new_sync_map
+ }
+
+ ## Convert decimal value to four digit hexadecimal value
+ # @access private
+ # @parm Int number - number to convert
+ # @return String - result
+ proc get_4hex {number} {
+ # Convert value
+ set number [format %X $number]
+ # Adjust length
+ set len [string length $number]
+ if {$len < 4} {
+ set number "[string repeat 0 [expr {4 - $len}]]$number"
+ }
+ # Return result
+ return $number
+ }
+
+ ## Translate source index to target index acording to synchronization map
+ # @access private
+ # @parm Int idx - Source index
+ # @return Int - target index
+ proc getIdx {idx} {
+ variable sync_map ;# Map of lines in code listing
+
+ set result [lindex $sync_map $idx]
+ if {$result == {}} {
+ set result 0
+ }
+ return $result
+ }
+
+ ## Adjust synchronization map to create empty space to insert something
+ # @access private
+ # @parm Int dest_idx - Target index
+ # @parm Int len - Number of lines
+ # @return void
+ proc insert_lines {dest_idx len} {
+ # Check if code listing is enabled
+ if {!${Compiler::Settings::PRINT}} {return}
+ if {$len == 0} {return}
+
+ variable sync_map ;# Map of lines in code listing
+ variable new_sync_map ;# Tempotary Map of lines in code listing
+
+ # Adjust synchronization map
+ set dest_item [lindex $sync_map $dest_idx]
+ if {$dest_item == {}} {
+ set dest_item 0
+ }
+ set new_sync_map {}
+ set idx -1
+ foreach item $sync_map {
+ incr idx
+
+ # Taget index
+ if {$idx == $dest_idx} {
+ if {$item == {}} {
+ continue
+ }
+ set tmp [expr {$len + $item}]
+ while {$item <= $tmp} {
+ lappend new_sync_map $item
+ incr item
+ }
+
+ # Empty index or too low index to be changed
+ } elseif {$item == {} || $item < $dest_item} {
+ lappend new_sync_map $item
+
+ # Index somewhere in the affected area
+ } else {
+ incr item $len
+ lappend new_sync_map $item
+ }
+ }
+
+ set sync_map $new_sync_map
+ }
+}
diff --git a/lib/compiler/compiler.tcl b/lib/compiler/compiler.tcl
new file mode 100755
index 0000000..35dea32
--- /dev/null
+++ b/lib/compiler/compiler.tcl
@@ -0,0 +1,557 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# 8051 COMPILER - BASE NAMESPACE
+# --------------------------------------------------------------------------
+
+# Include other parts
+source "${::LIB_DIRNAME}/compiler/codelisting.tcl" ;# Code listing creator
+source "${::LIB_DIRNAME}/compiler/assembler.tcl" ;# Assemler
+source "${::LIB_DIRNAME}/compiler/disassembler.tcl" ;# Disassembler
+source "${::LIB_DIRNAME}/compiler/preprocessor.tcl" ;# Preprocessor
+source "${::LIB_DIRNAME}/compiler/compilerconsts.tcl" ;# Compiler constant definitons
+source "${::LIB_DIRNAME}/compiler/external_compiler.tcl";# External compiler interface
+
+namespace eval Compiler {
+ variable error_count ;# Number of errors occured during compilation
+ variable warning_count ;# Number of warning reported during compilation
+
+ variable in_IDE 0 ;# Bool: Running in IDE (I mean GUI)
+
+ # Procedure which do nothing (for better portability)
+ proc doNothing args {}
+
+ ## Initiate compilation
+ # @parm String project_dir - Project directory
+ # @parm String current_dir - Current working directory
+ # @parm String input_file_name - Name of input source code
+ # @parm String input_file_extension = {} - Extension of input file
+ # @return Bool - result
+ proc compile {project_dir current_dir input_file_name input_file_extension} {
+ variable error_count ;# Number of errors occured during compilation
+ variable warning_count ;# Number of warning reported during compilation
+
+ # Compiler settings to defaults
+ Compiler::Settings::restoreDefaults
+
+ # Adjust compiler settings
+ if {${::Compiler::Settings::_print} == 2} {
+ set ::Compiler::Settings::PRINT 0
+ } {
+ set ::Compiler::Settings::PRINT 1
+ }
+ if {${::Compiler::Settings::_object} == 2} {
+ set ::Compiler::Settings::OBJECT 0
+ } {
+ set ::Compiler::Settings::OBJECT 1
+ }
+
+ # Reset errors and warnings counters
+ set error_count 0
+ set warning_count 0
+
+ # Set input filename and determinate time of start of compilation
+ set Settings::INPUT_FILE_NAME $input_file_name
+ set sec [clock seconds]
+
+ # Adjust input file extension
+ if {$input_file_extension != {}} {
+ set input_file_extension ".$input_file_extension"
+ }
+
+ # Check for usability of the given input file
+ set file [file join $current_dir $input_file_name$input_file_extension]
+
+ # Open and read contents of the input file
+ if {[catch {
+ set asm [open $file r]
+ set asm_data [read $asm]
+ close $asm
+ }]} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}][mc "Unable to open the specified file. (%s)" $file]
+ ${Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}][mc "Compilation FAILED !"]
+ } {
+ ${Settings::TEXT_OUPUT_COMMAND} [mc "Unable to open the specified file. (\033\[34;1m%s\033\[m)" $file]
+ ${Settings::TEXT_OUPUT_COMMAND} [mc "\033\[31;1mCompilation FAILED !\033\[m"]
+ }
+ return 0
+ }
+
+ # Initialize preprocessor
+ if {!${::Compiler::Settings::QUIET}} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ "\n\n[::Compiler::msgc {SN}][mc {Compiling file: %s} $input_file_name$input_file_extension]"
+ } {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\n\nCompiling file: \033\[34;1m%s\033\[m" $input_file_name$input_file_extension]
+ }
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Initializing pre-processor ..."]
+ }
+ set precompiledCode [PreProcessor::compile $current_dir $file $asm_data]
+ set asm_data {}
+ incr error_count ${PreProcessor::error_count}
+ incr warning_count ${PreProcessor::warning_count}
+ if {${PreProcessor::error_count} > 0} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}][mc "Pre-processing FAILED !"]
+ } {
+ ${Settings::TEXT_OUPUT_COMMAND} [mc "\033\[31;1mPre-processing FAILED !\033\[m"]
+ }
+ report_status $current_dir $input_file_name
+ return 0
+ }
+
+ if {${Settings::ABORT_VARIABLE}} {return 0}
+
+ # Initialize Assembler
+ if {!${::Compiler::Settings::QUIET}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Compiling ..."]
+ }
+ assembler::compile \
+ [md5::md5 -hex -file $file] \
+ [clock format [clock seconds] -format "%D"] \
+ $project_dir \
+ [file join $current_dir $input_file_name$input_file_extension] \
+ ${::PreProcessor::included_files} \
+ $precompiledCode
+ set ::PreProcessor::included_files {}
+ incr error_count ${assembler::error_count}
+ if {${assembler::error_count} > 0} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}][mc "Compilation FAILED !"]
+ } {
+ ${Settings::TEXT_OUPUT_COMMAND} [mc "\033\[31;1mCompilation FAILED !\033\[m"]
+ }
+ report_status $current_dir $input_file_name
+ return 0
+ }
+
+ if {${Settings::ABORT_VARIABLE}} {return 0}
+
+ # Write resulting object code
+ if {${Settings::OBJECT}} {
+ if {${Settings::OBJECT_FILE} != {}} {
+ set object_file ${Settings::OBJECT_FILE}
+ } {
+ set object_file $input_file_name
+ append object_file {.hex}
+ }
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Creating IHEX8 ...\t\t\t-> \"%s\"" $object_file]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Creating IHEX8 ...\t\t\t-> \"\033\[34;1m%s\033\[m\"" $object_file]
+ }
+ makeBackupFile $current_dir $object_file
+ if {[catch {
+ set hex [open [file join $current_dir $object_file] w 420]
+ }]} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "Error: Unable to open file \"%s\" for writing" [file join $current_dir $object_file]]
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "Compilation FAILED !"]
+ } {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[31;1mError\033\[m: Unable to open file \"\033\[34;1m%s\033\[m\" for writing" [file join $current_dir $object_file]]
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[31;1mCompilation FAILED !\033\[m"]
+ }
+ report_status $current_dir $input_file_name
+ return 0
+ } else {
+ puts -nonewline $hex ${assembler::hex}
+ close $hex
+ }
+ }
+
+ if {${Settings::ABORT_VARIABLE}} {return 0}
+
+ # Write resulting binary object code
+ if {${Settings::CREATE_BIN_FILE}} {
+ if {!${::Compiler::Settings::QUIET}} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Creating object file ...\t\t-> \"%s\"" "${input_file_name}.bin"]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Creating object file ...\t\t-> \"\033\[34;1m%s\033\[m\"" "${input_file_name}.bin"]
+ }
+ }
+
+ makeBackupFile $current_dir "${input_file_name}.bin"
+ if {[catch {
+ set bin [open [file join $current_dir $input_file_name.bin] w 420]
+ }]} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "Error: Unable to open file \"%s\" for writing" [file join $current_dir $input_file_name.bin]]
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "Compilation FAILED !"]
+ } {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Error: Unable to open file \"\033\[34;1m%s\033\[m\" for writing" [file join $current_dir "${input_file_name}.bin"]]
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[31;1mCompilation FAILED !\033\[m"]
+ }
+ report_status $current_dir $input_file_name
+ return 0
+ } else {
+ fconfigure $bin -translation binary
+ puts -nonewline $bin ${assembler::bin}
+ close $bin
+ }
+ set bin_data {}
+ }
+ set hex_data {}
+
+ if {${Settings::ABORT_VARIABLE}} {return 0}
+
+ # Write simulator data file
+ if {${Settings::CREATE_SIM_FILE}} {
+ if {!${::Compiler::Settings::QUIET}} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Creating assembler debug file ...\t-> \"%s\"" "${input_file_name}.adf"]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Creating simulator data file ...\t-> \"\033\[34;1m%s\033\[m\"" "${input_file_name}.adf"]
+ }
+ }
+ makeBackupFile $current_dir "${input_file_name}.adf"
+ if {[catch {
+ set sim [open [file join $current_dir $input_file_name.adf] w 420]
+ }]} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "Error: Unable to open file \"%s]\" for writing" [file join $current_dir $input_file_name.adf]
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "Compilation FAILED !"]
+ } {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[31;1mError\033\[m: Unable to open file \"\033\[34;1m%s\033\[m\" for writing" [file join $current_dir $input_file_name.adf]]
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[31;1mCompilation FAILED !\033\[m"]
+ }
+ report_status $current_dir $input_file_name
+ return 0
+ } {
+ puts -nonewline $sim ${assembler::adf}
+ close $sim
+ }
+ }
+
+ if {${Settings::ABORT_VARIABLE}} {return 0}
+
+ # Report final status
+ report_status $current_dir $input_file_name
+ if {!${::Compiler::Settings::QUIET}} {
+ if {${::Compiler::Settings::optim_ena}} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Number of optimalizations performed: %s" ${::PreProcessor::optims}]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Number of optimalizations performed: \033\[1m%s\033\[m" ${::PreProcessor::optims}]
+ }
+ }
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {SN}][mc "Compilation successful. (time: %s sec.)" [expr {[clock seconds] - $sec}]]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[32;1mCompilation successful.\033\[m (time: %s sec.)" [expr {[clock seconds] - $sec}]]
+ }
+ }
+
+ # Successful
+ return 1
+ }
+
+ ## Free resureces reserved during compilation
+ # @return void
+ proc free_resources {} {
+ ::assembler::free_resources
+ ::CodeListing::free_resources
+ set ::PreProcessor::asm {}
+ set ::PreProcessor::tmp_asm {}
+ }
+
+ ## Report final status and write code listing file
+ # @parm String current_dir - Working directory
+ # @parm String input_file_name - Name of input file
+ # @return void
+ proc report_status {current_dir input_file_name} {
+ variable error_count ;# Number of errors occured during compilation
+ variable warning_count ;# Number of warning reported during compilation
+
+ # Determinate name of code listing file
+ if {${Settings::PRINT_FILE} != {}} {
+ set print_file ${Settings::PRINT_FILE}
+ } {
+ set print_file $input_file_name
+ append print_file {.lst}
+ }
+
+ # Message "Creting code listing file"
+ if {!${::Compiler::Settings::QUIET}} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Creting code listing file ...\t\t-> \"%s\"" $print_file]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "Creting code listing file ...\t\t-> \"\033\[34;1m%s\033\[m\"" $print_file]
+ }
+ }
+
+ # Report number of errors and warning
+ if {!${::Compiler::Settings::QUIET}} {
+ if {$::TRANSLATION_LOADED} {
+ set text [mc "%s errors, %s warnings" $error_count $warning_count]
+ } {
+ set text "$error_count error"
+ if {$error_count != 1} {
+ append text "s"
+ }
+ append text ", $warning_count warning"
+ if {$warning_count != 1} {
+ append text "s"
+ }
+ }
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} $text
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} "\033\[1m$text\033\[m"
+ }
+ }
+
+ # Write code listing file
+ makeBackupFile $current_dir $print_file
+ if {[catch {
+ set lst [open [file join $current_dir $print_file] w 420]
+ }]} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "Error: Unable to open file \"%s\" for writing" [file join $current_dir $print_file]]
+ ${Settings::TEXT_OUPUT_COMMAND} [mc "Compilation FAILED !"]
+ } {
+ ${Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "Error: Unable to open file \"\033\[34;1m%s\033\[m\" for writing" [file join $current_dir $print_file]]
+ ${Settings::TEXT_OUPUT_COMMAND} [mc "\033\[31;1mCompilation FAILED !\033\[m"]
+ }
+ return 0
+ } else {
+ puts -nonewline $lst [CodeListing::getListing]
+ close $lst
+ }
+ }
+
+ ## Create backup copy of the specified file
+ # @parm String current_dir - Working directory
+ # @parm String filename - File name
+ # @parm String extension - File extension
+ # @return void
+ proc makeBackupFile {current_dir filename} {
+ if {[file exists [file join $current_dir $filename]]} {
+ catch {
+ file rename -force \
+ [file join $current_dir $filename] \
+ "[file join $current_dir $filename]~"
+ }
+ }
+ }
+
+ ## Namespace containing compiler settings
+ namespace eval Settings {
+ ## Peerhole optimalization enable flag
+ variable optim_ena 0 ;# Bool: 0 == disabled; 1 == enabled
+
+ ## Memory limits
+ variable iram_size 0x100 ;# Internal data memory
+ variable xram_size 0x10000 ;# External data memory
+ variable code_size 0x10000 ;# Overall program memory
+
+ ## Enable/Disable controls
+ # options:
+ # 0 - Controled by compiler
+ # 1 - Always
+ # 2 - Never
+ variable _symbols 0 ;# Control: $SYMBOLS
+ variable _print 0 ;# Control: $PRINT
+ variable _object 0 ;# Control: $OBJECT
+
+ # Options:
+ # 0 - use value defined in source code
+ # 1 - ignore
+ variable _nomod 0 ;# Control: $NOMOD
+ variable _paging 0 ;# Control: $PAGING
+ variable _pagelength 0 ;# Control: $PAGELENGTH(int)
+ variable _pagewidth 0 ;# Control: $PAGEWIDTH(int)
+ variable _title 0 ;# Control: $TITLE('string')
+ variable _date 0 ;# Control: $DATE('date')
+ variable _list 0 ;# Controls: $LIST $NOLIST; Directives: list nolist
+
+ # Default values for some controls
+ variable _object_file {} ;# Location of IHEX8 object file
+ variable _print_file {} ;# Location of Code Listing file
+ variable _title_value {} ;# Title string for code listing
+ variable _date_value {} ;# Date string for code listing
+ variable _nomod_value 0 ;# Bool: use predefined SFR addresses
+ variable _paging_value 0 ;# Bool: Use Form Feeds in code listing
+ variable _pagelength_value 0 ;# Number of lines per page in code listing
+ variable _pagewidth_value 132 ;# Number of characters per line in code listing
+
+ # Active settings
+ variable SYMBOLS {} ;# Bool: Include table of symbols to code listing
+ variable NOMOD {} ;# Bool: Do not use predefined SFR register addresses
+ variable PAGING {} ;# Bool: Use 'FF' in code listing
+ variable PAGELENGTH {} ;# Number of characters per line in code listing
+ variable PAGEWIDTH {} ;# Number of characters per line in code listing
+ variable TITLE {} ;# Title string for code listing
+ variable DATE {} ;# Date string for code listing
+ variable OBJECT {} ;# Bool: Generate IHEX8 object file
+ variable OBJECT_FILE {} ;# Location of IHEX8 object file
+ variable PRINT {} ;# Bool: Generate Code Listing file
+ variable PRINT_FILE {} ;# Location of Code Listing file
+ variable INPUT_FILE_NAME {} ;# Location of input file
+
+ variable CREATE_SIM_FILE 1 ;# Bool: Crete simulator data file
+ variable CREATE_BIN_FILE 1 ;# Bool: Create binary object code
+
+ variable max_ihex_rec_length 16 ;# Int: Maximum length of IHEX-8 record
+
+ ## Warning level
+ # 0 - all
+ # 1 - Errors + Warnings
+ # 2 - Errros only
+ # 3 - Nothing
+ variable WARNING_LEVEL 0
+
+ # Do not print what's going on
+ variable QUIET 0
+ # Update command (eg. 'update')
+ variable UPDATE_COMMAND {::Compiler::doNothing}
+ # Bool: 1 == abort now
+ variable ABORT_VARIABLE 0
+ # Text output command (eg. 'puts')
+ variable TEXT_OUPUT_COMMAND {puts}
+ # Disable color output
+ variable NOCOLOR 1
+
+ ## Restore default settings
+ # @return void
+ proc restoreDefaults {} {
+
+ variable _symbols ;# Control: $SYMBOLS
+ variable _print ;# Control: $PRINT
+ variable _object ;# Control: $OBJECT
+
+ variable SYMBOLS ;# Bool: Include table of symbols to code listing
+ variable NOMOD ;# Bool: Do not use predefined SFR register addresses
+ variable PAGING ;# Bool: Use 'FF' in code listing
+ variable PAGELENGTH ;# Number of characters per line in code listing
+ variable PAGEWIDTH ;# Number of characters per line in code listing
+ variable TITLE ;# Title string for code listing
+ variable DATE ;# Date string for code listing
+ variable OBJECT ;# Bool: Generate IHEX8 object file
+ variable OBJECT_FILE ;# Location of IHEX8 object file
+ variable PRINT ;# Bool: Generate Code Listing file
+ variable PRINT_FILE ;# Location of Code Listing file
+ variable INPUT_FILE_NAME ;# Location of input file
+
+ variable _object_file ;# Location of IHEX8 object file
+ variable _print_file ;# Location of Code Listing file
+ variable _title_value ;# Title string for code listing
+ variable _date_value ;# Date string for code listing
+ variable _nomod_value ;# Bool: use predefined SFR addresses
+ variable _paging_value ;# Bool: Use Form Feeds in code listing
+ variable _pagelength_value ;# Number of lines per page in code listing
+ variable _pagewidth_value ;# Number of characters per line in code listing
+
+ # Reset settings
+ foreach var {
+ NOMOD PAGING PAGELENGTH PAGEWIDTH
+ TITLE DATE OBJECT_FILE PRINT_FILE
+ } default {
+ _nomod_value _paging_value _pagelength_value _pagewidth_value
+ _title_value _date_value _object_file _print_file
+ } {
+ set $var [subst "\$$default"]
+ }
+
+ # Finalize
+ if {($_symbols == 1) || ($_symbols == 0)} {
+ set SYMBOLS 1
+ } elseif {$_symbols == 2} {
+ set SYMBOLS 0
+ }
+ if {($_print == 1) || ($_print == 0)} {
+ set PRINT 1
+ } elseif {$_print == 2} {
+ set PRINT 0
+ }
+ if {($_object == 1) || ($_object == 0)} {
+ set OBJECT 1
+ } elseif {$_object == 2} {
+ set OBJECT 0
+ }
+ }
+ }
+
+ ## Generate parser-friendly error code
+ # @parm String code - Basic message specification (e.g. EL means ERROR and LINE)
+ # @return Char - A special (unprintable) character represention the message
+ proc msgc {code} {
+ variable in_IDE ;# Bool: Running in IDE (I mean GUI)
+
+ if {!$in_IDE} {
+ return {}
+ }
+
+ switch -- $code {
+ {EL} { ;# ERROR and LINE specification
+ return "|EL|"
+ }
+ {EN} { ;# Just ERROR
+ return "|EN|"
+ }
+ {WL} { ;# WARNING and LINE specification
+ return "|WL|"
+ }
+ {WN} { ;# Just WARNING
+ return "|WN|"
+ }
+ {SN} { ;# SUCCESS
+ return "|SN|"
+ }
+ }
+ }
+}
+
+# Compiler settings to defaults
+Compiler::Settings::restoreDefaults
diff --git a/lib/compiler/compilerconsts.tcl b/lib/compiler/compilerconsts.tcl
new file mode 100755
index 0000000..175ceb9
--- /dev/null
+++ b/lib/compiler/compilerconsts.tcl
@@ -0,0 +1,873 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Defines compiler constatnts. This code is part of Compiler
+# (see compiler.tcl) and many other sources.
+#
+# Contains:
+# - Definition of instruction set
+# - Lists of defined instructions and durectives
+# - many other things (see code)
+# --------------------------------------------------------------------------
+
+namespace eval CompilerConsts {
+ # Directives defining constants
+ variable ConstDefinitionDirectives {
+ bit set equ code data xdata idata flag
+ }
+ # Data segment selection directives
+ variable ConstDataSegmentSelectionDirectives {
+ bseg dseg iseg xseg
+ }
+ # Data memory reservation directives
+ variable ConstDataMemoryReservationDirectives {
+ ds dbit
+ }
+ # Fixed (non-variable) operands
+ variable FixedOperands {
+ a c ab @dptr @a+dptr
+ @a+pc r0 r1 r2 r3
+ r4 r5 r6 r7 @r0
+ @r1 dptr
+ }
+ # All 8051 instructions
+ variable AllInstructions {
+ acall add addc ajmp anl
+ anl cjne clr cpl da
+ dec div djnz inc jb
+ jbc jc jmp jnb jnc
+ jnz jz lcall ljmp mov
+ movc movx mul nop orl
+ pop push ret reti rl
+ rr rlc rrc setb sjmp
+ subb swap xch xchd xrl
+ call
+ }
+ # All compiler directives
+ variable AllDirectives {
+ bit set equ code data
+ xdata idata bseg dseg iseg
+ xseg ds dbit cseg db
+ dw include list nolist
+ }
+ # Addresses of SFR registers
+ variable MapOfSFRArea {
+ {P0 80} {SP 81} {DPL 82} {DPH 83}
+ {PCON 87} {TCON 88} {TMOD 89} {TL0 8A}
+ {TL1 8B} {TH0 8C} {TH1 8D} {P1 90}
+ {SCON 98} {SBUF 99} {P2 A0} {IE A8}
+ {P3 B0} {IP B8} {PSW D0} {ACC E0}
+ {B F0} {P4 C0} {WDTCON A7} {EECON 96}
+ {DP0H 83} {DP0L 82} {DP1H 85} {DP1L 84}
+ {T2CON C8} {T2MOD C9} {RCAP2L CA} {RCAP2H CB}
+ {TL2 CC} {TH2 CD} {AUXR1 A2} {WDTRST A6}
+ {CLKREG 8F} {ACSR 97} {IPH B7} {SADDR A9}
+ {SADEN B9} {SPCR D5} {SPSR AA} {SPDR 86}
+ {AUXR 8E} {CKCON 8F} {WDTPRG A7}
+
+ {CH F9} {CCAP0H FA} {CCAP1H FB} {CCAP2H FC}
+ {CCAP3H FD} {CCAP4H FE} {CCAPL2H FC} {CCAPL3H FD}
+ {CCAPL4H FE} {ADCLK F2} {ADCON F3} {ADDL F4}
+ {ADDH F5} {ADCF F6} {P5 E8} {CL E9}
+ {CCAP0L EA} {CCAP1L EB} {CCAPL2L EC} {CCAPL3L ED}
+ {CCAPL4L EE} {CCON D8} {CMOD D9} {CCAPM0 DA}
+ {CCAPM1 DB} {CCAPM2 DC} {CCAPM3 DD} {CCAPM4 DE}
+ {P1M2 E2} {P3M2 E3} {P4M2 E4} {P1M1 D4}
+ {P3M1 D5} {P4M1 D6} {SPCON C3} {SPSTA C4}
+ {SPDAT C5} {IPL0 B8} {IPL1 B2} {IPH1 B3}
+ {IPH0 B7} {BRL 9A} {BDRCON 9B} {BDRCON_1 9C}
+ {KBLS 9C} {KBE 9D} {KBF 9E} {SADEN_0 B9}
+ {SADEN_1 BA} {SADDR_0 A9} {SADDR_1 AA} {CKSEL 85}
+ {OSCCON 86} {CKRL 97} {CKCON0 8F}
+ }
+
+ # Addresses of bits of SFR registers
+ variable MapOfSFRBitArea {
+ {IT0 88} {IE0 89} {IT1 8A} {IE1 8B}
+ {TR0 8C} {TF0 8D} {TR1 8E} {TF1 8F}
+
+ {RI 98} {TI 99} {RB8 9A} {TB8 9B}
+ {REN 9C} {SM2 9D} {SM1 9E} {SM0 9F}
+ {FE 9F}
+
+ {EX0 A8} {ET0 A9} {EX1 AA} {ET1 AB}
+ {ES AC} {ET2 AD} {EC AE} {EA AF}
+
+ {RXD B0} {TXD B1} {INT0 B2} {INT1 B3}
+ {T0 B4} {T1 B5} {WR B6} {RD B7}
+
+ {PX0 B8} {PT0 B9} {PX1 BA} {PT1 BB}
+ {PS BC} {PT2 BD} {PC BE}
+
+ {PPCL BE} {PT2L BD} {PSL BC}
+ {PT1L BB} {PX1L BA} {PT0L B9} {PX0L B8}
+
+ {TF2 CF} {EXF2 CE} {RCLK CD} {TCLK CC}
+ {EXEN2 CB} {TR2 CA} {CT2 C9} {CPRL2 C8}
+
+ {P D0} {OV D2} {RS0 D3}
+ {RS1 D4} {F0 D5} {AC D6} {CY D7}
+
+ {CR DE} {CCF4 DC}
+ {CCF3 DB} {CCF2 DA} {CCF1 D9} {CCF0 D8}
+ }
+
+ # Program vectors
+ variable progVectors {
+ {RESET 00} {EXTI0 03} {TIMER0 0B} {EXTI1 13}
+ {TIMER1 1B} {SINT 23} {TIMER2 2B} {CFINT 33}
+ }
+
+ ## Instruction set definition
+ # ---------------------------------------------------------------------------------------------
+ #
+ # Format:
+ # {
+ # {Instruction} {Operands_count
+ # {{Operand_type_0 Operand_type_1 ...} Code_length Opcode Opcode_mask Instr_cycles_per_iteration}
+ # ...
+ # }
+ # ...
+ # }
+ # Note: Triple dot means "et catera"
+ # ---------------------------------------------------------------------------------------------
+ #
+ # Opreand types:
+ # code8 - 8 bit offset for relative jump
+ # code11 - 11 bit program memory address
+ # code16 - 16 bit program memory address
+ # imm8 - 8 bit constant data
+ # imm16 - 16 bit constant data
+ # data - internal data memory or SFR direct address
+ # bit - bit memory direct address
+ #
+ # DPTR - Data PoinTeR register (16 bit)
+ # A - Primary work register (Accumulator)
+ # AB - 16bit Accumulator
+ # R0..R7 - Register of active bank
+ # C - Carry flag in PSW
+ # @R0, R1, @DPTR, @A+PC, @A+DPTR - Indirect addresses
+ # ---------------------------------------------------------------------------------------------
+ # For instance, instruction "acall" takes "1" operand,
+ # that operand must be an operand of type "code11", acall takes "2" bytes
+ # in the program memory. Its opcode is 0x11 and opcode mask is 0xE0
+ # and instruction time is 2 cycles (for 8051 is means 24 clock periods).
+ # ---------------------------------------------------------------------------------------------
+ #
+ # Opcode mask explanation (for acall):
+ # Bit number: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 hex
+ #
+ # Opcode mask: - - - 1 1 1 0 0 0 0 0 -- E0
+ # Operand: 1 1 1 1 1 1 1 1 1 1 1 -7 FF
+ # -- $processing --
+ # Final operand: 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 E0 FF
+ # -- OR --
+ # Opcode: 0 0 0 1 0 0 0 1 - - - - - - - - -- 11
+ # ----------------------------------------------
+ # Processor code: 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 F1 FF
+ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ #
+ # Note: $processing == "ones stands for operand code and zeroes are just zeroes"
+ # ---------------------------------------------------------------------------------------------
+ # Note: I know it doesn't make much sence, but I don't know any another way how to explain that.
+ # I'm sorry for that, see the list.
+ # ---------------------------------------------------------------------------------------------
+ variable InstructionSetDefinition {
+ {acall} {1
+ {
+ {{code11 } 2 11 E0 2}
+ }
+ }
+ {add} {2
+ {
+ {{A imm8 } 2 24 00 1}
+ {{A data } 2 25 00 1}
+
+ {{A @R0 } 1 26 00 1}
+ {{A @R1 } 1 27 00 1}
+
+ {{A R0 } 1 28 00 1}
+ {{A R1 } 1 29 00 1}
+ {{A R2 } 1 2A 00 1}
+ {{A R3 } 1 2B 00 1}
+ {{A R4 } 1 2C 00 1}
+ {{A R5 } 1 2D 00 1}
+ {{A R6 } 1 2E 00 1}
+ {{A R7 } 1 2F 00 1}
+ }
+ }
+ {addc} {2
+ {
+ {{A imm8 } 2 34 00 1}
+ {{A data } 2 35 00 1}
+
+ {{A @R0 } 1 36 00 1}
+ {{A @R1 } 1 37 00 1}
+
+ {{A R0 } 1 38 00 1}
+ {{A R1 } 1 39 00 1}
+ {{A R2 } 1 3A 00 1}
+ {{A R3 } 1 3B 00 1}
+ {{A R4 } 1 3C 00 1}
+ {{A R5 } 1 3D 00 1}
+ {{A R6 } 1 3E 00 1}
+ {{A R7 } 1 3F 00 1}
+ }
+ }
+ {ajmp} {1
+ {
+ {{code11 } 2 01 E0 2}
+ }
+ }
+ {anl} {2
+ {
+ {{data A } 2 52 00 1}
+ {{data imm8 } 3 53 00 2}
+
+ {{A imm8 } 2 54 00 1}
+ {{A data } 2 55 00 1}
+
+ {{A @R0 } 1 56 00 1}
+ {{A @R1 } 1 57 00 1}
+
+ {{A R0 } 1 58 00 1}
+ {{A R1 } 1 59 00 1}
+ {{A R2 } 1 5A 00 1}
+ {{A R3 } 1 5B 00 1}
+ {{A R4 } 1 5C 00 1}
+ {{A R5 } 1 5D 00 1}
+ {{A R6 } 1 5E 00 1}
+ {{A R7 } 1 5F 00 1}
+
+ {{C bit } 2 82 00 2}
+ {{C /bit } 2 B0 00 2}
+ }
+ }
+ {call} {1
+ {
+ {{code16 } 3 12 00 2}
+ {{code11 } 2 11 E0 2}
+ }
+ }
+ {cjne} {3
+ {
+ {{A imm8 code8} 3 B4 00 2}
+ {{A data code8} 3 B5 00 2}
+
+ {{@R0 imm8 code8} 3 B6 00 2}
+ {{@R1 imm8 code8} 3 B7 00 2}
+
+ {{R0 imm8 code8} 3 B8 00 2}
+ {{R1 imm8 code8} 3 B9 00 2}
+ {{R2 imm8 code8} 3 BA 00 2}
+ {{R3 imm8 code8} 3 BB 00 2}
+ {{R4 imm8 code8} 3 BC 00 2}
+ {{R5 imm8 code8} 3 BD 00 2}
+ {{R6 imm8 code8} 3 BE 00 2}
+ {{R7 imm8 code8} 3 BF 00 2}
+ }
+ }
+ {clr} {1
+ {
+ {{A } 1 E4 00 1}
+ {{bit } 2 C2 00 1}
+ {{C } 1 C3 00 1}
+ }
+ }
+ {cpl} {1
+ {
+ {{A } 1 F4 00 1}
+ {{bit } 2 B2 00 1}
+ {{C } 1 B3 00 1}
+ }
+ }
+ {da} {1
+ {
+ {{A } 1 D4 00 1}
+ }
+ }
+ {dec} {1
+ {
+ {{A } 1 14 00 1}
+ {{data } 2 15 00 1}
+
+ {{@R0 } 1 16 00 1}
+ {{@R1 } 1 17 00 1}
+
+ {{R0 } 1 18 00 1}
+ {{R1 } 1 19 00 1}
+ {{R2 } 1 1A 00 1}
+ {{R3 } 1 1B 00 1}
+ {{R4 } 1 1C 00 1}
+ {{R5 } 1 1D 00 1}
+ {{R6 } 1 1E 00 1}
+ {{R7 } 1 1F 00 1}
+ }
+ }
+ {div} {1
+ {
+ {{AB } 1 84 00 4}
+ }
+ }
+ {djnz} {2
+ {
+ {{data code8 } 3 D5 00 2}
+
+ {{R0 code8 } 2 D8 00 2}
+ {{R1 code8 } 2 D9 00 2}
+ {{R2 code8 } 2 DA 00 2}
+ {{R3 code8 } 2 DB 00 2}
+ {{R4 code8 } 2 DC 00 2}
+ {{R5 code8 } 2 DD 00 2}
+ {{R6 code8 } 2 DE 00 2}
+ {{R7 code8 } 2 DF 00 2}
+ }
+ }
+ {inc} {1
+ {
+ {{A } 1 04 00 1}
+ {{data } 2 05 00 1}
+
+ {{@R0 } 1 06 00 1}
+ {{@R1 } 1 07 00 1}
+
+ {{R0 } 1 08 00 1}
+ {{R1 } 1 09 00 1}
+ {{R2 } 1 0A 00 1}
+ {{R3 } 1 0B 00 1}
+ {{R4 } 1 0C 00 1}
+ {{R5 } 1 0D 00 1}
+ {{R6 } 1 0E 00 1}
+ {{R7 } 1 0F 00 1}
+
+ {{DPTR } 1 A3 00 2}
+ }
+ }
+ {jb} {2
+ {
+ {{bit code8 } 3 20 00 2}
+ }
+ }
+ {jbc} {2
+ {
+ {{bit code8 } 3 10 00 2}
+ }
+ }
+ {jc} {1
+ {
+ {{code8 } 2 40 00 2}
+ }
+ }
+ {jmp} {1
+ {
+ {{@A+DPTR } 1 73 00 2}
+ {{code16 } 3 02 00 2}
+ {{code11 } 2 01 E0 2}
+ {{code8 } 2 80 00 2}
+ }
+ }
+ {jnb} {2
+ {
+ {{bit code8 } 3 30 00 2}
+ }
+ }
+ {jnc} {1
+ {
+ {{code8 } 2 50 00 2}
+ }
+ }
+ {jnz} {1
+ {
+ {{code8 } 2 70 00 2}
+ }
+ }
+ {jz} {1
+ {
+ {{code8 } 2 60 00 2}
+ }
+ }
+ {lcall} {1
+ {
+ {{code16 } 3 12 00 2}
+ }
+ }
+ {ljmp} {1
+ {
+ {{code16 } 3 02 00 2}
+ }
+ }
+ {mov} {2
+ {
+ {{A imm8 } 2 74 00 1}
+ {{A data } 2 E5 00 1}
+
+ {{A @R0 } 1 E6 00 1}
+ {{A @R1 } 1 E7 00 1}
+
+ {{A R0 } 1 E8 00 1}
+ {{A R1 } 1 E9 00 1}
+ {{A R2 } 1 EA 00 1}
+ {{A R3 } 1 EB 00 1}
+ {{A R4 } 1 EC 00 1}
+ {{A R5 } 1 ED 00 1}
+ {{A R6 } 1 EE 00 1}
+ {{A R7 } 1 EF 00 1}
+
+
+
+ {{data A } 2 F5 00 1}
+
+ {{data imm8 } 3 75 00 2}
+ {{data data } 3 85 00 2}
+
+ {{data @R0 } 2 86 00 2}
+ {{data @R1 } 2 87 00 2}
+
+ {{data R0 } 2 88 00 2}
+ {{data R1 } 2 89 00 2}
+ {{data R2 } 2 8A 00 2}
+ {{data R3 } 2 8B 00 2}
+ {{data R4 } 2 8C 00 2}
+ {{data R5 } 2 8D 00 2}
+ {{data R6 } 2 8E 00 2}
+ {{data R7 } 2 8F 00 2}
+
+
+
+ {{@R0 A } 1 F6 00 1}
+ {{@R1 A } 1 F7 00 1}
+
+ {{@R0 imm8 } 2 76 00 1}
+ {{@R1 imm8 } 2 77 00 1}
+
+ {{@R0 data } 2 A6 00 2}
+ {{@R1 data } 2 A7 00 2}
+
+
+
+ {{R0 A } 1 F8 00 1}
+ {{R1 A } 1 F9 00 1}
+ {{R2 A } 1 FA 00 1}
+ {{R3 A } 1 FB 00 1}
+ {{R4 A } 1 FC 00 1}
+ {{R5 A } 1 FD 00 1}
+ {{R6 A } 1 FE 00 1}
+ {{R7 A } 1 FF 00 1}
+
+ {{R0 imm8 } 2 78 00 1}
+ {{R1 imm8 } 2 79 00 1}
+ {{R2 imm8 } 2 7A 00 1}
+ {{R3 imm8 } 2 7B 00 1}
+ {{R4 imm8 } 2 7C 00 1}
+ {{R5 imm8 } 2 7D 00 1}
+ {{R6 imm8 } 2 7E 00 1}
+ {{R7 imm8 } 2 7F 00 1}
+
+ {{R0 data } 2 A8 00 2}
+ {{R1 data } 2 A9 00 2}
+ {{R2 data } 2 AA 00 2}
+ {{R3 data } 2 AB 00 2}
+ {{R4 data } 2 AC 00 2}
+ {{R5 data } 2 AD 00 2}
+ {{R6 data } 2 AE 00 2}
+ {{R7 data } 2 AF 00 2}
+
+
+
+ {{DPTR imm16 } 3 90 00 2}
+
+ {{bit C } 2 92 00 2}
+
+ {{C bit } 2 A2 00 1}
+ }
+ }
+ {movc} {2
+ {
+ {{A @A+DPTR } 1 93 00 2}
+ {{A @A+PC } 1 83 00 2}
+ }
+ }
+ {movx} {2
+ {
+ {{A @R0 } 1 E2 00 2}
+ {{A @R1 } 1 E3 00 2}
+ {{A @DPTR } 1 E0 00 2}
+
+ {{@R0 A } 1 F2 00 2}
+ {{@R1 A } 1 F3 00 2}
+ {{@DPTR A } 1 F0 00 2}
+ }
+ }
+ {mul} {1
+ {
+ {{AB } 1 A4 00 4}
+ }
+ }
+ {nop} {0
+ {
+ {{ } 1 00 00 1}
+ }
+ }
+ {orl} {2
+ {
+ {{data A } 2 42 00 1}
+ {{data imm8 } 3 43 00 2}
+
+ {{A imm8 } 2 44 00 1}
+ {{A data } 2 45 00 1}
+
+ {{A @R0 } 1 46 00 1}
+ {{A @R1 } 1 47 00 1}
+
+ {{A R0 } 1 48 00 1}
+ {{A R1 } 1 49 00 1}
+ {{A R2 } 1 4A 00 1}
+ {{A R3 } 1 4B 00 1}
+ {{A R4 } 1 4C 00 1}
+ {{A R5 } 1 4D 00 1}
+ {{A R6 } 1 4E 00 1}
+ {{A R7 } 1 4F 00 1}
+
+ {{C bit } 2 72 00 2}
+ {{C /bit } 2 A0 00 2}
+ }
+ }
+ {pop} {1
+ {
+ {{data } 2 D0 00 2}
+ }
+ }
+ {push} {1
+ {
+ {{data } 2 C0 00 2}
+ }
+ }
+ {ret} {0
+ {
+ {{ } 1 22 00 2}
+ }
+ }
+ {reti} {0
+ {
+ {{ } 1 32 00 2}
+ }
+ }
+ {rl} {1
+ {
+ {{A } 1 23 00 1}
+ }
+ }
+ {rr} {1
+ {
+ {{A } 1 03 00 1}
+ }
+ }
+ {rlc} {1
+ {
+ {{A } 1 33 00 1}
+ }
+ }
+ {rrc} {1
+ {
+ {{A } 1 13 00 1}
+ }
+ }
+ {setb} {1
+ {
+ {{C } 1 D3 00 1}
+ {{bit } 2 D2 00 1}
+ }
+ }
+ {sjmp} {1
+ {
+ {{code8 } 2 80 00 2}
+ }
+ }
+ {subb} {2
+ {
+ {{A imm8 } 2 94 00 1}
+ {{A data } 2 95 00 1}
+
+ {{A @R0 } 1 96 00 1}
+ {{A @R1 } 1 97 00 1}
+
+ {{A R0 } 1 98 00 1}
+ {{A R1 } 1 99 00 1}
+ {{A R2 } 1 9A 00 1}
+ {{A R3 } 1 9B 00 1}
+ {{A R4 } 1 9C 00 1}
+ {{A R5 } 1 9D 00 1}
+ {{A R6 } 1 9E 00 1}
+ {{A R7 } 1 9F 00 1}
+ }
+ }
+ {swap} {1
+ {
+ {{A } 1 C4 00 1}
+ }
+ }
+ {xch} {2
+ {
+ {{A data } 2 C5 00 1}
+
+ {{A @R0 } 1 C6 00 1}
+ {{A @R1 } 1 C7 00 1}
+
+ {{A R0 } 1 C8 00 1}
+ {{A R1 } 1 C9 00 1}
+ {{A R2 } 1 CA 00 1}
+ {{A R3 } 1 CB 00 1}
+ {{A R4 } 1 CC 00 1}
+ {{A R5 } 1 CD 00 1}
+ {{A R6 } 1 CE 00 1}
+ {{A R7 } 1 CF 00 1}
+ }
+ }
+ {xchd} {2
+ {
+ {{A @R0 } 1 D6 00 1}
+ {{A @R1 } 1 D7 00 1}
+ }
+ }
+ {xrl} {2
+ {
+ {{data A } 2 62 00 1}
+ {{data imm8 } 3 63 00 2}
+
+ {{A imm8 } 2 64 00 1}
+ {{A data } 2 65 00 1}
+
+ {{A @R0 } 1 66 00 1}
+ {{A @R1 } 1 67 00 1}
+
+ {{A R0 } 1 68 00 1}
+ {{A R1 } 1 69 00 1}
+ {{A R2 } 1 6A 00 1}
+ {{A R3 } 1 6B 00 1}
+ {{A R4 } 1 6C 00 1}
+ {{A R5 } 1 6D 00 1}
+ {{A R6 } 1 6E 00 1}
+ {{A R7 } 1 6F 00 1}
+ }
+ }
+ }
+
+ variable InstructionDefinition ;# Array of instruction efinitions (key: instrcution name)
+ variable SimpleOperandDefinitions ;# Array of simple operand definitions (eg. '#', '/')
+ variable defined_OPCODE {} ;# List of defined opcodes
+ variable defined_SFR {} ;# List of defined SFR (lowercase)
+ variable defined_SFRBitArea {} ;# List of defined bit addressable bits in SFR (lowercase)
+ variable defined_progVectors {} ;# List of defined interrupt vectors (lowercase)
+ variable Opcode ;# Array of instruction defnitions (key: OP code)
+
+ ## Initialize NS variables (must be called to make this NS usable)
+ # @return void
+ proc initialize {} {
+ variable InstructionDefinition ;# Array of instruction efinitions (key: instrcution name)
+ variable InstructionSetDefinition ;# List of instruction definitions
+ variable SimpleOperandDefinitions ;# Array of simple operand definitions (eg. '#', '/')
+ variable defined_OPCODE ;# List of defined opcodes
+ variable defined_SFR ;# List of defined SFR
+ variable defined_SFRBitArea ;# List of defined bit addressable bits in SFR
+ variable defined_progVectors ;# List of defined interrupt vectors
+ variable Opcode ;# Array of instruction defnitions (key: OP code)
+
+ # Remove redutant space from lists
+ foreach var {
+ ConstDefinitionDirectives
+ ConstDataSegmentSelectionDirectives
+ ConstDataMemoryReservationDirectives
+ FixedOperands
+ AllInstructions
+ AllDirectives
+ MapOfSFRArea
+ MapOfSFRBitArea
+ progVectors
+ } {
+ variable $var
+ set val [subst "\$$var"]
+ regsub -all {\s+} $val { } $var
+ }
+
+ # Initialize defined_SFR, defined_SFRBitArea and defined_progVectors
+ foreach item $MapOfSFRArea {
+ lappend defined_SFR [string tolower [lindex $item 0]]
+ }
+ foreach item $MapOfSFRBitArea {
+ lappend defined_SFRBitArea [string tolower [lindex $item 0]]
+ }
+ foreach item $progVectors {
+ lappend defined_progVectors [string tolower [lindex $item 0]]
+ }
+
+ # Create new constants from list of instructin definitions
+ for {set i 0} {1} {incr i} {
+ # Determinate instruction name
+ set instruction [lindex $InstructionSetDefinition $i]
+ if {$instruction == {}} {break}
+
+ # Determinate instruction definition
+ incr i
+ set def [lindex $InstructionSetDefinition $i]
+ set def [regsub -all {\s+} $def { }]
+
+ # Initialize simple operands definition and instruction definition array
+ set SimpleOperandDefinitions($instruction) {}
+ set InstructionDefinition($instruction) [string tolower $def]
+
+ # Iterate over oprand set definitions
+ set def_idx 0
+ foreach code_def [lindex $def 1] {
+ incr def_idx
+
+ # Local variables
+ set mask [lindex $code_def 3] ;# OP code mask
+ set opcode [lindex $code_def 2] ;# OP code
+ set len [lindex $code_def 1] ;# Code length
+ set operands [lindex $code_def 0] ;# Operand types
+ set new_oprs {} ;# List of simple operands
+
+ # Create list of simple operands
+ foreach opr $operands {
+ # Direct addressing
+ if {[lsearch {data bit code8 code11 code16} $opr] != -1} {
+ lappend new_oprs {D}
+ # Immediate addressing
+ } elseif {$opr == {imm8} || $opr == {imm16}} {
+ lappend new_oprs {#}
+ # Inverted bit
+ } elseif {$opr == {/bit}} {
+ lappend new_oprs {/}
+ # Fixed operand
+ } else {
+ lappend new_oprs $opr
+ }
+ }
+ lappend SimpleOperandDefinitions($instruction) $new_oprs
+
+ ## Create array of instruction definitions by OP codes (for disassembler)
+ # No OP code mask
+ if {$mask == {00}} {
+ # Skip "CALL" and "JMP" (except 1st op. set)
+ if {!($instruction == {call} || ($instruction == {jmp} && $def_idx > 1))} {
+ if {[lsearch $defined_OPCODE $opcode] != -1} {
+ puts "Instruction set parse error 0 -- opcode $opcode"
+ continue
+ }
+ lappend defined_OPCODE $opcode
+ set Opcode($opcode) "$instruction {$operands} $len {}"
+ }
+ # Non-zero OP code mask
+ } {
+ # Translate OP code and its mask to list of booleans
+ set opcode [assembler::hex2binlist $opcode]
+ set mask [assembler::hex2binlist $mask]
+
+ # Insure than masked OP code bits are zeroes
+ set idx 0
+ foreach mask_bit $mask {
+ if {$mask_bit} {
+ lset opcode $idx 0
+ }
+ incr idx
+ }
+
+ # Determinate number of positive bits in the
+ # mask and maximum value under mask
+ set max 0
+ set val 1
+ set bits 0
+ foreach bit $mask {
+ if {$bit} {
+ incr bits
+ incr max $val
+ set val [expr {$val * 2}]
+ }
+ }
+
+ # Determinate list of possible high-order values
+ # of opreands acording to the mask
+ set values {}
+ set tmp 0
+ set tmp_len 0
+ for {set val 0} {$val <= $max} {incr val} {
+ set tmp [NumSystem::dec2bin $val]
+ set tmp_len [string length $tmp]
+ if {$tmp_len != $bits} {
+ set tmp "[string repeat 0 [expr {$bits - $tmp_len}]]$tmp"
+ }
+ lappend values $tmp
+ }
+
+ # Detereminate list of possible OP codes and
+ # corresponding high-order operand values
+ set opcodes {}
+ set new_values {}
+ foreach val $values {
+ set tmp {}
+ set idx 0
+ foreach mask_bit $mask opcode_bit $opcode {
+ if {$mask_bit} {
+ append tmp [string index $val $idx]
+ incr idx
+ } {
+ append tmp $opcode_bit
+ }
+ }
+ set tmp [NumSystem::bin2hex $tmp]
+ if {[string length $tmp] == 1} {
+ set tmp "0$tmp"
+ }
+ lappend opcodes $tmp
+ lappend new_values [NumSystem::bin2hex $val]
+ }
+ set values $new_values
+
+ # Append results to Array of instruction definitions by OP codes
+ foreach opcode $opcodes masked_opr $values {
+ # Skip "CALL" and "JMP" (except 1st op. set)
+ if {$instruction == {call}} {
+ break
+ } elseif {$instruction == {jmp} && $def_idx > 1} {
+ break
+ }
+
+ # Register OP code
+ if {[lsearch $defined_OPCODE $opcode] != -1} {
+ puts "Instruction set parse error 1 -- opcode $opcode"
+ continue
+ }
+ lappend defined_OPCODE $opcode
+ set Opcode($opcode) [list $instruction $operands $len $masked_opr]
+
+ }
+ }
+ }
+ }
+ }
+}
+
+# Initialize NS variables
+CompilerConsts::initialize
diff --git a/lib/compiler/disassembler.tcl b/lib/compiler/disassembler.tcl
new file mode 100755
index 0000000..b74fedf
--- /dev/null
+++ b/lib/compiler/disassembler.tcl
@@ -0,0 +1,664 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# Disassembler 8051
+#
+# DESCRIPTION:
+# Converts data from Intel HEX 8 fromat to assembler 51.
+#
+# SUMMARY:
+# * Generated code doesn't contain any compiler directives except 'DB', 'ORG' and 'END'.
+# * Unrecognized opcodes are traslated to 'DB opcode'
+# * Labels referencing to "nowhere" are traslated as 'label EQU address'
+# * Input code must be absolutely clear so it mustn't contain any
+# ambiguity and all addresses must be in icremental order
+# * Lines in hex code which don't start with colon ':' are ignored
+#
+# USAGE:
+# disassembler::compile $hex_data ;# -> asm code
+#
+# --------------------------------------------------------------------------
+
+namespace eval disassembler {
+
+ variable tmp_asm {} ;# Tempotary variable for code procedure: 'final_stage'
+ variable hex_data {} ;# Raw input data
+ variable hex {} ;# Adjusted input data, list: {addr hex0 hex1 hex2 ...}
+ variable lineNum {} ;# Number of line currently beeing parsed
+ variable error_count {} ;# Number of errors raised during decompilation
+ variable warning_count {} ;# Number of warnings occured
+ variable label_idx {} ;# Label index
+ variable final_lbls 0 ;# Number of final labels
+ variable label ;# Array of tempotary labels, label(int) -> addr
+ variable asm {} ;# Resulting source code
+
+
+ # ----------------------------------------------------------------
+ # GENERAL PURPOSE PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Initiate decompilation
+ # @parm string data - Input IHEX8 code
+ # @return string - output asm code or {}
+ proc compile {data} {
+
+ variable hex_data ;# Raw input
+ variable hex ;# Adjusted input data, list: {addr hex0 hex1 hex2 ...}
+ variable lineNum ;# Number of line currently beeing parsed
+ variable error_count ;# Number of errors raised during decompilation
+ variable warning_count ;# Number of warnings occured
+ variable asm ;# Resulting source code
+
+ set error_count 0 ;# reset errors count
+ set warning_count 0 ;# reset errors count
+ set hex {} ;# clear hex data used for futher prosessing
+ set hex_data $data ;# set input data
+
+ # Adjust input data
+ regexp -all {\r\n?} hex_data "\n" hex_data
+ set hex_data [split $hex_data "\n"]
+
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {SN}][mc "Initializing disassembler ..."]
+
+ # Verify input code validity and set variable 'hex'
+ adjust_code
+
+ # Exit if the code does not seem to be valid
+ if {$error_count != 0} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "Disassembly FAILED ..."]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EN}][mc "\033\[31;1mDisassembly FAILED\033\[m ..."]
+ }
+ return {}
+ }
+
+ if {${Compiler::Settings::ABORT_VARIABLE}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}][mc "Aborted"]
+ free_resources
+ return {}
+ }
+
+ # Convert processor code into asm code
+ decompile_code
+
+ if {${Compiler::Settings::ABORT_VARIABLE}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}[mc "Aborted"]
+ free_resources
+ return {}
+ }
+
+ # Create labels in resulting code
+ parse_labels
+
+ if {${Compiler::Settings::ABORT_VARIABLE}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}][mc "Aborted"]
+ free_resources
+ return {}
+ }
+
+ # Final stage
+ final_stage
+
+ if {${Compiler::Settings::ABORT_VARIABLE}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}][mc "Aborted"]
+ free_resources
+ return {}
+ }
+
+ # Free memory used during decompilation
+ free_resources
+
+ if {${Compiler::Settings::ABORT_VARIABLE}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EN}][mc "Aborted"]
+ free_resources
+ return {}
+ }
+
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {SN}][mc "Disassembly complete"]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[32;1mDisassembly complete\033\[m"]
+ }
+
+ # Return resulting source code
+ return $asm
+ }
+
+
+ # ----------------------------------------------------------------
+ # INTERNAL AUXILIARY PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Verify input code validity and set variable 'hex'
+ # @return void
+ proc adjust_code {} {
+ variable hex ;# Adjusted input data
+ variable lineNum ;# Number of line currently beeing parsed
+ variable hex_data ;# Raw input (hex data)
+
+ set pointer -1 ;# Program address pointer
+ set lineNum 0 ;# Line number
+
+ foreach line $hex_data {
+
+ if {[expr {$lineNum % 10}] == 0} ${Compiler::Settings::UPDATE_COMMAND}
+
+ incr lineNum ;# line number
+
+ # Skip comments
+ if {[string index $line 0] != {:}} {continue}
+
+ # Check for valid characters
+ set line [string range $line 1 end]
+ if {![regexp {^[0-9A-Fa-f]*$} $line]} {
+ Error $lineNum [mc "Invalid line (line contain not allowed characters)"]
+ continue
+ }
+
+ # Check for odd number of characters
+ set len [string length $line]
+ if {[expr {$len % 2}] != 0} {
+ Error $lineNum [mc "Line do not contain odd number of chars"]
+ continue
+ }
+
+ # Check for valid checksum
+ set check [string range $line {end-1} end]
+ set new_check [::IHexTools::getCheckSum [string range $line 0 {end-2}]]
+ if {$check != $new_check} {
+ Error $lineNum [mc "Bad checksum, given: %s ; computed: %s" $check $new_check]
+ continue
+ }
+
+ # Check for correct record type
+ set type [string range $line 6 7]
+ if {$type == {01}} {
+ break
+ } elseif {$type != {00}} {
+ Error $lineNum [mc "Unknown record type number `%s' (Intel HEX 8 can contain only 00 and 01)" $type]
+ }
+
+ # Check valid line length
+ set len [string range $line 0 1]
+ set len [expr "0x$len"]
+ set data [string range $line 8 {end-2}]
+ if {$len != ([string length $data] / 2)} {
+ Error $lineNum [mc "Length field do not corespond true data length"]
+ continue
+ }
+
+ # Check for valid incremental addressing without any ambiguity
+ set addr_hex [string range $line 2 5]
+ set addr [expr "0x$addr_hex"]
+ if {$addr <= $pointer} {
+ Error $lineNum [mc "Unexpected address -- code is not well formated"]
+ continue
+ } elseif {$addr > ($pointer + 1)} {
+ set pointer $addr
+ } {
+ incr pointer $len
+ }
+
+ ## Convert line into this form:
+ # {
+ # {addr hex hex hex ...}
+ # ...
+ # }
+ set len [expr {($len * 2) - 1}]
+ set line {}
+ for {set i 0} {$i <= $len} {incr i} {
+ append line { }
+ append line [string index $data $i]
+ incr i
+ append line [string index $data $i]
+ }
+ lappend hex [string toupper "${addr_hex}${line}"]
+ }
+ set hex_data {} ;# delete input data
+ }
+
+ ## Convert processor code into source code
+ # @return void
+ proc decompile_code {} {
+
+ variable hex ;# Adjusted input data, list: {{addr hex0 hex1 hex2 ...} ...}
+ variable asm ;# Resulting source code
+ variable label ;# Array of tempotary labels, label(int) -> addr
+ variable label_idx ;# Number of usages of code memory addressing
+
+ set pointer 0 ;# reset code memory pointer
+ set label_idx -1 ;# set label counter
+ set asm {} ;# reset asm
+ set idx 0
+
+ set trailing_data [list] ;# data remained after parsing last line
+ set trailing_data_length 0 ;# length od trailing_data
+
+ foreach line $hex {
+
+ if {[expr {$idx % 10}] == 0} ${Compiler::Settings::UPDATE_COMMAND}
+
+ incr idx
+
+ set addr [lindex $line 0] ;# address field (hex)
+ set line [lreplace $line 0 0] ;# data fields (hex)
+ set addr_dec [expr "0x$addr"] ;# decimal value of address
+
+ ## If requested address overlaping expected address then
+ # adjust pointer and write trailing data by DB directive
+ if {$addr_dec > ($pointer + 1 + $trailing_data_length) || ($pointer == 0)} {
+ if {$trailing_data_length} {
+ # Write trailing data
+ foreach opcode $trailing_data {
+ append asm "_$pointer {DB 0${opcode}h {}} "
+ incr pointer
+ }
+ # Reset trailing data
+ set trailing_data_length 0
+ set trailing_data [list]
+ }
+
+ # Adjust pointer
+ set pointer $addr_dec
+ append asm "{} {} {} {ORG [HEX $addr]h {}} "
+ }
+
+ # Number of data fields
+ set len [llength $line]
+
+ # Append trailing data from last parsing to the current line
+ if {$trailing_data_length} {
+ # append
+ incr len $trailing_data_length
+ set line [concat $trailing_data $line]
+ # reset
+ set trailing_data_length 0
+ set trailing_data [list]
+ }
+
+ # Translate opcodes to source code
+ set instruction_skipped 0
+ set remaining_bytes $len
+ incr len -1
+ for {set idx 0} {$idx <= $len} {incr idx} {
+
+ set opcode [lindex $line $idx] ;# current opcode
+ # Search for he given opcode
+ if {[lsearch ${CompilerConsts::defined_OPCODE} $opcode] == -1} {
+ # opcode not found -> write opcode directly to source code
+ append asm "_$pointer {DB 0${opcode}h {}} "
+ set length 1
+ } else {
+ # opcode found -> resolve it's definition
+ set def $CompilerConsts::Opcode($opcode)
+
+ set instruction [lindex $def 0] ;# Instruction name
+ set opr_types [lindex $def 1] ;# Oprand types
+ set length [lindex $def 2] ;# Instruction length
+ set mask_opr [lindex $def 3] ;# Opreand mask
+ set operands {} ;# reset operand values
+
+ ## If remaining code on this line has insufficient length to
+ # make valid instruction then continue to next line and
+ # append remainder of current line to the next line
+ if {$length > $remaining_bytes} {
+ set trailing_data_length $remaining_bytes
+ set trailing_data [lrange $line $idx end]
+
+ break
+ }
+
+ # Resolve operands
+ set opr {}
+ foreach type $opr_types {
+
+ if {[lsearch ${CompilerConsts::FixedOperands} [string tolower $type]] != -1} {
+ # Fixed operand -> only copy
+ set opr $type
+ } {
+ # Get operand value
+ incr idx
+
+ if {$idx > $len} {
+ append asm "_$pointer {DB 0${opcode}h {}} "
+ set instruction_skipped 1
+ set length 1
+ incr idx -1
+ break
+ }
+ switch -- $type {
+ {imm8} { ;# Immediate addressing 8 bit
+ set opr "#[HEX [lindex $line $idx]]h"
+ }
+ {imm16} { ;# Immmediate addressing 16 bit
+ set opr "#[HEX [lindex $line $idx]]"
+ incr idx
+
+ if {$idx > $len} {
+ append asm "_$pointer {DB 0${opcode}h {}} "
+ set instruction_skipped 1
+ set length 1
+ incr idx -2
+ break
+ }
+ append opr "[lindex $line $idx]h"
+ }
+ {bit} { ;# Direct addressing bit
+ set opr "[HEX [lindex $line $idx]]h"
+ set tmp_opr [string range $opr 0 {end-1}]
+ set tmp_opr [expr "0x$tmp_opr"]
+ foreach item ${CompilerConsts::MapOfSFRBitArea} {
+ if {[expr "0x[lindex $item 1]"] == $tmp_opr} {
+ set opr [lindex $item 0]
+ break
+ }
+ }
+ }
+ {/bit} { ;# Direct inverted addressing bit
+ set opr "/[HEX [lindex $line $idx]]h"
+ set tmp_opr [string range $opr 1 {end-1}]
+ set tmp_opr [expr "0x$tmp_opr"]
+ foreach item ${CompilerConsts::MapOfSFRBitArea} {
+ if {[expr "0x[lindex $item 1]"] == $tmp_opr} {
+ set opr [lindex $item 0]
+ break
+ }
+ }
+ }
+ {data} { ;# Direct addressing
+ set opr "[HEX [lindex $line $idx]]h"
+ set tmp_opr [string range $opr 0 {end-1}]
+ set tmp_opr [expr "0x$tmp_opr"]
+ foreach item ${CompilerConsts::MapOfSFRArea} {
+ if {[expr "0x[lindex $item 1]"] == $tmp_opr} {
+ set opr [lindex $item 0]
+ break
+ }
+ }
+ }
+ {code8} { ;# Immediate addressing code memory, 8 bit
+ incr label_idx
+ set opr "lbl${label_idx}-"
+
+ set label($label_idx) [expr "0x[lindex $line $idx]"]
+
+ if {$label($label_idx) > 127} {
+ incr label($label_idx) -256
+ }
+
+ incr label($label_idx) $pointer
+ incr label($label_idx) $length
+
+ if {$label($label_idx) > 0x0FFFF || $label($label_idx) < 0} {
+ set label($label_idx) [expr {$label($label_idx) & 0x0FFFF}]
+ Warning "Code address overflow, instruction: $instruction"
+ } elseif {$label($label_idx) == $pointer} {
+ unset label($label_idx)
+ incr label_idx -1
+ set opr {$}
+ }
+ }
+ {code11} { ;# Immediate addressing code memory, 11 bit
+ incr label_idx
+ set opr "lbl${label_idx}-"
+ set label($label_idx) "$mask_opr[lindex $line $idx]"
+ set label($label_idx) [expr "0x$label($label_idx)"]
+
+ if {$label($label_idx) == $pointer} {
+ unset label($label_idx)
+ incr label_idx -1
+ set opr {$}
+ }
+ }
+ {code16} { ;# Immediate addressing code memory, 16 bit
+ incr label_idx
+ set opr "lbl${label_idx}-"
+ set label($label_idx) [lindex $line $idx]
+ incr idx
+
+ if {$idx > $len} {
+ append asm "_$pointer {DB 0${opcode}h {}} "
+ set length 1
+ incr idx -2
+ set instruction_skipped 1
+ break
+ }
+ append label($label_idx) [lindex $line $idx]
+ set label($label_idx) [expr "0x$label($label_idx)"]
+
+ if {$label($label_idx) == $pointer} {
+ unset label($label_idx)
+ incr label_idx -1
+ set opr {$}
+ }
+ }
+ }
+ }
+ # Resulting operand value to operand list
+ lappend operands $opr
+ }
+
+ if {$instruction_skipped} {
+ set instruction_skipped 0
+ incr pointer $length
+ incr remaining_bytes -$length
+ continue
+ }
+
+ # Append line to source code list
+ append asm "_$pointer {$instruction {$operands} {}} "
+ }
+ # Increment program address pointer
+ incr pointer $length
+ incr remaining_bytes -$length
+ }
+ }
+ }
+
+ ## Create labels in resulting code
+ # Replace tempotary labels references by theirs final forms
+ # and add appropriate labels to lines (label: mov A, #56q)
+ proc parse_labels {} {
+
+ variable asm ;# Resulting source code
+ variable label ;# Array of tempotary labels, label(int) -> addr
+ variable label_idx ;# Label index
+ variable final_lbls ;# Number of final labels
+
+ set addrs {} ;# List of set addresses
+ set equ_block {} ;# Reset block of declarations of unresoved labels
+
+ # Replace each tempotary label with final label
+ set lbl_idx -1
+ for {set i 0} {$i <= $label_idx} {incr i} {
+ set idx [lsearch $addrs $label($i)]
+ if {$idx != -1} {
+ # Reuse an existing label
+ regsub -all "lbl${i}-" $asm "label$idx" asm
+ } {
+ # Realy a new label
+ lappend addrs $label($i)
+ incr lbl_idx
+ regsub -all "lbl${i}-" $asm "label$lbl_idx" asm
+ }
+ }
+ set final_lbls $lbl_idx
+
+ # Write final labels to the source code
+ set i 0
+ foreach addr $addrs {
+ set idx [lsearch $asm "_$addr"]
+ if {$idx == -1} {
+ # Not found
+ append equ_block "{} {CODE [HEX [format %X $addr]]h label$i} "
+ } {
+ # Found
+ incr idx
+ lset asm [list $idx 2] "label$i"
+ }
+ incr i
+ }
+
+ # Append block of declarations of unresolved labels to resulting source code
+ append equ_block $asm
+ set asm $equ_block
+ }
+
+ ## Final stage
+ # list -> plain text
+ proc final_stage {} {
+ variable asm ;# Resulting code
+ variable tmp_asm ;# Tempotary variable only this procedure
+ variable final_lbls ;# Number of final labels
+
+ set tmp_asm {} ;# reset tempotary code
+ set len [llength $asm] ;# length of source code list
+ incr len -1
+
+ # Rewrite the source code
+ for {set i 1} {$i <= $len} {incr i 2} {
+
+ if {[expr {$len % 5}] == 0} ${Compiler::Settings::UPDATE_COMMAND}
+
+ set line [lindex $asm $i] ;# Get line
+
+ # Empty line
+ if {$line == {}} {
+ append tmp_asm "\n"
+ continue
+
+ # Not an empty line
+ } {
+ set label [lindex $line 2] ;# label
+ set instr [lindex $line 0] ;# instruction
+ set oprs [lindex $line 1] ;# oprands
+
+ if {$label != {} && $instr != {CODE}} {
+ append label {:}
+ if {[string length $label] > 7} {
+ append tmp_asm "$label\n"
+ set label {}
+ }
+ }
+ if {$instr == {CODE}} {
+ if {$final_lbls > 999 && [string length $label] < 8} {
+ append label "\t"
+ }
+ }
+ }
+
+ # Write line
+ append label "\t" $instr "\t" [join $oprs {, }]
+ append tmp_asm [string trimright $label] "\n"
+ }
+
+ # Append 'END' directive at the end
+ append tmp_asm "\n\tEND"
+ set asm $tmp_asm
+ }
+
+ ## Free memory used during processing
+ proc free_resources {} {
+ variable tmp_asm ;# Tempotary variable for procedure: 'final_stage'
+ variable hex_data ;# Raw input data
+ variable hex ;# Adjusted input data, list: {addr hex0 hex1 hex2 ...}
+ variable lineNum ;# Number of line currently beeing parsed
+ variable error_count ;# Number of errors raised during decompilation
+ variable label_idx ;# Label index
+ variable label ;# Array of tempotary labels, label(int) -> addr
+ variable asm ;# Resulting source code
+
+ set tmp_asm {}
+ set hex_data {}
+ set hex {}
+ set lineNum {}
+ set error_count {}
+ set label_idx {}
+ catch {array unset label}
+ }
+
+ ## Adjust hexadecimal number
+ # note: resulting number starts with digit
+ # @parm String number - input
+ # @return String - result
+ proc HEX {number} {
+
+ set number [string trimleft $number 0]
+ if {$number == {}} {return 0}
+
+ if {[regexp {^[a-fA-F]} $number]} {
+ return "0$number"
+ }
+
+ return $number
+ }
+
+ ## Report warning message
+ # @parm Int LineNumber - Number of line where it occured
+ # @parm String ErrorInfo - Text of the warning
+ # @return void
+ proc Warning {ErrorInfo} {
+ variable idx ;# Current position in asm list
+ variable warning_count ;# Number of warnings occured
+
+ # Increment warning counter
+ incr warning_count
+
+ # Report the warning
+ if {${::Compiler::Settings::WARNING_LEVEL} < 2} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {WN}][mc "Warning: %s" $ErrorInfo]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "\033\[33mWarning\033\[m: %s" $ErrorInfo]
+ }
+ }
+ }
+
+ ## Error
+ # @parm Int lineNumber - number of line, where the error occured
+ # @parm String info - error string
+ proc Error {lineNumber info} {
+ variable error_count
+ incr error_count
+ if {$lineNumber != {}} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ set lineNumber [mc " at line %s" $lineNumber]
+ } {
+ set lineNumber [mc " at line \033\[31;1;4m%s\033\[m" $lineNumber]
+ }
+ }
+ if {${::Compiler::Settings::WARNING_LEVEL} < 3} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [::Compiler::msgc {EL}][mc "Error%s: %s" $lineNumber $info]
+ } {
+ ${Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "\033\[31;1mError%s\033\[m: %s" $lineNumber $info]
+ }
+ }
+ }
+}
diff --git a/lib/compiler/external_compiler.tcl b/lib/compiler/external_compiler.tcl
new file mode 100755
index 0000000..3cf581b
--- /dev/null
+++ b/lib/compiler/external_compiler.tcl
@@ -0,0 +1,1076 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements interface to external compilers
+# --------------------------------------------------------------------------
+
+namespace eval ExternalCompiler {
+ variable input_filename ;# String: Name of file to compile (without extension)
+ variable compiler_used ;# Int: Compiler ID (1 == ASEM-51; 2 == ASL; 3 == AS31, other values have no meaning)
+ variable project_dir ;# String: Project directory
+ variable working_dir ;# String: Compiler working directory
+ variable input_file_base;# String: Full file name of the primary source file
+
+ ## Int: Preffered assembler
+ # 0 - Native MCU 8051 IDE assembler
+ # 1 - ASEM-51
+ # 2 - ASL
+ # 3 - AS31
+ variable selected_assembler 0
+ variable selected_assembler_def 0 ;# Int: Default value for $selected_assembler
+
+ #
+ ## External assembler configuration
+ #
+
+ ## ASEM-51
+ # Default ASEM-51 assembler configuration
+ variable assembler_ASEM51_config_def {
+ --omf-51 0
+ --columns 0
+ --verbose 1
+ -i {}
+ custom {}
+ }
+ # Current ASEM-51 assembler configuration
+ variable assembler_ASEM51_config
+ # Default ASEM-51 additional configuration
+ variable assembler_ASEM51_addcfg_def {
+ adf 1
+ }
+ # Current ASEM-51 additional configuration
+ variable assembler_ASEM51_addcfg
+
+ ## ASL
+ # Array: ASL additional configuration
+ variable assembler_ASL_addcfg
+ # Default ASL assembler configuration
+ variable assembler_ASL_config_def {
+ -A 0 -a 0
+ -C 0 -c 0
+ -h 0 -I 1
+ -L 1 -M 0
+ -P 0 -n 0
+ -quiet 0 -s 1
+ -u 0 -U 0
+ -w 0 -x 0
+
+ -r {} -i {}
+ -g {MAP} -cpu {8051}
+ custom {}
+ }
+ # Current ASL assembler configuration
+ variable assembler_ASL_config
+ # Default ASL additional configuration
+ variable assembler_ASL_addcfg_def {
+ ihex 1
+ adf 1
+ }
+ # Current ASL additional configuration
+ variable assembler_ASL_addcfg
+
+ ## AS31
+ # Array: AS31 additional configuration
+ variable assembler_AS31_addcfg
+ # Default AS31 assembler configuration
+ variable assembler_AS31_config_def {
+ -l 1 -F {hex}
+ -A {} custom {}
+ }
+ # Current AS31 assembler configuration
+ variable assembler_AS31_config
+ # Default AS31 additional configuration
+ variable assembler_AS31_addcfg_def {
+ adf 1
+ }
+ # Current ASL additional configuration
+ variable assembler_AS31_addcfg
+
+ ## SDCC
+ # Default SDCC boolean options
+ variable sdcc_bool_options_def {
+ --verbose 1
+ -V 1
+ -S 0
+ --compile-only 0
+ --preprocessonly 0
+ --c1mode 0
+ --print-search-dirs 0
+ --use-stdout 0
+ --nostdlib 0
+ --nostdinc 0
+ --less-pedantic 0
+ --debug 1
+ --cyclomatic 0
+ --fdollars-in-identifiers 0
+ --funsigned-char 0
+ --xstack 0
+ --int-long-reent 0
+ --float-reent 0
+ --main-return 0
+ --xram-movc 0
+ --profile 0
+ --fommit-frame-pointer 0
+ --all-callee-saves 0
+ --stack-probe 0
+ --parms-in-bank1 0
+ --no-xinit-opt 0
+ --no-c-code-in-asm 0
+ --no-peep-comments 0
+ --fverbose-asm 0
+ --short-is-8bits 0
+ --stack-auto 0
+ --nooverlay 1
+ --nogcse 0
+ --nolabelopt 0
+ --noinvariant 0
+ --noinduction 1
+ --nojtbound 0
+ --noloopreverse 0
+ --no-peep 0
+ --no-reg-params 0
+ --peep-asm 0
+ --opt-code-speed 0
+ --opt-code-size 0
+ --out-fmt-ihx 0
+ --out-fmt-s19 0
+ }
+ # Current SDCC boolean options
+ variable sdcc_bool_options
+ # Default SDCC string options
+ variable sdcc_string_options_def {
+ model --model-small
+ standard --std-sdcc89
+ stack --pack-iram
+ custom {}
+ }
+ # Current SDCC string options
+ variable sdcc_string_options
+ # Default SDCC optional string options
+ variable sdcc_optional_string_options_def {
+ --codeseg {}
+ --constseg {}
+ --lib-path {}
+ --xram-loc {}
+ --xstack-loc {}
+ --code-loc {}
+ --stack-loc {}
+ --data-loc {}
+ --stack-size {}
+ }
+ # Current SDCC optional string options
+ variable sdcc_optional_string_options
+ # Default semicolon separated optional string options
+ variable sdcc_scs_string_options_def {
+ -I {}
+ -l {}
+ -L {}
+ --disable-warning {}
+ }
+ # Current semicolon separated optional string options
+ variable sdcc_scs_string_options
+
+
+ ## Make backup copies for files with the given extensions and remove original files
+ # (input_filename.extension -> input_filename.extension~)*
+ # @parm List suffixes - List of file extensions (e.g. {asm c h})
+ # @return void
+ proc backup_and_remove {suffixes} {
+ variable input_filename ;# String: Name of file to compile (without extension)
+
+ foreach ext $suffixes {
+ catch {
+ file rename -force -- "$input_filename.$ext" "$input_filename.$ext~"
+ }
+ }
+ }
+
+ ## Start SDCC (ANSI C compiler)
+ # @parm String work_dir - Current working directory
+ # @parm String input_file - C source file to compile
+ # @parm Int iram - Amount of internal data memory
+ # @parm Int xram - Amount of external data memory
+ # @parm Int code - Amount of overall program memory
+ # @return Int - Compiler PID
+ proc compile_C {work_dir input_file iram xram code} {
+ variable input_filename ;# String: Name of file to compile (without extension)
+ variable compiler_used ;# Int: Compiler ID (1 == ASEM-51; 2 == ASL; 3 == AS31, other values have no meaning)
+
+ set compiler_used 0
+ set input_filename [file rootname $input_file]
+ backup_and_remove {asm cdb ihx}
+ set sdcc_opts [determinate_sdcc_options]
+ if {${::PROGRAM_AVALIABLE(sdcc-sdcc)}} {
+ set sdcc_cmd {sdcc-sdcc}
+ } {
+ set sdcc_cmd {sdcc}
+ }
+ ::X::messages_text_append [::Compiler::msgc {S}][mc "\n\nStarting compiler ..."]
+ if {!$::MICROSOFT_WINDOWS} {
+ ::X::messages_text_append "\ncd \"$work_dir\"\n$sdcc_cmd -mmcs51 --iram-size $iram --xram-size $xram --code-size $code $sdcc_opts \"$input_file\""
+ } {
+ ::X::messages_text_append "\ncd \"$work_dir\"\n$sdcc_cmd -mmcs51 --iram-size $iram --xram-size $xram --code-size $code --nooverlay --noinduction --verbose --debug -V --std-sdcc89 --model-small --pack-iram \"$input_file\""
+ }
+ if {[catch {
+ cd $work_dir
+ }]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nError: Unable to change working directory to '%s'" $work_dir]
+ }
+ if {!$::MICROSOFT_WINDOWS} { ;# Normal way (POSIX)
+ return [exec -- /bin/sh -c "$sdcc_cmd -mmcs51 \
+ --iram-size $iram \
+ --xram-size $xram \
+ --code-size $code \
+ $sdcc_opts \"$input_file\"" |& \
+ tclsh "${::LIB_DIRNAME}/external_command.tcl" \
+ [tk appname] \
+ {::ExternalCompiler::ext_compilation_complete 1}\
+ ::X::compilation_message & \
+ ]
+ } { ;# Microsoft Windows way
+ eval [subst -nocommands {
+ return [exec -- "${::LIB_DIRNAME}/sdcc.bat" \
+ "${::LIB_DIRNAME}" \
+ $iram \
+ $xram \
+ $code \
+ "$input_file" \
+ |& \
+ "${::LIB_DIRNAME}/external_command.bat" \
+ "${::LIB_DIRNAME}/external_command.tcl" \
+ [tk appname] \
+ {::ExternalCompiler::ext_compilation_complete 1} \
+ ::X::compilation_message & \
+ ]
+ }]
+ }
+ }
+
+ ## Start AS31 (Assembler)
+ # @parm String work_dir - Current working directory
+ # @parm String input_file - Assembler source file to compile
+ # @parm String project_directory - Project directory (for debug file)
+ # @return Int - Compiler PID
+ proc as31_compile {work_dir input_file project_directory} {
+ variable project_dir ;# String: Project directory
+ variable compiler_used ;# Int: Compiler ID (1 == ASEM-51; 2 == ASL; 3 == AS31, other values have no meaning)
+ variable input_filename ;# String: Name of file to compile (without extension)
+ variable working_dir ;# String: Compiler working directory
+ variable input_file_base;# String: Full file name of the primary source file
+ global argv
+
+ set compiler_used 3
+ set project_dir $project_directory
+ set input_file_base [file normalize [file join $work_dir $input_file]]
+ set input_filename [file rootname $input_file_base]
+ set working_dir $work_dir
+
+ set as31_options [determinate_as31_options]
+ ::X::messages_text_append [::Compiler::msgc {S}][mc "\n\nStarting compiler ..."]
+ ::X::messages_text_append "\ncd \"$work_dir\"\nas31 $as31_options \"$input_file\""
+ if {[catch {
+ cd $work_dir
+ }]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nError: Unable to change working directory to '%s'" $work_dir]
+ }
+ backup_and_remove {adf hex lst}
+
+ return [exec -- /bin/sh -c "as31 $as31_options \"$input_file\"" |& \
+ tclsh "${::LIB_DIRNAME}/external_command.tcl" "[tk appname]" \
+ ::ExternalCompiler::ext_compilation_complete ::X::compilation_message & \
+ ]
+ }
+
+ ## Start ASEM-51 (Assembler)
+ # @parm String work_dir - Current working directory
+ # @parm String input_file - Assembler source file to compile
+ # @parm String project_directory - Project directory (for debug file)
+ # @return Int - Compiler PID
+ proc asem51_compile {work_dir input_file project_directory} {
+ variable project_dir ;# String: Project directory
+ variable compiler_used ;# Int: Compiler ID (1 == ASEM-51; 2 == ASL; 3 == AS31, other values have no meaning)
+ variable input_filename ;# String: Name of file to compile (without extension)
+ variable working_dir ;# String: Compiler working directory
+ variable input_file_base;# String: Full file name of the primary source file
+ global argv
+
+ set compiler_used 1
+ set project_dir $project_directory
+ set input_file_base [file normalize [file join $work_dir $input_file]]
+ set input_filename [file rootname $input_file_base]
+ set working_dir $work_dir
+
+ set asem51_options [determinate_asem51_options]
+ ::X::messages_text_append [::Compiler::msgc {S}][mc "\n\nStarting compiler ..."]
+ ::X::messages_text_append "\ncd \"$work_dir\"\nasem $asem51_options \"$input_file\""
+ if {[catch {
+ cd $work_dir
+ }]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nError: Unable to change working directory to '%s'" $work_dir]
+ }
+ backup_and_remove {adf hex lst omf}
+
+ return [exec -- /bin/sh -c "asem $asem51_options \"$input_file\"" |& \
+ tclsh "${::LIB_DIRNAME}/external_command.tcl" "[tk appname]" \
+ ::ExternalCompiler::ext_compilation_complete ::X::compilation_message & \
+ ]
+ }
+
+ ## Start ASL (Assembler)
+ # @parm String work_dir - Current working directory
+ # @parm String input_file - Assembler source file to compile
+ # @parm String project_directory - Project directory (for debug file)
+ # @return Int - Compiler PID
+ proc asl_compile {work_dir input_file project_directory} {
+ variable project_dir ;# String: Project directory
+ variable compiler_used ;# Int: Compiler ID (1 == ASEM-51; 2 == ASL; 3 == AS31, other values have no meaning)
+ variable input_filename ;# String: Name of file to compile (without extension)
+ variable assembler_ASL_addcfg ;# Current ASL additional configuration
+ global argv
+
+ set compiler_used 2
+ set project_dir $project_directory
+ set input_filename [file join $work_dir [file rootname $input_file]]
+ backup_and_remove {hex lst map adf}
+ set asl_opts [determinate_asl_options]
+ set additional_commands {}
+ if {$assembler_ASL_addcfg(ihex)} {
+ append additional_commands {&& p2hex "} $input_filename.p {" "} $input_filename.hex {"}
+ }
+
+ ::X::messages_text_append [::Compiler::msgc {S}][mc "\n\nStarting compiler ..."]
+ ::X::messages_text_append "\ncd \"$work_dir\"\nasl $asl_opts \"$input_file\""
+ if {[catch {
+ cd $work_dir
+ }]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nError: Unable to change working directory to '%s'" $work_dir]
+ }
+ return [exec -- /bin/sh -c "asl $asl_opts \"$input_file\" $additional_commands" |& \
+ tclsh "${::LIB_DIRNAME}/external_command.tcl" "[tk appname]" \
+ ::ExternalCompiler::ext_compilation_complete ::X::compilation_message & \
+ ]
+ }
+
+ ## Create file containg MD5 hashes of source files
+ # Suitable for C language only!
+ # This file will be later used to chech wheter any of these files was changed or not.
+ # @return void
+ proc create_hashes_file {} {
+ variable input_filename ;# String: Name of file to compile (without extension)
+
+ # List of files included files in the main file
+ set included_files [list]
+
+ # Open C DeBug file generated by SDCC compiler
+ if {[catch {
+ set cdb_file [open $input_filename.cdb r]
+ }]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nUnable to find \"%s\"" [file rootname $input_filename].cdb]
+ return
+ }
+
+ # Open the hashes file for writing (possibly create the file)
+ if {[catch {
+ set hs_file [open $input_filename.hashes w 420]
+ }]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nUnable to create \"%s\"" [file rootname $input_filename].hashes]
+ catch {close $cbd_file}
+ return
+ }
+
+ # Iterate over lines in the C DeBug file and list all included source files
+ while {![eof $cdb_file]} {
+ set line [gets $cdb_file]
+
+ if {[string first {L:C$} $line]} {
+ continue
+ }
+
+ set line [string replace $line 0 3]
+ set line [string replace $line [string first {$} $line] end]
+
+ if {[lsearch -ascii -exact $included_files $line] == -1} {
+ lappend included_files $line
+ }
+ }
+
+ # Compute MD5 hash for each of the included files
+ foreach filename $included_files {
+ catch {
+ puts $hs_file "[::md5::md5 -hex -file $filename] \"$filename\" "
+ }
+ }
+
+ # Clean up
+ catch {close $cdb_file}
+ catch {close $hs_file}
+ }
+
+ ## This function must be called after exteral compiler finished its work
+ # @parm Int action = 0 - Action to perform after successfull compilation
+ # 0 - No action
+ # 1 - Copy <file>.ihx to <file>.hex
+ # @return void
+ proc ext_compilation_complete args {
+ variable input_filename ;# String: Name of file to compile (without extension)
+ variable compiler_used ;# Int: Compiler ID (1 == ASEM-51; 2 == ASL; 3 == AS31, other values have no meaning)
+ variable assembler_ASEM51_addcfg;# Current ASEM-51 assembler configuration
+ variable assembler_ASL_addcfg ;# Current ASL additional configuration
+ variable assembler_AS31_addcfg ;# Current AS31 additional configuration
+
+ # Compilation successfull
+ if {$::X::compilation_successfull} {
+
+ # Create MCU 8051 IDE assembler debug file -
+ switch -- $compiler_used {
+ 1 { ;# - from ASEM-51 code listing (*.lst)
+ if {$assembler_ASEM51_addcfg(adf) && ![asem_51_analyze]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nUnable to find \"%s\"\n\tMCU 8051 IDE debug file (*.adf) could not be generated\n\tPLEASE CHECK YOUR %s CONFIGURATION" [file rootname $input_filename].lst {ASEM-51}]
+ }
+ }
+ 2 { ;# - from ASL native debug file (*.map)
+ if {$assembler_ASL_addcfg(adf) && ![asl_analyze]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nUnable to find \"%s\"\n\tMCU 8051 IDE debug file (*.adf) could not be generated\n\tPLEASE CHECK YOUR %s CONFIGURATION" [file rootname $input_filename].map {ASL}]
+ }
+ }
+ 3 { ;# - from AS31 code listing file (*.lst)
+ if {$assembler_ASL_addcfg(adf) && ![as31_analyze]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nUnable to find \"%s\"\n\tMCU 8051 IDE debug file (*.adf) could not be generated\n\tPLEASE CHECK YOUR %s CONFIGURATION" [file rootname $input_filename].lst {AS31}]
+ }
+ }
+ 0 { ;# SDCC used: Create .hashes file from .cdb file
+ create_hashes_file
+ }
+ }
+ ::X::messages_text_append [::Compiler::msgc {S}][mc "\nCompilation successful"]
+
+ # Perform specified after successfull compilation
+ switch -- [lindex $args 0] {
+ 0 { ;# No action
+ }
+ 1 { ;# Copy <file>.ihx to <file>.hex
+ catch {
+ file rename -force -- "$input_filename.hex" "$input_filename.hex~"
+ }
+ catch {
+ file copy -force -- "$input_filename.ihx" "$input_filename.hex"
+ }
+ }
+ }
+
+ # Compilation failed
+ } {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nCompilation FAILED"]
+ }
+ ::X::ext_compilation_complete
+ }
+
+ ## Create MCU 8051 IDE assembler debug file from AS31 code listing
+ # @return Bool - 1 == success; 0 == failure
+ proc as31_analyze {} {
+ variable project_dir ;# String: Project directory
+ variable working_dir ;# String: Compiler working directory
+ variable input_filename ;# String: Name of file to compile (without extension)
+ variable input_file_base;# String: Full file name of the primary source file
+
+ # Local variables
+ set line_number 0 ;# Line number in LST file
+ set adf_line 0 ;# Line number to record in ADF file
+ set adf_code {} ;# Processor code in decimal representation (for ADF file)
+ set address {} ;# Address in code memory
+ set processor_code {} ;# Processor code read from LST file
+
+ # Try to open code listing file and some tempotary debug file
+ if {[catch {
+ set lst_file [open $input_filename.lst r]
+ set adf_file [open $input_filename.adf w 420]
+ } result]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "File access error:\n%s" $result]
+ return 0
+ }
+
+ # Write file header
+ puts $adf_file "# Assembler Debug File created by ${::APPNAME}"
+ puts $adf_file "# Used assembler: AS31"
+ puts $adf_file "# Date: [clock format [clock seconds] -format {%D}]"
+
+ # Write MD5 of the source file
+ puts -nonewline $adf_file [::md5::md5 -hex -file $input_file_base]
+ puts -nonewline $adf_file { }
+ puts -nonewline $adf_file [string replace $input_file_base 0 [string length $project_dir]]
+
+ # One pass compilation LST -> ADF
+ while {![eof $lst_file]} {
+ incr line_number
+
+ # Read one line from the code listing
+ set line [string range [gets $lst_file] 0 17]
+
+ # Lines which does not contain address or code will be ignored
+ #+ but line number counter must be still incremented on these lines
+ if {[regexp {^\s*$} $line]} {
+ continue
+ }
+
+ set address [string trim [string range $line 0 3]]
+ set code [string trim [string range $line 6 17]]
+
+ # If there is no processor code then skip the line
+ if {$code == {}} {
+ continue
+ }
+
+ # Convert processor code to format suitable for this application,
+ #+ that means convert list of HH to list of DDD
+ if {[catch {
+ set adf_code {}
+ foreach h $code {
+ scan $h %x h
+ lappend adf_code $h
+ }
+ }]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "Unable to understand formulation at line %s in file %s" $line_number $input_filename.lst]
+ close $lst_file
+ close $adf_file
+ return 0
+ }
+
+ # If there is no address then append the current code to the last ADF record
+ if {$address == {}} {
+ puts -nonewline $adf_file { }
+ puts -nonewline $adf_file $adf_code
+ } {
+ if {[catch {
+ scan $address %x address
+ }]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "Unable to understand formulation at line %s in file %s" $line_number $input_filename.lst]
+ close $lst_file
+ close $adf_file
+ return 0
+ }
+ set adf_line $line_number
+
+ puts -nonewline $adf_file "\n0 $adf_line $address $adf_code"
+ }
+ }
+
+ # Close all files and finalize ...
+ puts $adf_file {}
+ close $lst_file
+ close $adf_file
+ return 1
+ }
+
+ ## Create MCU 8051 IDE assembler debug file from ASEM-51 code listing
+ # @return Bool - 1 == success; 0 == failure
+ proc asem_51_analyze {} {
+ variable project_dir ;# String: Project directory
+ variable working_dir ;# String: Compiler working directory
+ variable input_filename ;# String: Name of file to compile (without extension)
+ variable input_file_base;# String: Full file name of the primary source file
+
+ # Local variables
+ array set line_number {} ;# Array of Int: Line number within certain inslusion level
+ set inclusion_level 0 ;# Int: Current inclusion level
+ set file_number 0 ;# Int: Current file number (number of included file in $included_files)
+ set file_number_changed 0 ;# Bool: Next line includes new file
+ set address 0 ;# Int(H|D): Address in machine code
+ set code {} ;# List of Int(H|D): Machine code
+ set included_files [list $input_file_base] ;# List of all included files (unique, unsorted)
+
+ # Try to open code listing file and some tempotary debug file
+ if {[catch {
+ set lst_file [open $input_filename.lst r]
+ set adf_file [open $input_filename._adf w 420]
+ } result]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "File access error:\n%s" $result]
+ return 0
+ }
+
+ # Initialize line number counter
+ for {set i 0} {$i < 100} {incr i} {
+ set line_number($i) 0
+ }
+
+ # One pass compilation LST -> ADF
+ while {![eof $lst_file]} {
+ # Read 1 line
+ set line [gets $lst_file]
+
+ # Normal line coresponding to certain line in source code
+ if {[regexp {^ *\d+:(..)?} $line inclusion_level]} {
+ # Extract numbers after "line_num: inc_lvl "
+ set line [string range $line [string length $inclusion_level] end]
+ regexp {^[0-9a-fA-F\s]+} $line code
+
+ # Determinate address and machine code
+ set address [lindex $code 0]
+ set code [lrange $code 1 end]
+
+ # Determinate inclusion level
+ set inclusion_level [string trim [string range $inclusion_level end-1 end]]
+ if {$inclusion_level == {} || [string index $inclusion_level end] == {:}} {
+ set inclusion_level 0
+ set file_number 0
+ }
+ incr line_number($inclusion_level)
+
+ # Continuation of previous unfinished line
+ } elseif {![string first { } $line]} {
+ set address [lindex $line 0]
+ set code [lrange $line 1 end]
+
+ # Other lines
+ } else {
+ continue
+ }
+
+ # Detect directive "$INCLUDE(file)"
+ if {[regexp -nocase -- {.*\$include\s*\([^\(\)]+\)} $line line]} {
+ regsub {;.+$} $line {} line
+ set line [string trim $line]
+ regexp -nocase -- {\$include\s*\([^\(\)]+\)} $line line
+ if {$line == {}} {
+ continue
+ }
+ set line [string replace $line 0 7]
+ set line [string trim $line {( )}]
+ set line [file normalize [file join $working_dir $line]]
+ set file_number_changed 1
+ set file_number [lsearch -ascii -exact $included_files $line]
+ if {$file_number == -1} {
+ set file_number [llength $included_files]
+ lappend included_files $line
+ }
+ continue
+ }
+
+ # Next file included -> Reset lines counter
+ if {$file_number_changed} {
+ set line_number($inclusion_level) 1
+ set file_number_changed 0
+ }
+
+ # Convert machine code from hexadecimal to decimal value
+ set code_dec {}
+ foreach byte $code {
+ if {[string length $byte] != 2 || ![string is xdigit -strict $byte]} {
+ break
+ }
+ scan $byte %x byte
+ lappend code_dec $byte
+ }
+
+ # Machine code must not be empty
+ if {$code_dec == {}} {continue}
+
+ # Check for valid address
+ if {[string length $address] != 4 || ![string is xdigit -strict $address]} {
+ continue
+ }
+
+ # Write line to tempotary debug file
+ scan $address %x address
+ puts -nonewline $adf_file [list $file_number $line_number($inclusion_level) $address]
+ puts -nonewline $adf_file { }
+ puts $adf_file $code_dec
+ }
+ close $adf_file
+
+ # Open final debug file
+ if {[catch {
+ set adf_file [open $input_filename.adf w 420]
+ } result]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "File access error:\n%s" $result]
+ return 0
+ }
+ # Write file header
+ puts $adf_file "# Assembler Debug File created by ${::APPNAME}"
+ puts $adf_file "# Used assembler: ASEM-51"
+ puts $adf_file "# Date: [clock format [clock seconds] -format {%D}]"
+ # Create list of included files with MD5 hashes
+ set hashes_and_files {}
+ set project_dir_len [string length $project_dir]
+ foreach filename $included_files {
+ if {[catch {
+ lappend hashes_and_files [::md5::md5 -hex -file $filename]
+ } result]} {
+ lappend hashes_and_files 0
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "File access error:\n%s" $result]
+ }
+ if {![string first $project_dir $filename]} {
+ set filename [string replace $filename 0 $project_dir_len]
+ }
+ lappend hashes_and_files $filename
+ }
+ # Write list of included files
+ puts $adf_file $hashes_and_files
+ # Copy content of tempotary debug file to final debug file
+ if {[catch {
+ set adf__file [open $input_filename._adf r]
+ } result]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "File access error:\n%s" $result]
+ return 0
+ }
+ while {![eof $adf__file]} {
+ puts $adf_file [gets $adf__file]
+ }
+
+ # Close all files and delete tempotary file
+ close $adf__file
+ close $lst_file
+ close $adf_file
+ file delete -force $input_filename._adf
+ return 1
+ }
+
+ ## Create MCU 8051 IDE assembler debug file from ASL code listing
+ # @return Bool - 1 == success; 0 == fail
+ proc asl_analyze {} {
+ variable project_dir ;# String: Project directory
+ variable input_filename ;# String: Name of file to compile (without extension)
+
+ # Try to open all required files
+ if {[catch {
+ set map_file [open $input_filename.map r] ;# ASL debug file
+ set hex_file [open $input_filename.hex r] ;# Machine code
+ set adf_file [open $input_filename.adf w 420] ;# MCU 8051 IDE debug file
+ } result]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "File access error:\n%s" $result]
+ return 0
+ }
+
+ # Load machine code
+ ::IHexTools::free_resources
+ if {![::IHexTools::load_hex_data [read $hex_file]]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "Compilation error:\nFile \"%s\" is not a valid Intel® HEX 8 file" $input_filename.hex]
+ return 0
+ }
+ close $hex_file
+
+ # Initialize local variables
+ set filenames {}
+ set hashes_and_files {}
+ set filename {}
+ set project_dir_len [string length $project_dir]
+ set read_values 0
+
+ ## 1st pass
+ # Determinate list of included files (and list of files and MD5 hashes)
+ while {![eof $map_file]} {
+ # Get significant line from the code
+ set line [gets $map_file]
+ if {$line == {Segment CODE}} {
+ set read_values 1
+ continue
+ }
+ if {$line == {}} {
+ break
+ }
+ if {!$read_values} {
+ continue
+ }
+
+ # Ignore lines which doesn't start with "File "
+ if {[string first {File } $line]} {
+ continue
+ }
+
+ # Determinate raw name of included file
+ set filename [string replace $line 0 4]
+
+ # Adjust list of included files
+ if {[lsearch $filenames $filename] != -1} {
+ lappend filenames $filename
+ continue
+ }
+
+ # Determinate final file name and its MD5 hash
+ lappend filenames $filename
+ set filename [file join $project_dir [file normalize $filename]]
+ if {[catch {
+ lappend hashes_and_files [::md5::md5 -hex -file $filename]
+ } result]} {
+ ::X::messages_text_append [::Compiler::msgc {E}][mc "\nFile access error:\n%s" $result]
+ lappend hashes_and_files {0}
+ }
+ if {![string first $project_dir $filename]} {
+ set filename [string replace $filename 0 $project_dir_len]
+ }
+
+ # Adjust list of files and MD5 hashes
+ lappend hashes_and_files $filename
+ continue
+ }
+
+ # Create ADF file header
+ seek $map_file 0
+ puts $adf_file "# Assembler Debug File created by ${::APPNAME}"
+ puts $adf_file "# Used assembler: ASL"
+ puts $adf_file "# Date: [clock format [clock seconds] -format {%D}]"
+ puts $adf_file $hashes_and_files
+ unset hashes_and_files
+
+ ## 2nd (final) pass
+ # Create ADF (Assembler Debug File)
+ set last_line -1 ;#
+ set last_address -1 ;#
+ set last_file_num 0 ;#
+ set line_number 0 ;#
+ set file_number 0 ;#
+ set read_values 0 ;#
+ while {![eof $map_file]} {
+ # Get significant line from the code
+ set line [gets $map_file]
+ if {$line == {Segment CODE}} {
+ set read_values 1
+ continue
+ }
+ if {$line == {}} {
+ break
+ }
+ if {!$read_values} {
+ continue
+ }
+
+ # Change file number
+ if {![string first {File } $line]} {
+ set file_number [lsearch $filenames [string replace $line 0 4]]
+ continue
+ }
+
+ # Create ADF record(s)
+ foreach item $line {
+ # Determinate line number and address
+ set item [split $item {:}]
+ set line_number [lindex $item 0]
+ scan [lindex $item 1] %x address
+
+ # Handle firts record (first of all)
+ if {$last_line == -1} {
+ set last_line $line_number
+ set last_address $address
+ set last_file_num $file_number
+ continue
+ }
+
+ # Write record
+ write_to_adf_from_hex $adf_file $last_address \
+ [expr {$address - 1}] $last_line $last_file_num
+ set last_line $line_number
+ set last_address $address
+ set last_file_num $file_number
+ }
+ }
+
+ # Write last record (last of all)
+ if {$last_line != -1} {
+ write_to_adf_from_hex $adf_file $last_address \
+ ${::IHexTools::highest_addr} \
+ $last_line $last_file_num
+ }
+
+ # Clean up
+ ::IHexTools::free_resources
+ close $map_file
+ close $adf_file
+ return 1
+ }
+
+ ## Write record to MCU 8051 IDE assembler debug file (*.adf)
+ # Auxiliary procedure for procedure asl_analyze
+ # @parm Chanel adf_file - Target file
+ # @parm Int start_address - Starting address in machine code
+ # @parm Int end_address - End address in machine code
+ # @parm Int linenum - Line number
+ # @parm Int filenum - File number (ID of included file)
+ # @return void
+ proc write_to_adf_from_hex {adf_file start_address end_address linenum filenum} {
+ # Get machine code from NS ::IHexTools
+ set code {}
+ for {set i $start_address} {$i <= $end_address} {incr i} {
+ set val [::IHexTools::get_value $i]
+ if {$val > -1} {
+ lappend code [expr "0x$val"]
+ } {
+ lappend code 0
+ }
+ }
+
+ # Write to file
+ if {$linenum == {}} {
+ set linenum 0
+ }
+ puts -nonewline $adf_file [list $filenum $linenum $start_address]
+ puts -nonewline $adf_file { }
+ puts $adf_file $code
+ }
+
+ ## Determinate CLI options for external compiler sdcc
+ # @return String - Options for sdcc
+ proc determinate_sdcc_options {} {
+ variable sdcc_bool_options ;# Default SDCC boolean options
+ variable sdcc_string_options ;# Default SDCC string options
+ variable sdcc_optional_string_options ;# Default SDCC optional string options
+ variable sdcc_scs_string_options ;# Default semicolon separated optional string options
+
+ set result {}
+
+ # Boolean options
+ foreach key [array names sdcc_bool_options] {
+ if {$sdcc_bool_options($key)} {
+ append result { } $key
+ }
+ }
+
+ # String options
+ foreach key [array names sdcc_string_options] {
+ append result { } [regsub -all {\n} $sdcc_string_options($key) {}]
+ }
+
+ # Optional string options
+ foreach key [array names sdcc_optional_string_options] {
+ set value $sdcc_optional_string_options($key)
+ if {$value != {}} {
+ if {[regexp {\s} $value]} {
+ append result { } $key { } "\"" $value "\""
+ } {
+ append result { } $key { } $value
+ }
+ }
+ }
+
+ # Semicolon separated optional string options
+ foreach key [array names sdcc_scs_string_options] {
+ set values $sdcc_scs_string_options($key)
+ foreach value [split $values {;}] {
+ if {$value != {}} {
+ if {[regexp {\s} $value]} {
+ append result { } $key { } "\"" $value "\""
+ } {
+ append result { } $key { } $value
+ }
+ }
+ }
+ }
+
+ return $result
+ }
+
+ ## Determinate CLI options for external assembler ASEM-51
+ # @return String - Options for ASEM-51
+ proc determinate_asem51_options {} {
+ variable assembler_ASEM51_config ;# Current ASEM-51 assembler configuration
+
+ set result $assembler_ASEM51_config(custom)
+ if {$assembler_ASEM51_config(-i) != {}} {
+ append result { -i } {"} $assembler_ASEM51_config(i) {"}
+ }
+ foreach opt {--omf-51 --columns --verbose} {
+ if {$assembler_ASEM51_config($opt)} {
+ append result { } $opt
+ }
+ }
+
+ return $result
+ }
+
+ ## Determinate CLI options for external assembler AS31
+ # @return String - Options for AS31
+ proc determinate_as31_options {} {
+ variable assembler_AS31_config ;# Current AS31 assembler configuration
+
+ set result {}
+ if {$assembler_AS31_config(custom) != {}} {
+ append result { } ${assembler_AS31_config(custom)}
+ }
+ foreach opt {-l} {
+ if {$assembler_AS31_config($opt)} {
+ append result { } $opt
+ }
+ }
+ foreach opt {-F -A} {
+ if {$assembler_AS31_config($opt) != {}} {
+ append result { } $opt $assembler_AS31_config($opt)
+ }
+ }
+
+ return $result
+ }
+
+ ## Determinate CLI options for external assembler ASL
+ # @return String - Options for ASL
+ proc determinate_asl_options {} {
+ variable assembler_ASL_config ;# Current ASL assembler configuration
+
+ set result {-gnuerrors}
+ if {$assembler_ASL_config(custom) != {}} {
+ append result { } ${assembler_ASL_config(custom)}
+ }
+ foreach opt {-A -a -C -c -h -I -L -M -P -n -quiet -s -u -U -w -x} {
+ if {$assembler_ASL_config($opt)} {
+ append result { } $opt
+ }
+ }
+ foreach opt {-r -i -g -cpu} {
+ if {$assembler_ASL_config($opt) != {}} {
+ append result { } $opt { "} $assembler_ASL_config($opt) {"}
+ }
+ }
+
+ return $result
+ }
+
+ ## Initialize NS variables
+ # @return void
+ proc initialize {} {
+ # Assembler
+ array set ::ExternalCompiler::assembler_ASEM51_addcfg \
+ $::ExternalCompiler::assembler_ASEM51_addcfg_def
+ array set ::ExternalCompiler::assembler_ASEM51_config \
+ $::ExternalCompiler::assembler_ASEM51_config_def
+ array set ::ExternalCompiler::assembler_ASL_addcfg \
+ $::ExternalCompiler::assembler_ASL_addcfg_def
+ array set ::ExternalCompiler::assembler_ASL_config \
+ $::ExternalCompiler::assembler_ASL_config_def
+ array set ::ExternalCompiler::assembler_AS31_addcfg \
+ $::ExternalCompiler::assembler_AS31_addcfg_def
+ array set ::ExternalCompiler::assembler_AS31_config \
+ $::ExternalCompiler::assembler_AS31_config_def
+
+ # SDCC
+ array set ::ExternalCompiler::sdcc_bool_options \
+ $::ExternalCompiler::sdcc_bool_options_def
+ array set ::ExternalCompiler::sdcc_string_options \
+ $::ExternalCompiler::sdcc_string_options_def
+ array set ::ExternalCompiler::sdcc_optional_string_options \
+ $::ExternalCompiler::sdcc_optional_string_options_def
+ array set ::ExternalCompiler::sdcc_scs_string_options \
+ $::ExternalCompiler::sdcc_scs_string_options_def
+ }
+}
+
+# Initialize NS variables
+ExternalCompiler::initialize
diff --git a/lib/compiler/preprocessor.tcl b/lib/compiler/preprocessor.tcl
new file mode 100755
index 0000000..4fca542
--- /dev/null
+++ b/lib/compiler/preprocessor.tcl
@@ -0,0 +1,5184 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# 8051 Assembly language compiler preprocessor. This code is part of Compiler
+# (see compiler.tcl). This NS generates precompiled code for assembler
+# (see assembler.tcl).
+#
+# Requires:
+# - CompilerConsts (compilerconsts.tcl)
+# - CodeListing (codelisting.tcl)
+# - NumSystem (Math.tcl)
+#
+# Basic principle of operation:
+# 1) Remove comments and include files
+# 2) Process controll sequences ($SOMETHING)
+# 3) Define as much constants/variables as possible (with cross references)
+# 4) Conditional compilation and directive USING
+# 5) Define macro instructions
+# 6) Recomposite code acording to ORG directives
+# 7) Expand macro instructions (recursive with cross references)
+# 8) Final stage
+#
+# Summary:
+# As you can see it is not just antother two pass assembler. This one
+# is much more sophisticated an much much slower than almost any other
+# 8051 assembler. This assembler should be backward compatible with
+# MetaLink® ASM51 and ASEM-51 by W.W. Heinz.
+# --------------------------------------------------------------------------
+
+namespace eval PreProcessor {
+
+ ## General
+ variable asm {} ;# Resulting precompiled code
+ variable tmp_asm {} ;# Tempotary auxiliary precompiled code
+ variable lineNum 0 ;# Number of the current line
+ variable fileNum 0 ;# Number of the current file
+ variable program_memory ;# String of booleans: Map of program memory usage
+ variable idx 0 ;# Current position in asm list
+ variable optims 0 ;# Number of performed optimalizations
+ variable macros_first 1 ;# Bool: Define and expand macro instruction before conditional
+ ;#+ assembly and constants expansions
+
+ ## Errors and warnings
+ variable ErrorAtLine 0 ;# Bool: Error occured on the current line
+ variable Error 0 ;# Bool: An error occured during precompilation
+ variable error_count 0 ;# Number of errors occured
+ variable warning_count 0 ;# Number of warnings occured
+
+ ## Conditional compilation
+ variable Enable 1 ;# Bool: Compilation enabled (conditional compilation)
+ variable IfElse_map ;# Array: Conditional compilation map ($IfElse_map($level) == $bool)
+ variable IfElse_level 0 ;# Current level of conditional compilation evaluation
+
+ ## Memory reservation
+ variable selected_segment cseg ;# Current memory segment (one of {cseg bseg dseg iseg xseg})
+ variable memory_reservation_map ;# Array: memory reservation map (see code)
+ variable segment_pointer ;# Current memory segment pointer
+
+ ## Contants/Variables definitions
+ variable const_BIT ;# Array: Bit values -- ($const_BIT($bit_name) == $value)
+ variable const_CODE ;# Array: Constants defined by directive 'CODE'
+ variable const_DATA ;# Array: Constants defined by directive 'DATA'
+ variable const_IDATA ;# Array: Constants defined by directive 'IDATA'
+ variable const_XDATA ;# Array: Constants defined by directive 'XDATA'
+ variable const_SET ;# Array: Constants defined by directive 'CODE'
+ variable const_EQU ;# Array: Constants defined by directive 'EQU'
+ variable const_SET_SPEC ;# Array: Special constants defined by directive 'CODE'
+ variable const_EQU_SPEC ;# Array: Special constants defined by directive 'EQU'
+ variable labels ;# Array: Values of defined labels ($labels($label) == $address)
+ variable defined_BIT {} ;# List of defined bits (directove 'BIT')
+ variable defined_CODE {} ;# List of constants defined by 'CODE'
+ variable defined_DATA {} ;# List of constants defined by 'DATA'
+ variable defined_IDATA {} ;# List of constants defined by 'IDATA'
+ variable defined_XDATA {} ;# List of constants defined by 'XDATA'
+ variable defined_SET {} ;# List of variables defined by 'SET'
+ variable defined_EQU {} ;# List of constants defined by 'EQU'
+ variable defined_SET_SPEC {} ;# List of special variables defined by 'SET'
+ variable defined_EQU_SPEC {} ;# List of special constants defined by 'EQU'
+ variable defined_LABEL {} ;# List of defined labels
+
+ # List of lists containing names of defined constants
+ variable const_definitions {
+ defined_BIT defined_CODE
+ defined_DATA defined_IDATA
+ defined_XDATA defined_SET
+ defined_EQU defined_SET_SPEC
+ defined_EQU_SPEC
+ }
+
+ ## Macro expansion
+ variable macro ;# Array: Code of defined macro instructions
+ variable defined_MACRO {} ;# List of defined macro instructions
+ variable macro_name_to_append ;# Name of currently defined macro instruction
+
+ ## Special variables
+ variable original_expression ;# Auxiliary variable (see proc. 'ComputeExpr')
+ variable tmp ;# General purpose tempotary variable
+ variable DB_asm {} ;# Tempotary asm code for creating code memory tables
+ variable included_files {} ;# List: Unique unsorted list of included files
+ variable working_dir {} ;# String: Current working directory
+ variable origin_d_addr {} ;# List: Addresses of static program blocks
+
+ ## Configuration variables
+ variable max_include_level 8 ;# Maximum inclusion level
+ variable max_macro_level 8 ;# Maximum macro expansion level
+ variable check_sfr_usage 0 ;# Bool: Check for legal usage of SFR and SFB
+ variable avaliable_SFR {} ;# List: Avaliable SFR and SFB on the target MCU
+
+
+ # ----------------------------------------------------------------
+ # GENERAL PURPOSE PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Initialize preprocessor
+ # @parm String current_dir - Directory containing source file
+ # @parm String filename - Name of file containing source code
+ # @parm String data - Source code to compile
+ # @return List - precompiled source code
+ proc compile {current_dir filename data} {
+ variable macros_first 1 ;# Bool: Define and expand macro instruction before conditional
+ ;#+ assembly and constants expansions
+ variable memory_reservation_map ;# Array: memory reservation map (see code)
+ variable working_dir ;# String: Current working directory
+ variable asm ;# Resulting precompiled code
+ variable segment_pointer ;# Current memory segment pointer
+ variable error_count ;# Number of errors occured
+ variable warning_count ;# Number of warnings occured
+ variable max_include_level ;# Maximum inclusion level
+ variable max_macro_level ;# Maximum macro expansion level
+ variable optims ;# Number of performed optimalizations
+ variable included_files ;# List: Unique unsorted list of included files
+ variable selected_segment ;# Current memory segment (one of {cseg bseg dseg iseg xseg})
+ variable const_EQU ;# Array: Constants defined by directive 'EQU'
+ variable defined_EQU ;# List of constants defined by 'EQU'
+
+ # Reset memory segment pointers
+ set segment_pointer(bseg) 0
+ set segment_pointer(dseg) 0
+ set segment_pointer(iseg) 0
+ set segment_pointer(xseg) 0
+ set selected_segment cseg
+
+ # Reset maps of memory reservation
+ set memory_reservation_map(bseg) [ string repeat 0 256 ]
+ set memory_reservation_map(iseg) [ string repeat 0 256 ]
+ set memory_reservation_map(dseg) [ string repeat 0 256 ]
+ set memory_reservation_map(xseg) [ string repeat 0 65536]
+
+ # Set constants "??MCU_8051_IDE" and "??VERSION"
+ lappend defined_EQU {??MCU_8051_IDE} {??VERSION}
+ set const_EQU(??MCU_8051_IDE) 32849
+ scan $::VERSION "%d.%d.%d" i j k
+ set i [expr {($i << 8) + ($j << 4) + $k}]
+ set const_EQU(??VERSION) $i
+
+ # Reset counters of errors and warnings
+ set error_count 0
+ set warning_count 0
+
+ # Incialize list of included files
+ set working_dir $current_dir
+ set included_files [list [file normalize [file join $current_dir $filename]]]
+
+ # Message "formating code ..."
+ set asm $data
+ if {!${::Compiler::Settings::QUIET}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "\tPreformating code ..."]
+ }
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ ## Convert code to this format:
+ # {
+ # {{lineNumber} {fileNumber} {line of code}}
+ # ...
+ # }
+ line_numbers
+
+ # Message "include ..."
+ if {!${::Compiler::Settings::QUIET}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "\tPutting program pieces together ..."]
+ }
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Import code pieces (INCLUDE file.asm // $INCLUDE('file.inc'))
+ set counter 0
+ while 1 {
+ if {![include_directive $current_dir]} {break}
+ incr counter
+ if {$counter > $max_include_level} {
+ CompilationError "unknown" {} [mc "Inclusion nesting exceeded maximum allowed level"]
+ break
+ }
+ }
+
+ # Remove code after END directive
+ end_of_code
+
+ # Message "encapsulating code ..."
+ if {!${::Compiler::Settings::QUIET}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "\tEncapsulating code ..."]
+ }
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Remove comments and redutant white space
+ trim_code
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ ## Parse controls like $TITLE('bla...bla') or $DATE(36/13/1907)
+ parse_controls
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Discard code listing if listing os not required
+ if {!${::Compiler::Settings::PRINT}} {
+ CodeListing::free_resources
+ }
+
+ # Define basic symbolc names (eg. P0)
+ if {!${::Compiler::Settings::NOMOD}} {
+ define_basic_symbolic_names
+ }
+
+ # Message "Parsing constants, macros etc."
+ if {!${::Compiler::Settings::QUIET}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "\tParsing constants, macros, etc. ..."]
+ }
+
+ if {$macros_first} {
+ # Define macro instructions
+ define_macro_instructions
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Expand macro instructions
+ set counter 0
+ while 1 {
+ if {![expand_macro_instructions]} {break}
+ incr counter
+ if {$counter > $max_macro_level} {
+ CompilationError "unknown" {} [mc "Macro nesting exceeded maximum allowed level"]
+ break
+ }
+ }
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+ }
+
+ ## Parse these directives:
+ # - Donditional compilation (IF, ELSE, ENDIF) (group 0)
+ # - Code listing enable/disable (LIST, NOLIST) (group 1)
+ # - Active bank selection (USING) (group 2)
+ # - Data memory segment selection (BSEG, DSEG, ISEG, XSEG) (group 3)
+ # - Constant definitions (SET, EQU, BIT, DATA, IDATA, XDATA) (group 4)
+ # - Date memory reservation (DS, DBIT) (group 5)
+ while 1 {
+ if {![parse_Consts_and_ConditionalCompilation {0 0 1 1 1 1} 1]} {
+ break
+ }
+ }
+ parse_Consts_and_ConditionalCompilation {1 1 1 1 1 1} 1
+ set selected_segment cseg
+
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Parse code memory segmentation (CSEG DB DW)
+ code_segment 1
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ if {!$macros_first} {
+ # Define macro instructions
+ define_macro_instructions
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+ }
+
+ # Reassemble code acording to ORG directives
+ origin_directive
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Message "Expanding macros"
+ if {!${::Compiler::Settings::QUIET}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "\tExpanding macros ..."]
+ }
+
+ if {!$macros_first} {
+ # Expand macro instructions
+ set counter 0
+ while 1 {
+ if {![expand_macro_instructions]} {break}
+ incr counter
+ if {$counter > $max_macro_level} {
+ CompilationError "unknown" {} [mc "Macro nesting exceeded maximum allowed level"]
+ break
+ }
+ }
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+ }
+
+ # Message "Final stage"
+ if {!${::Compiler::Settings::QUIET}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "\tFinal stage ..."]
+ }
+
+ ## Do three things:
+ # * Convert code to this format:
+ # {
+ # {
+ # {lineNumber} {fileNumber} {instructionAddress} {instructionLength} {instruction}
+ # {oprerand0 operand1 ...} {operand0_type ...}
+ # } ...
+ # }
+ # * Parse labels definition
+ # * Create map of program memory usage (bitmap)
+ parse_instructions
+
+ # Perform code optimalizations
+ set optims 0
+ if {${::Compiler::Settings::optim_ena}} {
+ # Message "Optimalizations"
+ if {!${::Compiler::Settings::QUIET}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "\tOptimalizations ..."]
+ }
+ optimalization
+ }
+
+ # Final constants expansion
+ while 1 {
+ if {![parse_Consts_and_ConditionalCompilation {0 0 1 1 1 1} 0]} {
+ break
+ }
+ }
+
+ # Import table of symbols to current code listing
+ CodeListing::import_symbolic_names
+
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ ## Final stage -- finaly encapsulate code to the resulting form:
+ # {
+ # {
+ # {lineNumber} {fileNumber} {instructionAddress} {instruction}
+ # {oprerand0 operand1 ...} {operand0_type ...}
+ # } ...
+ # }
+ final_stage
+
+ # Free reserved resources
+ free_resources
+
+ # Return precompiled code
+ return $asm
+ }
+
+ ## Free reserved resources
+ # @return void
+ proc free_resources {} {
+ variable memory_reservation_map ;# Array: memory reservation map (see code)
+ variable segment_pointer ;# Current memory segment pointer
+ variable const_BIT ;# Array: Bit values -- ($const_BIT($bit_name) == $value)
+ variable const_CODE ;# Array: Constants defined by directive 'CODE'
+ variable const_DATA ;# Array: Constants defined by directive 'DATA'
+ variable const_IDATA ;# Array: Constants defined by directive 'IDATA'
+ variable const_XDATA ;# Array: Constants defined by directive 'XDATA'
+ variable const_SET ;# Array: Constants defined by directive 'CODE'
+ variable const_EQU ;# Array: Constants defined by directive 'EQU'
+ variable macro ;# Array: Code of defined macro instructions
+ variable program_memory ;# String of booleans: Map of program memory usage
+ variable labels ;# Array: Values of defined labels ($labels($label) == $address)
+ variable defined_BIT {} ;# List of defined bits (directove 'BIT')
+ variable defined_CODE {} ;# List of constants defined by 'CODE'
+ variable defined_DATA {} ;# List of constants defined by 'DATA'
+ variable defined_IDATA {} ;# List of constants defined by 'IDATA'
+ variable defined_XDATA {} ;# List of constants defined by 'XDATA'
+ variable defined_SET {} ;# List of variables defined by 'SET'
+ variable defined_EQU {} ;# List of constants defined by 'EQU'
+ variable defined_SET_SPEC {} ;# List of variables defined by 'SET'
+ variable defined_EQU_SPEC {} ;# List of constants defined by 'EQU'
+ variable defined_LABEL {} ;# List of defined labels
+ variable defined_MACRO {} ;# List of defined macro instructions
+
+ catch {unset macro}
+ catch {unset memory_reservation_map}
+ catch {unset segment_pointer}
+ catch {unset const_BIT}
+ catch {unset const_CODE}
+ catch {unset const_DATA}
+ catch {unset const_IDATA}
+ catch {unset const_XDATA}
+ catch {unset const_SET}
+ catch {unset const_EQU}
+ catch {unset const_SET_SPEC}
+ catch {unset const_EQU_SPEC}
+ catch {unset program_memory}
+ catch {unset labels}
+ }
+
+
+ # ----------------------------------------------------------------
+ # INTERNAL AUXILIARY PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Define basic symbolic names acording to MapOfSFRArea, MapOfSFRBitArea and progVectors
+ # @return void
+ proc define_basic_symbolic_names {} {
+ variable const_BIT ;# Array: Bit values -- ($const_BIT($bit_name) == $value)
+ variable const_DATA ;# Array: Constants defined by directive 'DATA'
+ variable const_CODE ;# Array: Constants defined by directive 'CODE'
+ variable defined_BIT ;# List of defined bits (directove 'BIT')
+ variable defined_DATA ;# List of constants defined by 'DATA'
+ variable defined_CODE ;# List of constants defined by 'CODE'
+
+ # Define bits
+ foreach def ${CompilerConsts::MapOfSFRBitArea} {
+ set var [lindex $def 0] ;# Name
+ set val [lindex $def 1] ;# Address
+ # Adjust name
+ set var [string tolower $var]
+ # Define
+ lappend defined_BIT $var
+ set const_BIT($var) [expr "0x$val"]
+ }
+
+ # Define registers
+ foreach def ${CompilerConsts::MapOfSFRArea} {
+ set var [lindex $def 0] ;# Name
+ set val [lindex $def 1] ;# Address
+ # Adjust name
+ set var [string tolower $var]
+ # Define
+ lappend defined_DATA $var
+ set const_DATA($var) [expr "0x$val"]
+ }
+
+ # Define Program vectors
+ foreach def ${CompilerConsts::progVectors} {
+ set var [lindex $def 0] ;# Name
+ set val [lindex $def 1] ;# Address
+ # Adjust name
+ set var [string tolower $var]
+ # Define
+ lappend defined_CODE $var
+ set const_CODE($var) [expr "0x$val"]
+ }
+ }
+
+ ## Split the given cotrol sequence into its name and argument (without parentheses and quotes)
+ # @parm String data - line of source code to evaluate
+ # @return List - {control argument}
+ proc evaluateControl {data} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # Make backup for input data
+ set original_data $data
+
+ # Determinate control name
+ set data [string range $data 1 end]
+ if {[regexp {^\w+} $data control]} {
+ regsub {^\w+} $data {} data
+ set control [string tolower $control]
+ } {
+ set control {}
+ }
+
+ # Control without argument
+ if {$data == {}} {
+ return [list $control {}]
+ }
+
+ # Determinate argument
+ if {[regexp {^\(.*\)} $data argument]} {
+ # Remove parentheses
+ regsub {^\(.*\)} $data {} data
+ set argument [string trimleft $argument {(}]
+ set argument [string trimright $argument {)}]
+
+ # Remove quotes
+ if {[string index $argument 0] == {'}} {
+ if {[string index $argument end] != {'}} {
+ SyntaxError $lineNum $fileNum [mc "Invalid argument: %s" $argument]
+ } {
+ set argument [string trimleft $argument {'}]
+ set argument [string trimright $argument {'}]
+ }
+ }
+ } {
+ set argument {}
+ }
+
+ # Line cannot contain anything except CS
+ if {$data != {}} {
+ SyntaxError $lineNum $fileNum [mc "Extra characters after control sequence: %s" $original_data]
+ }
+
+ # Return result
+ return [list $control $argument]
+
+ }
+
+ ## Adjust compiler settings to the specified control sequence
+ # @parm String condition - Condition variable (if 1 then dismiss)
+ # @parm String setting - Target configuration variable
+ # @parm String value - New configuration value
+ # @return Bool - One if setting was accepted, zero if setting was dismissed
+ proc AssemlerContol {condition setting value} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # Determinate condition value
+ set condition [subst "\${::Compiler::Settings::$condition}"]
+
+ # Accept
+ if {$condition == 0} {
+ set Compiler::Settings::$setting $value
+ return 1
+ # Dismiss
+ } {
+ Notice $lineNum $fileNum [mc "Control %s has been overrriden (by compiler settings)" $setting]
+ return 0
+ }
+ }
+
+ ## Invoke error message if the given control sequence has no argument
+ # @parm String control - Control sequence (name only)
+ # @parm String argument - Argument (without parantesis and quotes)
+ # @return Bool - result (1 == success; 0 == error message)
+ proc AssemlerContol_expect_one_argument {control argument} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ if {$argument == {}} {
+ SyntaxError $lineNum $fileNum \
+ [mc "Control `%s' expect exactly one argument, but no argument given" "\$[string toupper $control]"]
+ return 0
+ }
+ return 1
+ }
+
+ ## Invoke error message if the given control sequence has an argument
+ # @parm String control - Control sequence (name only)
+ # @parm String argument - Argument (without parantesis and quotes)
+ # @return Bool - result (1 == success; 0 == error message)
+ proc AssemlerContol_expect_no_argument {control argument} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ if {$argument != {}} {
+ SyntaxError $lineNum $fileNum [mc "Control `%s' takes no arguments." "\$[string toupper $control]"]
+ return 0
+ }
+ return 1
+ }
+
+ ## Evaluate and remove control sequences
+ # @return void
+ proc parse_controls {} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable idx ;# Current position in asm list
+
+ variable macros_first 1 ;# Bool: Define and expand macro instruction before conditional
+ ;#+ assembly and constants expansions
+
+ # Reset NS variables
+ set tmp_asm {}
+ set idx -1
+
+ # Iterate over the code
+ foreach line $asm {
+ incr idx
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Determinate line number and line content
+ set lineNum [lindex $line 0]
+ set fileNum [lindex $line 1]
+ set line [lindex $line 2]
+
+ # Skip lines without a control sequence
+ if {[string index $line 0] != "\$"} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ continue
+ }
+
+ # Remove this line from sync. map in code listing
+ CodeListing::delete_line $idx
+ incr idx -1
+
+ # Get and anylize control sequence
+ set ctrl [evaluateControl $line]
+ set control [lindex $ctrl 0] ;# Name
+ set argument [lindex $ctrl 1] ;# Argument
+
+ # Adjust compiler settings acording to the control sequence
+ switch -- $control {
+ {nomacrosfirst} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ set macros_first 0
+ }
+ }
+ {eject} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ CodeListing::directive_eject $idx
+ }
+ }
+ {ej} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ CodeListing::directive_eject $idx
+ }
+ }
+ {nolist} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ CodeListing::directive_nolist $idx
+ }
+ }
+ {noli} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ CodeListing::directive_nolist $idx
+ }
+ }
+ {list} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ CodeListing::directive_list $idx
+ }
+ }
+ {li} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ CodeListing::directive_list $idx
+ }
+ }
+ {nomod} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _nomod NOMOD 1
+ }
+ }
+ {nomod51} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _nomod NOMOD 1
+ }
+ }
+ {nomo} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _nomod NOMOD 1
+ }
+ }
+ {paging} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _paging PAGING 1
+ }
+ }
+ {pi} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _paging PAGING 1
+ }
+ }
+ {nopaging} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _paging PAGING 0
+ }
+ }
+ {nopi} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _paging PAGING 0
+ }
+ }
+ {pagewidth} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ if {[regexp {^\d+$} $argument]} {
+ AssemlerContol _pagewidth PAGEWIDTH $argument
+ } {
+ SyntaxError $lineNum $fileNum \
+ [mc "Invalid argument (must be integer): %s" $argument]
+ }
+ }
+ }
+ {pw} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ if {[regexp {^\d+$} $argument]} {
+ AssemlerContol _pagewidth PAGEWIDTH $argument
+ } {
+ SyntaxError $lineNum $fileNum \
+ [mc "Invalid argument (must be integer): %s" $argument]
+ }
+ }
+ }
+ {pagelength} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ if {[regexp {^\d+$} $argument]} {
+ AssemlerContol _pagelength PAGELENGTH $argument
+ } {
+ SyntaxError $lineNum $fileNum \
+ [mc "Invalid argument (must be integer): %s" $argument]
+ }
+ }
+ }
+ {pl} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ if {[regexp {^\d+$} $argument]} {
+ AssemlerContol _pagelength PAGELENGTH $argument
+ } {
+ SyntaxError $lineNum $fileNum \
+ [mc "Invalid argument (must be integer): %s" $argument]
+ }
+ }
+ }
+ {title} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ AssemlerContol _title TITLE $argument
+ }
+ }
+ {tt} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ AssemlerContol _title TITLE $argument
+ }
+ }
+ {date} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ AssemlerContol _date DATE $argument
+ }
+ }
+ {da} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ AssemlerContol _date DATE $argument
+ }
+ }
+ {object} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ AssemlerContol _object OBJECT_FILE $argument
+ AssemlerContol _object OBJECT 1
+ }
+ }
+ {noobject} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _object OBJECT 0
+ }
+ }
+ {nosb} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _symbols SYMBOLS 0
+ }
+ }
+ {nosymbols} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _symbols SYMBOLS 0
+ }
+ }
+ {noprint} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _print PRINT 0
+ }
+ }
+ {symbols} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _symbols SYMBOLS 1
+ }
+ }
+ {sb} {
+ if {[AssemlerContol_expect_no_argument $control $argument]} {
+ AssemlerContol _symbols SYMBOLS 1
+ }
+ }
+ {print} {
+ if {[AssemlerContol_expect_one_argument $control $argument]} {
+ AssemlerContol _print PRINT_FILE $argument
+ AssemlerContol _print PRINT 1
+ }
+ }
+ default {
+ Warning $lineNum $fileNum [mc "Unsupported control sequence: %s -- control sequence ignored" $line]
+ }
+ }
+ }
+
+ # Replace old code with the new one
+ set asm $tmp_asm
+
+ }
+
+ ## Evaluate and code memory reservation directives (CSEG DB DW)
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names
+ # @return void
+ proc code_segment {ignore_undefined} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable selected_segment ;# Current memory segment (one of {cseg bseg dseg iseg xseg})
+ variable segment_pointer ;# Current memory segment pointer
+ variable DB_asm ;# Tempotary asm code for creating code memory tables
+ variable idx ;# Current position in asm list
+
+ # Reset NS variables
+ set DB_asm {}
+ set value {}
+ set tmp_asm {}
+ set segment_pointer(cseg) {}
+ set idx -1
+
+ # Iterate over the code
+ foreach line $asm {
+ incr idx
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Anylize line
+ set lineNum [lindex $line 0] ;# Line number
+ set fileNum [lindex $line 1] ;# File number
+ set line [lindex $line 2] ;# Line code
+ set cmd [split_line $line] ;# label, command and argumet(s)
+ set directive [regsub {^\.} [lindex $cmd 1] {}] ;# Directive
+
+ # Directive 'DB' (byte reservation) or 'DW' (word reservation)
+ if {$directive == {db} || $directive == {dw} || $directive == {byte}} {
+ # Handle directive "BYTE", which has exactly the same meaning as the "DB"
+ #+ "BYTE" is borrowed from AS31 assembler
+ if {$directive == {byte}} {
+ Warning $lineNum $fileNum [mc "You are using unusual directive 'BYTE', consider usage of 'DB' instead"]
+ set directive {db}
+ }
+
+ set result [reserve_code_memory $cmd $directive $idx $ignore_undefined]
+ if {$result != {}} {
+ incr idx $result
+ }
+
+ # Directive 'CSEG' - code segment selection
+ } elseif {$directive == {cseg}} {
+
+ # Check if there is no label
+ if {[lindex $cmd 0] != {}} {
+ SyntaxError $lineNum $fileNum [mc "CSEG cannot take any label: %s" [lindex $cmd 0]]
+ continue
+ }
+
+ # Select code segment
+ set selected_segment {cseg}
+
+ # Remove this line from the code listing
+ CodeListing::delete_line $idx
+
+ # Check for presence of address expression
+ set expr [lindex $cmd 2]
+ if {$expr == {}} {
+ set segment_pointer(cseg) {}
+ continue
+ }
+
+ # Check for presence of 'AT' operator (CSEG AT addr)
+ if {[string tolower [lindex $expr 0]] != {at}} {
+ SyntaxError $lineNum $fileNum [mc "Missing `AT' operator"]
+ continue
+ }
+ set expr [lreplace $expr 0 0]
+
+ # Determinate, set and validate segment pointer
+ set value [ComputeExpr $expr]
+ if {$value != {}} {
+ # Validate address
+ if {$value > 65535} {
+ SyntaxError $lineNum $fileNum [mc "Argument value out of range: %s (%s)" $expr $value]
+ continue
+ }
+ # Set pointer
+ set segment_pointer(cseg) $value
+ # Adjust code
+ lappend DB_asm [list $lineNum [list {ORG} $value]]
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid expression `%s'" $expr]
+ }
+
+ # Line does not contain any of {CSEG DB DW}
+ } else {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ }
+ }
+
+ # Finalize code adjustment
+ append tmp_asm { }
+ append tmp_asm $DB_asm
+ set asm $tmp_asm
+ }
+
+ ## Reserve code memory (byte or word) -- directives 'DB' 'DW'
+ # -- auxiliary procedure for proc. 'code_segment'
+ # This procedure writes result to NS variable 'DB_asm' or 'tmp_asm'
+ # @parm String cmd - Line of source code adjusted by proc. 'split_line'
+ # @parm String directive - Directive name (one of {DB DW})
+ # @parm String idx - Source index (precompiled code list)
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names
+ # @return Int - Byte length of occupied program memory
+ proc reserve_code_memory {cmd directive idx ignore_undefined} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable selected_segment ;# Current memory segment (one of {cseg bseg dseg iseg xseg})
+ variable segment_pointer ;# Current memory segment pointer
+ variable DB_asm ;# Tempotary asm code for creating code memory tables
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+
+ # Determinate maximum value
+ if {$directive == {db}} {
+ set directive_db 1
+ set max 255
+ } elseif {$directive == {dw}} {
+ set directive_db 0
+ set max 65535
+ } {
+ CompilationError $lineNum $fileNum "Unknown error 7"
+ return
+ }
+
+ # Check if the currently selected memory segment is 'CSEG'
+ if {$selected_segment != {cseg}} {
+ Warning $lineNum $fileNum [mc "Using `%s', but active segment is `%s' (should be CSEG)" [string toupper $directive] [string toupper $selected_segment]]
+ }
+
+ # Validate directive operands
+ set operands [lindex $cmd 2]
+ if {$operands == {}} {
+ SyntaxError $lineNum $fileNum [mc "Missing value"]
+ return
+ }
+ set operands [getOperands $operands 1]
+ if {[llength $operands] == 0} {
+ SyntaxError $lineNum $fileNum [mc "Invalid value"]
+ return
+ }
+ # Check for allowed number of arguments
+ if {!$directive_db && [llength $operands] > 1} {
+ SyntaxError $lineNum $fileNum [mc "Directive DW can take only one argument"]
+ return
+ }
+
+ # Determinate label
+ set label [lindex $cmd 0]
+ if {$label != {}} {
+ append label { }
+ }
+
+ # Iterate over directive operands
+ set first_time 1
+ set undefined 0
+ foreach opr $operands {
+ set undefined 0
+ set len -1
+ # Operand is a string
+ if {![isExpression $opr] && ([string index $opr 0] == {'}) && ([string index $opr end] == {'})} {
+ # Adjust operand
+ set opr [string trimleft $opr {'}]
+ set opr [string trimright $opr {'}]
+ regsub -all {''} $opr {'} opr
+ set opr [subst -nocommands -novariables $opr]
+ set opr_length [string length $opr]
+
+ # Initialize list of decimal operand values (per bytes)
+ set values {}
+
+ # Convert each character separately (to decimal)
+ set escaped 0
+ for {set char_idx 0} {$char_idx < $opr_length} {incr char_idx} {
+ set char [string index $opr $char_idx]
+
+ # Convert character
+ set value [character2number $char]
+
+ # Invalid value
+ if {$value == {}} {
+ CompilationError $lineNum $fileNum [mc "Unable to recognize character: `%s'" $char]
+ continue
+
+ # Valid value
+ } {
+ if {$first_time} {
+ set line [list [list $lineNum $fileNum "${label}DB $value"]]
+ } {
+ set line [list [list $lineNum $fileNum [list DB $value]]]
+ }
+ set first_time 0
+ lappend values $value
+ }
+
+ # Adjust precompiled code
+ if {$segment_pointer(cseg) != {}} {
+ append DB_asm { }
+ append DB_asm $line
+ } {
+ append tmp_asm { }
+ append tmp_asm $line
+ }
+ incr len
+ }
+
+ # Adjust code listing
+ CodeListing::db $idx $values
+ CodeListing::insert_empty_lines $idx $len
+
+ incr idx $len
+
+ # Operand is a direct numerical value, expression, constant, label or variable
+ } else {
+
+ # Evaluate operand value
+ set value [ComputeExpr $opr $ignore_undefined]
+
+ # Unable to compute value
+ if {$value == {}} {
+ # Value could not be determinated in this pass
+ if {$ignore_undefined} {
+ set undefined 1
+ set value $opr
+
+ # Invalid value
+ } {
+ CompilationError $lineNum $fileNum [mc "Invalid expression `%s'" $opr]
+ continue
+ }
+ }
+
+ ## Valid value
+
+ # Check for valid range
+ if {!$undefined && (($value > $max) || ($value < 0))} {
+ SyntaxError $lineNum $fileNum [mc "Argument value out of range: %s" $opr]
+ continue
+ }
+
+ # Round value
+ if {!$undefined} {
+ set value [expr {int($value)}]
+ }
+
+ # One byte (directive DB)
+ if {$directive_db} {
+ if {$first_time} {
+ set line [list [list $lineNum $fileNum "${label}DB $value"]]
+ } {
+ set line [list [list $lineNum $fileNum [list DB $value]]]
+ }
+ CodeListing::db $idx $value
+ incr len
+ set first_time 0
+
+ # Two bytes (directive DW)
+ } {
+ # Spilt value into high- and low-order bytes
+ if {$undefined} {
+ set H_value "(($value) / 256)"
+ set L_value "(($value) % 256)"
+ } {
+ set H_value [expr {$value / 256}]
+ set L_value [expr {$value % 256}]
+ }
+ if {$first_time} {
+ set line [list \
+ [list $lineNum $fileNum "${label}DB {$H_value}"]\
+ [list $lineNum $fileNum [list {DB} $L_value]] \
+ ]
+ } {
+ set line [list \
+ [list $lineNum $fileNum [list {DB} $H_value]] \
+ [list $lineNum $fileNum [list {DB} $L_value]] \
+ ]
+ }
+ set first_time 0
+
+ # Adjust code listing
+ CodeListing::db $idx [list $H_value $L_value]
+ CodeListing::insert_empty_lines $idx 1
+
+ incr len 2
+ incr idx $len
+ }
+
+ # Adjust precompiled code
+ if {$segment_pointer(cseg) != {}} {
+ append DB_asm { }
+ append DB_asm $line
+ } {
+ append tmp_asm { }
+ append tmp_asm $line
+ }
+ }
+ }
+
+ CodeListing::insert_empty_lines $idx [expr {[llength $operands] - 1}]
+ return $len
+ }
+
+ ## Split the given line of code into label, command and argumet(s)
+ # @parm String line - Line of source code
+ # @return List - {label command argument} or {label}
+ proc split_line {line} {
+ # Determinate label
+ if {[regexp {^\w+:} $line label]} {
+ regsub {^\w+:\s*} $line {} line
+ } {
+ set label {}
+ }
+ # If line contains only label -> return only label
+ if {$line == {}} {
+ return $label
+ }
+
+ # Determinate command and argumet(s)
+ if {![regexp {^\s*\.?\w+} $line command]} {
+ set command {}
+ } {
+ set command [string tolower [string trim $command]]
+ }
+ set argument [regsub {^[^\s]+\s*} $line {}]
+
+ # Return result
+ return [list $label $command $argument]
+ }
+
+ ## Convert given list op operands to their final values (expand constants, labels and expressions)
+ # @parm Int address - Instruction address
+ # @parm Int instr_lenght - Instruction length in bytes
+ # @parm List operands - List of operands
+ # @parm List operand_types - List of operand types
+ # @parm String instruction - Instruction name
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names
+ # @return List - resulting list of operands
+ proc operands_to_absolute_values {address instr_lenght operands operand_types instruction ignore_undefined} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # Initialize list of operands
+ if {$instruction == {db}} {
+ set new_operands $operands
+ set operands {}
+ } {
+ set new_operands {}
+ }
+
+ # Replace symbolic names with absolute values
+ foreach opr $operands type $operand_types {
+
+ # Fixed value (eg. 'A')
+ if {[isFixed $opr]} {
+ set opr_val $opr
+
+ # Regular value
+ } else {
+ # Adjust value (remove 1st char is it's one of {# @ /})
+ set char [string index $opr 0]
+ if {$char == {#} || $char == {@} || $char == {/}} {
+ set opr [string replace $opr 0 0]
+ } {
+ set char {}
+ }
+ set opr_val $char
+
+ # Value is an expression
+ if {[isExpression $opr]} {
+ append opr_val [ComputeExpr $opr {} $address]
+
+ # Value is bit addres represented by dot notation
+ } elseif {[regexp {^\w+\.\w+$} $opr]} {
+
+ if {$type != {bit} && $type != {/bit}} {
+ if {!$ignore_undefined} {
+ SyntaxError $lineNum $fileNum [mc "Expected bit address: %s" $opr]
+ }
+ } {
+ set bitAddr [getBitAddr $opr $ignore_undefined]
+ if {$bitAddr == {}} {set bitAddr 0}
+ append opr_val $bitAddr
+ }
+
+ # Value is regular symbolic name
+ } elseif {[isSymbolicName $opr]} {
+ # Determinate list of substitution priorities
+ switch -- $type {
+ {code8} {set priorities {labels code equset xdata} }
+ {code11} {set priorities {labels code equset xdata} }
+ {code16} {set priorities {labels code equset xdata} }
+
+ {imm8} {set priorities {equset data idata xdata bit code labels}}
+ {imm16} {set priorities {equset data idata xdata bit code labels}}
+
+ {data} {set priorities {data idata equset} }
+ {bit} {set priorities {bit equset} }
+ {/bit} {set priorities {bit equset} }
+ default {
+ CompilationError $lineNum $fileNum "Unknown error 0"
+ }
+ }
+
+ # Perform substitution
+ append opr_val [getValueOfSymbolicName \
+ $opr $priorities $address \
+ $ignore_undefined \
+ ]
+
+ # Direct value (some number)
+ } else {
+ append opr_val [COprToDec $opr]
+ }
+
+ # Adjust relative offset
+ if {[string is digit -strict $opr_val] && $type == {code8}} {
+ incr opr_val -$address
+ incr opr_val -$instr_lenght
+ if {($opr_val > 127) || ($opr_val < -128)} {
+ incr opr_val -0x10000
+ if {($opr_val > 127) || ($opr_val < -128)} {
+ if {!$ignore_undefined} {
+ SyntaxError $lineNum $fileNum \
+ [mc "Label is too far for 8-bit relative addressing.\nTry to disable peephole optimalizations if they are on."]
+ }
+ set opr_val 0
+ }
+ }
+ if {$opr_val < 0} {
+ incr opr_val 0x100
+ }
+ }
+ }
+
+ # Adjust list of operands
+ lappend new_operands $opr_val
+
+ # Check for valid value range
+ if {$opr_val != {} && ![checkRange $opr_val $type]} {
+ if {!$ignore_undefined && [string is digit -strict $opr_val]} {
+ SyntaxError $lineNum $fileNum [mc "Operand value out of range: `%s' (`%s')" $opr $opr_val]
+ } {
+ return {}
+ }
+ }
+ }
+
+ # Return result
+ return $new_operands
+ }
+
+ ## Finaly precompiled encapsulate code to the resulting form
+ # @return void
+ proc final_stage {} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable idx ;# Current position in asm list
+
+ # Reset NS variables
+ set idx -1
+ set tmp_asm {}
+ set new_operands {}
+
+ # Expand constants, variables and labels
+ foreach line $asm {
+ incr idx
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Split line into separate fields
+ set i 0
+ foreach var {lineNum fileNum address instr_lenght instruction operands operand_types} {
+ set $var [lindex $line $i]
+ incr i
+ }
+
+ # Directive DB
+ if {$instruction == {db}} {
+ # Undefined value -> try to define
+ set operands [lindex $operands 0]
+
+ if {![string is digit -strict $operands]} {
+ set value [ComputeExpr $operands 0 $address]
+ if {$value == {}} {
+ SyntaxError $lineNum $fileNum [mc "Invalid expression: `%s'" $operands]
+ } elseif {$value < 0 || $value > 255} {
+ SyntaxError $lineNum $fileNum [mc "Value out of range: `%s' (%s)" $operands $value]
+ }
+ set operands $value
+ }
+
+ # Check for instruction validity
+ } elseif {[lsearch -exact -ascii ${CompilerConsts::AllInstructions} $instruction] == -1} {
+ if {[string index $address end] == {:}} {
+ SyntaxError $lineNum $fileNum [mc "Invalid label declaration: `%s'\n\tLabels can contain alfanumeric characters only and must not begin with a digit" $address]
+ } {
+ SyntaxError $lineNum $fileNum [mc "Unknown keyword: `%s'\n\t`%s' is neighter macro nor instruction nor directive" [lindex $address 0] [lindex $address 0]]
+ }
+ continue
+ }
+
+ # Append adjusted line to the code
+ lappend tmp_asm [list \
+ $lineNum $fileNum $address \
+ $instruction \
+ [operands_to_absolute_values \
+ $address $instr_lenght \
+ $operands $operand_types \
+ $instruction 0 \
+ ] \
+ $operand_types \
+ ]
+ }
+
+ # Replace old code with the new one
+ set asm $tmp_asm
+ }
+
+ ## Convert bit addres represented by dot notation to decimal string
+ # @parm String expression - bit address (eg. 'PSW.4')
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names
+ # @return Int - Bit address
+ proc getBitAddr {expression ignore_undefined} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # Split bit address into two parts
+ set opr1 [split $expression {.}]
+ set opr0 [lindex $opr1 0] ;# Register
+ set opr1 [lindex $opr1 1] ;# Bit
+
+ # Register is 'A'
+ if {$opr0 == {A} || $opr0 == {a}} {
+ set regAddr 224
+ # Register is a symbolic name
+ } elseif {[isSymbolicName $opr0]} {
+ set regAddr [getValueOfSymbolicName \
+ $opr0 {data idata equset} {} \
+ $ignore_undefined \
+ ]
+ # Register is regular number
+ } {
+ set regAddr [COprToDec $opr0]
+ }
+
+ # Bit is a symbolic name
+ if {[isSymbolicName $opr1]} {
+ set bitNum [getValueOfSymbolicName \
+ $opr1 {equset} {} \
+ $ignore_undefined \
+ ]
+ # Bit is regular number
+ } {
+ set bitNum [COprToDec $opr1]
+ }
+
+ # Check for valid bit number value
+ if {$bitNum < 0 || $bitNum > 7} {
+ SyntaxError $lineNum $fileNum [mc "Invalid bit designator: %s" $expression]
+ return {}
+ }
+
+ # Register is in high bit addressable area
+ if {$regAddr > 31 && $regAddr < 48} {
+ return [expr {$regAddr - 32 + $bitNum}]
+ # Register bit addressable SFR
+ } elseif {[lsearch -exact -ascii {128 136 144 152 160 168 176 184 208 224 240} $regAddr] != -1} {
+ return [expr {$regAddr + $bitNum}]
+ # Register is not bit addressable
+ } else {
+ SyntaxError $lineNum $fileNum [mc "Given register does not belong to the bit addressable area: %s" $expression]
+ return {}
+ }
+ }
+
+ ## Convert operand value to decimal string (operand must not be an expression)
+ # @parm String operand - operand string (eg. '#0F5h')
+ # @return String - converted operand
+ proc COprToDec {operand} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # If the given operand is fixed string -> return it unchanged
+ if {[lsearch -exact -ascii ${CompilerConsts::FixedOperands} [string tolower $operand]] != -1} {
+ return $operand
+ }
+
+ # Adjust operand string
+ set char [string index $operand 0]
+ if {$char == {#} || $char == {@} || $char == {/}} {
+ set operand [string replace $operand 0 0]
+ } {
+ set char {}
+ }
+
+ # Determinate numeric base and adjust operand string
+ set base [string index $operand end]
+ set operand [string range $operand 0 {end-1}]
+
+ # No base specified -- decimal number
+ if {[regexp {[0-9]} $base]} {
+ append operand $base
+
+ # Convert and return
+ if {[NumSystem::isdec $operand]} {
+ return "$char$operand"
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid value: `%s'" "${char}${operand}"]
+ }
+
+ # Value is charater
+ } elseif {$base == {'}} {
+ # Remove leading quote
+ if {[string index $operand 0] != {'}} {
+ SyntaxError $lineNum $fileNum [mc "Invalid value: `%s'" "${char}${operand}"]
+ return {}
+ } {
+ set operand [string range $operand 1 end]
+ }
+ }
+
+ # Conevert operand value to decimal string
+ set base [string tolower $base]
+ switch -- $base {
+ {h} { ;# From hexadecimal
+ if {[NumSystem::ishex $operand]} {
+ set operand [expr "0x$operand"]
+ return "$char$operand"
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid value: `%s'" "${operand}${base}"]
+ return {}
+ }
+ }
+ {b} { ;# From binary
+ if {[NumSystem::isbin $operand]} {
+ set operand [NumSystem::bin2dec $operand]
+ return "$char$operand"
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid value: `%s'" "${operand}${base}"]
+ return {}
+ }
+ }
+ {o} { ;# From octal
+ if {[NumSystem::isoct $operand]} {
+ set operand [NumSystem::oct2dec $operand]
+ return "$char$operand"
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid value: `%s'" "${operand}${base}"]
+ return {}
+ }
+ }
+ {q} { ;# From octal
+ if {[NumSystem::isoct $operand]} {
+ set operand [NumSystem::oct2dec $operand]
+ return "$char$operand"
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid value: `%s'" "${operand}${base}"]
+ return {}
+ }
+ }
+ {'} { ;# From character
+ if {[string length $operand] != 0} {
+ set operand $char[character2number [subst -nocommands -novariables $operand]]
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid value: `%s'" $operand]
+ return {}
+ }
+ }
+ {d} { ;# From decimal (no conversion)
+ if {[NumSystem::isdec $operand]} {
+ return "$char$operand"
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid value: `%s'" "${operand}${base}"]
+ return {}
+ }
+ }
+ default { ;# Error -- invalid base
+ SyntaxError $lineNum $fileNum [mc "Invalid numeric base `%s'\n\tPossible options are: __H (hex), __D (dec) __B (bin), __Q __O (oct) and 'char'" $base]
+ return {}
+ }
+ }
+ }
+
+ ## Check for valid operand range
+ # @parm String operand - Operand string
+ # @parm String type - Operand type (one of {code8 code11 code16 imm8 imm16 data bit /bit})
+ # @return Bool - result (1 == valid; 0 == invalid)
+ proc checkRange {operand type} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # Both strings to lowercase
+ set type [string tolower $type]
+ set operand [string tolower $operand]
+
+ # Fixed operand
+ if {[lsearch -exact -ascii ${CompilerConsts::FixedOperands} $operand] != -1} {
+ if {$operand == $type} {
+ return 1
+ } {
+ return 0
+ }
+ }
+
+ # Adjust operand
+ set char [string index $operand 0]
+ if {$char == {#} || $char == {@} || $char == {/}} {
+ set operand [string trimleft $operand {#@/}]
+ } {
+ set char {}
+ }
+
+ # Determinate maximum value
+ switch -- $type {
+ {code8} {set max 255}
+ {code11} {set max 2047}
+ {code16} {set max 65535}
+
+ {imm8} {set max 255}
+ {imm16} {set max 65535}
+
+ {data} {set max 255}
+
+ {bit} {set max 255}
+ {/bit} {set max 255}
+ default {
+ CompilationError $lineNum $fileNum "Unknown error 1"
+ return 0
+ }
+ }
+
+ # Check for allowed range
+ if {$operand > $max || $operand < 0} {return 0} {return 1}
+ }
+
+ ## Determinate whether the given string is an expression
+ # @parm String expression - expression
+ # @return Bool - result (1 == is an expression; 0 == is not an expression)
+ proc isExpression {expression} {
+ # Remove strings and quoted characters
+ regsub -all {'[^']*'} $expression {} expression
+
+ # Remove redutant white space
+ set expression [string trimleft $expression "\t "]
+ set expression [string trimright $expression "\t "]
+
+ if {[regexp {[ \+\-\=<>\(\)\*/%]} $expression]} {
+ return 1
+ } {
+ return 0
+ }
+ }
+
+ ## Determinate whether the given string is fixed value (for instance 'A' or 'AB')
+ # @parm String operand - operand string to evaluate
+ # @return Bool - result (1 == is fixed; 0 == is not fixed)
+ proc isFixed {operand} {
+ set operand [string tolower $operand]
+ if {[lsearch -exact -ascii ${CompilerConsts::FixedOperands} $operand] != -1} {
+ return 1
+ } {
+ return 0
+ }
+ }
+
+ ## Determinate whether the given string is a symbolic name
+ # @parm String symbolic_name - operand string to evaluate
+ # @return Bool - result (1 == is symbolic name; 0 == is not symbolic name)
+ proc isSymbolicName {symbolic_name} {
+ # Adjust operand
+ set char [string index $symbolic_name 0]
+ if {$char == {#} || $char == {@} || $char == {/}} {
+ set symbolic_name [string trimleft $symbolic_name {#@/}]
+ }
+
+ # Check if the string starts with a digit or quote
+ if {[regexp {^(\d|')} $symbolic_name]} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Determinate value of the given symbolic name
+ # @parm String symbolic_name - Symbolic name to evaluate
+ # @parm List list_of_priorities - Substitution priorities
+ # @parm Int address - Instruction address
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names
+ # @return Int - decimal string
+ proc getValueOfSymbolicName {symbolic_name list_of_priorities address ignore_undefined} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable check_sfr_usage;# Bool: Check for legal usage of SFR and SFB
+ variable avaliable_SFR ;# List: Avaliable SFR and SFB on the target MCU
+
+ variable const_BIT ;# Array: Bit values -- ($const_BIT($bit_name) == $value)
+ variable const_CODE ;# Array: Constants defined by directive 'CODE'
+ variable const_DATA ;# Array: Constants defined by directive 'DATA'
+ variable const_IDATA ;# Array: Constants defined by directive 'IDATA'
+ variable const_XDATA ;# Array: Constants defined by directive 'XDATA'
+ variable const_SET ;# Array: Constants defined by directive 'CODE'
+ variable const_EQU ;# Array: Constants defined by directive 'EQU'
+
+ variable defined_BIT ;# List of defined bits (directove 'BIT')
+ variable defined_CODE ;# List of constants defined by 'CODE'
+ variable defined_DATA ;# List of constants defined by 'DATA'
+ variable defined_IDATA ;# List of constants defined by 'IDATA'
+ variable defined_XDATA ;# List of constants defined by 'XDATA'
+ variable defined_SET ;# List of variables defined by 'SET'
+ variable defined_EQU ;# List of constants defined by 'EQU'
+
+ variable labels ;# Array: Values of defined labels ($labels($label) == $address)
+ variable defined_LABEL ;# List of defined labels
+
+ # Convert symbolic name to tower case
+ set symbolic_name [string tolower $symbolic_name]
+
+ # Search definition list
+ foreach type $list_of_priorities {
+ switch -- $type {
+ {labels} {
+ if {
+ ([lsearch -exact -ascii $defined_LABEL $symbolic_name] == -1) &&
+ ($symbolic_name != "\$")
+ } {
+ continue
+ }
+
+ if {$symbolic_name == "\$"} {
+ set value $address
+ } {
+ set value $labels($symbolic_name)
+ }
+ CodeListing::symbol_used $symbolic_name {label}
+ return $value
+ }
+ {code} {
+ if {[lsearch -exact -ascii $defined_CODE $symbolic_name] != -1} {
+ CodeListing::symbol_used $symbolic_name {code}
+ return $const_CODE($symbolic_name)
+ }
+ }
+ {xdata} {
+ if {[lsearch -exact -ascii $defined_XDATA $symbolic_name] != -1} {
+ CodeListing::symbol_used $symbolic_name {xdata}
+ return $const_XDATA($symbolic_name)
+ }
+ }
+ {idata} {
+ if {[lsearch -exact -ascii $defined_IDATA $symbolic_name] != -1} {
+ CodeListing::symbol_used $symbolic_name {idata}
+ return $const_IDATA($symbolic_name)
+ }
+ }
+ {data} {
+ if {[lsearch -exact -ascii $defined_DATA $symbolic_name] != -1} {
+ CodeListing::symbol_used $symbolic_name {data}
+
+ if {$check_sfr_usage} {
+ if {
+ [lsearch -ascii -exact $::CompilerConsts::defined_SFR $symbolic_name] != -1
+ &&
+ [lsearch -ascii -exact $avaliable_SFR $symbolic_name] == -1
+ } {
+ Warning $lineNum $fileNum [mc "Special function register \"%s\" is not avaliable on the target MCU" [string toupper $symbolic_name]]
+ }
+ }
+
+ return $const_DATA($symbolic_name)
+ }
+ }
+ {bit} {
+ if {[lsearch -exact -ascii $defined_BIT $symbolic_name] != -1} {
+ CodeListing::symbol_used $symbolic_name {bit}
+
+ if {$check_sfr_usage} {
+ if {
+ [lsearch -ascii -exact $::CompilerConsts::defined_SFRBitArea $symbolic_name] != -1
+ &&
+ [lsearch -ascii -exact $avaliable_SFR $symbolic_name] == -1
+ } {
+ Warning $lineNum $fileNum [mc "Special function bit \"%s\" is not avaliable on the target MCU" [string toupper $symbolic_name]]
+ }
+ }
+
+ return $const_BIT($symbolic_name)
+ }
+ }
+ {equset} {
+ if {![const_exists $symbolic_name]} {
+ continue
+ }
+
+ set val [const_value $symbolic_name $lineNum]
+ if {$val == {}} {
+ break
+ } {
+ CodeListing::symbol_used $symbolic_name {equset}
+ return $val
+ }
+ }
+ default {
+ CompilationError $lineNum $fileNum "Unknown error 2"
+ }
+ }
+ }
+
+ # Symbolic name not found
+ if {!$ignore_undefined} {
+ SyntaxError $lineNum $fileNum [mc "Symbol not defined: %s" $symbolic_name]
+ }
+ return {}
+ }
+
+ ## Perform peerhole optimalization
+ # This function must be called between "parse_instructions" and "final_stage"
+ # @return void
+ proc optimalization {} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable idx ;# Current position in asm list
+ variable labels ;# Array: Values of defined labels ($labels($label) == $address)
+ variable defined_LABEL ;# List of defined labels
+ variable program_memory ;# String of booleans: Map of program memory usage
+ variable optims ;# Number of performed optimalizations
+ variable origin_d_addr ;# List: Addresses of static program blocks
+
+ # Iterate over the code
+ set tmp_asm {}
+ set asm_len [llength $asm]
+ for {set idx 0} {$idx < $asm_len} {incr idx} {
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Split line into separate fields
+ set i 0
+ foreach var {lineNum fileNum address instr_lenght instruction operands operand_types} {
+ set $var [lindex $asm [list $idx $i]]
+ incr i
+ }
+
+ # Convert instruction operands to absolute values
+ set operands_abs [operands_to_absolute_values \
+ $address $instr_lenght \
+ $operands $operand_types \
+ $instruction 1 \
+ ]
+
+ # Do not try to optimalize unresolved lines
+ if {$operands_abs == {} || [string first {$} $operands] != -1} {
+ lappend tmp_asm [list \
+ $lineNum $fileNum $address \
+ $instr_lenght $instruction $operands \
+ $operand_types \
+ ]
+ continue
+ }
+
+ # Optimalize code on this line
+ set bytes_saved 0
+ switch -- $instruction {
+ {setb} { ;# SETB 215 --> SETB C
+ if {[lindex $operands_abs 0] == {215}} {
+ lset operands 0 C
+ lset operand_types 0 c
+ set bytes_saved 1
+ }
+ }
+ {clr} { ;# CLR 215 --> CLR C
+ if {[lindex $operands_abs 0] == {215}} {
+ lset operands 0 C
+ lset operand_types 0 c
+ set bytes_saved 1
+ }
+ }
+ {jmp} { ;# A) JMP code11 --> AJMP code11
+ ;# B) JMP code8 --> SJMP code8
+ ## A)
+ if {[string is digit -strict [lindex $operands_abs 0]]} {
+ set diff [expr {$address - [lindex $operands_abs 0]}]
+ } else {
+ set diff 200 ;# Some value out of range [-126; 129]
+ }
+
+ if {[lindex $operand_types 0] != {code8} && $diff >= -126 && $diff <= 129} {
+ set instruction {sjmp}
+ set operand_types {code8}
+ set bytes_saved 1
+
+ ## B)
+ } elseif {
+ [lindex $operand_types 0] != {code8} &&
+ [lindex $operand_types 0] != {code11} &&
+ [lindex $operands_abs 0] < 2048
+ } then {
+ set instruction {ajmp}
+ set operand_types {code11}
+ set bytes_saved 1
+ }
+ }
+ {ljmp} { ;# A) LJMP code11 --> AJMP code11
+ ;# B) LJMP code8 --> SJMP code8
+ ## A)
+ if {[string is digit -strict [lindex $operands_abs 0]]} {
+ set diff [expr {$address - [lindex $operands_abs 0]}]
+ } {
+ set diff 200 ;# Some value out of range [-126; 129]
+ }
+ if {$diff >= -126 && $diff <= 129} {
+ set instruction {sjmp}
+ set operand_types {code8}
+ set bytes_saved 1
+
+ ## B)
+ } elseif {[lindex $operands_abs 0] < 2048} {
+ set instruction {ajmp}
+ set operand_types {code11}
+ set bytes_saved 1
+ }
+ }
+ {ajmp} { ;# AJMP code8 --> SJMP code8
+ if {[string is digit -strict [lindex $operands_abs 0]]} {
+ set diff [expr {$address - [lindex $operands_abs 0]}]
+ } {
+ set diff 200 ;# Some value out of range [-126; 129]
+ }
+ if {$diff >= -126 && $diff <= 129} {
+ set instruction {sjmp}
+ set operand_types {code8}
+ }
+ }
+ {call} { ;# CALL code11 --> ACALL code11
+ if {[lindex $operand_types 0] != {code11} && [lindex $operands_abs 0] < 2048} {
+ set instruction {acall}
+ set operand_types {code11}
+ set bytes_saved 1
+ }
+ }
+ {lcall} { ;# LCALL code11 --> ACALL code11
+ if {[lindex $operands_abs 0] < 2048} {
+ set instruction {acall}
+ set operand_types {code11}
+ set bytes_saved 1
+ }
+ }
+ {mov} { ;# A) MOV 224, ... --> MOV A, ...
+ ;# B) MOV ..., 224 --> MOV ..., A
+ ## A)
+ if {
+ [lindex $operands_abs 0] == 224
+ &&
+ [lindex $operand_types 0] == {data}
+ } {
+ if {[lindex $operands_abs 1] != {A}} {
+ lset operands 0 A
+ lset operand_types 0 a
+ set bytes_saved 1
+ }
+ ## B)
+ } elseif {
+ [lindex $operands_abs 1] == 224
+ &&
+ [lindex $operand_types 1] == {data}
+ } {
+ lset operands 1 A
+ lset operand_types 1 a
+ set bytes_saved 1
+ }
+ }
+ }
+
+ if {$bytes_saved} {
+ # Increment number of performed optimalizations
+ incr optims
+
+ # Shift code
+ set max_addr $address
+ set last_len $instr_lenght
+ for {set i [expr {$idx + 1}]} {$i < $asm_len} {incr i} {
+ set addr [lindex $asm [list $i 2]]
+ if {$addr != ($max_addr + $last_len) || [lsearch $origin_d_addr $addr] != -1} {
+ break
+ }
+ set max_addr $addr
+ set last_len [lindex $asm [list $i 3]]
+ lset asm [list $i 2] [expr {$addr - $bytes_saved}]
+ }
+
+ # Shift labels
+ foreach lbl $defined_LABEL {
+ if {$labels($lbl) > $address && $labels($lbl) <= $max_addr} {
+ incr labels($lbl) -$bytes_saved
+ }
+ }
+
+ # Adjust instruction length
+ incr instr_lenght -$bytes_saved
+ }
+
+ lappend tmp_asm [list \
+ $lineNum $fileNum $address \
+ $instr_lenght $instruction $operands \
+ $operand_types \
+ ]
+ }
+
+ set asm $tmp_asm
+ }
+
+ ## Evaluate and remove instructions
+ # @return void
+ proc parse_instructions {} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable idx ;# Current position in asm list
+ variable labels ;# Array: Values of defined labels ($labels($label) == $address)
+ variable defined_LABEL ;# List of defined labels
+ variable program_memory ;# String of booleans: Map of program memory usage
+
+ variable const_SET_SPEC ;# Array: Special constants defined by directive 'CODE'
+ variable const_EQU_SPEC ;# Array: Special constants defined by directive 'EQU'
+ variable defined_SET_SPEC ;# List of special variables defined by 'SET'
+ variable defined_EQU_SPEC ;# List of special constants defined by 'EQU'
+
+ # Reset NS variables
+ set lineNum {}
+ set instruction_len {}
+ set instruction {}
+ set operands {}
+ set operand_types {}
+ set local_labels {}
+ set tmp_asm {}
+ set program_memory [string repeat 0 65536]
+ set program_pointer 0
+ set new_program_pointer 0
+ set idx -1
+
+ # Iterate over the code
+ foreach line $asm {
+ incr idx
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Determinate line number and line content
+ set lineNum [lindex $line 0]
+ set fileNum [lindex $line 1]
+ set line [lindex $line 2]
+
+ ## Conditionaly change program pointer
+ if {![regexp {^\s*\w+} $line first_field]} {
+ set first_field {}
+ } {
+ set first_field [string trim $first_field]
+ }
+ if {$first_field == {ORG}} {
+ CodeListing::delete_line $idx
+ incr idx -1
+ set program_pointer [lindex $line 1]
+ continue
+ }
+
+ ## Determinate label
+ if {[regexp {^\w+:} $line label]} {
+ # Check for label validity
+ if {[regexp {^\w*:$} $label] && ![regexp {^\d} $label]} {
+
+ set label [string trimright $label {:}]
+ if {[isReservedKeyword $label]} {
+ Warning $lineNum $fileNum [mc "Reserved keyword used as label"]
+ }
+ lappend local_labels $label
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid label: `%s' \n\t(labels can contain only alfanumeric characters and must not begin with a digit)" $label]
+ }
+
+ # Remove label from the line
+ regsub {^\w+:\s*} $line {} line
+ }
+
+ # If the line contains only label then exit
+ if {$line == {}} {
+ CodeListing::delete_line $idx
+ incr idx -1
+ continue
+ }
+
+ ## Determinate instruction
+ if {![regexp {^\s*\.?\w+} $line instruction]} {
+ set instruction {}
+ } {
+ set instruction [string tolower [string trim $instruction]]
+ }
+
+ # Directive 'SKIP'
+ if {$instruction == {skip} || $instruction == {.skip}} {
+ set skip [ComputeExpr [regsub {^\s*\.?\w+\s*} $line {}]]
+ if {$skip == {}} {
+ set instruction_len 0
+ SyntaxError $lineNum $fileNum [mc "Invalid expression `%s'" [regsub {^\s*\.?\w+\s*} $line {}]]
+ } {
+ set instruction_len $skip
+ }
+
+ set instruction {} ;# <-- That means delete this line
+
+ # Directive 'DB'
+ } elseif {$instruction == {db}} {
+ set instruction_len 1
+ set operand_types {}
+ set operands [regsub {^\w+\s*} $line {}]
+
+ # Regular instruction
+ } else {
+ # Check for instruction validity
+ if {[lsearch -exact -ascii ${CompilerConsts::AllInstructions} $instruction] == -1} {
+ lappend tmp_asm [list $lineNum $fileNum {C} $line]
+ continue
+ }
+ # Remove instruction from the line
+ regsub {^\w+\s*} $line {} line
+
+ # Determinate operands
+ set operands [getOperands $line 1]
+
+ # Determinate operand types and instruction length
+ set instr_info [getInstructionInfo $instruction $operands $program_pointer]
+ if {$instr_info == {}} {continue}
+ set instruction_len [lindex $instr_info 0]
+ set operand_types [lindex $instr_info 1]
+ set operands [lindex $instr_info 2]
+ }
+
+ # Define found labels
+ define_labels $local_labels $program_pointer
+
+ # Determinate expected program position
+ set new_program_pointer $program_pointer
+ incr new_program_pointer $instruction_len
+
+ # Check for program pointer validity
+ for {set i $program_pointer} {$i <= $new_program_pointer} {incr i} {
+ if {[string index $program_memory $i] != 0} {
+ CompilationError $lineNum $fileNum [mc "Unable to overwrite already reserved program memory at address 0x%s -- compilation failed" [format %X $i]]
+ }
+ }
+ if {$program_pointer >= ${::Compiler::Settings::code_size}} {
+ Warning $lineNum $fileNum [mc "This instruction exceeding code memory capacity"]
+ }
+
+ # Adjust map of code memory usage
+ set program_memory [string replace $program_memory \
+ $program_pointer [expr {$new_program_pointer - 1}] \
+ [string repeat 1 $instruction_len] \
+ ]
+
+ # Create new code line
+ if {$instruction != {}} {
+ lappend tmp_asm [list \
+ $lineNum $fileNum \
+ $program_pointer $instruction_len \
+ $instruction $operands \
+ $operand_types \
+ ]
+ }
+
+ # Adjust code listing and program pointer
+ CodeListing::set_addr $idx $program_pointer
+ set program_pointer $new_program_pointer
+
+ # Reset
+ set lineNum {}
+ set fileNum {}
+ set instruction_len {}
+ set instruction {}
+ set operands {}
+ set operand_types {}
+ set local_labels {}
+ }
+
+ # Chech if reset address engaged
+ if {![string index $program_memory 0]} {
+ Warning $lineNum $fileNum [mc "No instruction found at address 0x00. Consider usage of appropriate ORG directive to clarify correct code placement."]
+ }
+
+ # Finalize
+ define_labels $local_labels $program_pointer
+ set asm $tmp_asm
+ }
+
+ ## Determinate whether the given string is reserved keyword
+ # @parm String string - string to evaluate
+ # @return Bool - result (1 == is reserved; 0 == is not reserved)
+ proc isReservedKeyword {string} {
+
+ set string [string tolower $string]
+
+ if {
+ [lsearch -exact -ascii ${CompilerConsts::AllInstructions} $string] != -1
+ ||
+ [lsearch -exact -ascii ${CompilerConsts::AllDirectives} $string] != -1
+ } {
+ return 1
+ } {
+ return 0
+ }
+ }
+
+ ## Assign the given address to the given labels
+ # @parm List list_of_labels - Labels to define
+ # @parm Int address - address to assign
+ # @return void
+ proc define_labels {list_of_labels address} {
+ variable defined_LABEL ;# List of defined labels
+ variable labels ;# Array: Values of defined labels ($labels($label) == $address)
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # Return if the given list is empty
+ if {![llength $list_of_labels]} {return}
+
+ # Define the given labels
+ set list_of_labels [string tolower $list_of_labels]
+ foreach label $list_of_labels {
+ if {[lsearch -exact -ascii $defined_LABEL $label] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Label is already defined: `%s'" $label]
+ } {
+ lappend defined_LABEL $label
+ set labels($label) $address
+ }
+ }
+ }
+
+ ## Determinate instruction length and list of operand types
+ # @parm String instruction - instruction name
+ # @parm List operands - instruction operands
+ # @parm Inr address - instruction address
+ # @return List - {instruction_length list_of_operand_types operands}
+ proc getInstructionInfo {instruction operands address} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ variable const_SET_SPEC ;# Array: Special constants defined by directive 'CODE'
+ variable const_EQU_SPEC ;# Array: Special constants defined by directive 'EQU'
+ variable defined_SET_SPEC ;# List of special variables defined by 'SET'
+ variable defined_EQU_SPEC ;# List of special constants defined by 'EQU'
+
+ # Convert fixed operands to uppercase
+ set l [llength $operands]
+ for {set i 0} {$i < $l} {incr i} {
+ set o [lindex $operands $i]
+ if {[lsearch -exact -ascii ${CompilerConsts::FixedOperands} [string tolower $o]] != -1} {
+ set operands [lreplace $operands $i $i [string toupper $o]]
+ }
+ }
+
+ # Initialize variables containing result
+ set operand_types {}
+ set instr_len 0
+
+ # Expand special constants
+ set l [llength $operands]
+ for {set i 0} {$i < $l} {incr i} {
+ set o [string tolower [lindex $operands $i]]
+ if {
+ [lsearch -ascii -exact $defined_EQU_SPEC $o] != -1
+ ||
+ [lsearch -ascii -exact $defined_SET_SPEC $o] != -1
+ } then {
+ set n [const_value $o $lineNum 1]
+ set operands [lreplace $operands $i $i $n]
+
+ Notice $lineNum $fileNum [mc "Overwriting `%s' with `%s' (acording to your previous definition!)" [string toupper $o] [string toupper $n]]
+ }
+ }
+
+ # Determinate basic operand types
+ set operand_types {}
+ foreach opr $operands {
+ lappend operand_types [operandType $opr $instruction $address]
+ }
+
+ # Find instruction set for given instruction
+ if {[lsearch -exact -ascii ${CompilerConsts::AllInstructions} $instruction] == -1} {
+ CompilationError $lineNum $fileNum "Unknown error 3"
+ return {}
+ }
+ set ins_def $CompilerConsts::InstructionDefinition($instruction)
+
+ # Check for valid operands count
+ set max_oprs [lindex $ins_def 0]
+ if {[llength $operands] > $max_oprs} {
+ SyntaxError $lineNum $fileNum [mc "Too many operands, %s can take only %s operand[expr {$max_oprs ? {} : {s}}]" $instruction $max_oprs]
+ return {}
+ } elseif {[llength $operands] < $max_oprs} {
+ SyntaxError $lineNum $fileNum [mc "Too few operands, %s must take exactly %s operand[expr {$max_oprs ? {} : {s}}]" $instruction $max_oprs]
+ return {}
+ }
+
+ # Find matching operand set
+ set operand_types [string tolower $operand_types]
+ set operands_org $operands
+ set operands_changed $operands
+ set operand_types_org $operand_types
+ set match 1
+ for {set i 0} {$i < 3} {incr i} {
+ foreach opr_set_def [lindex $ins_def 1] {
+
+ set opr_list [lindex $opr_set_def 0]
+
+ set match 1
+ foreach given_type $operand_types possible_type $opr_list {
+ if {[lsearch -exact -ascii $given_type $possible_type] == -1} {
+ set match 0
+ break
+ }
+ }
+ if {$match} {
+ set operand_types $opr_list
+ set instr_len [lindex $opr_set_def 1]
+ break
+ }
+ }
+ if {$match} {
+ if {$i} {
+ Notice $lineNum $fileNum [mc "`%s' changed by compiler to `%s'" "$instruction [join $operands_org {, }]" "$instruction [join $operands_changed {, }]"]
+ }
+ break
+ }
+
+ # Try to change operand set without changing meaning
+ set operands_i {}
+ while {$i < 2} {
+ set operands_i [lindex $operands $i]
+ if {
+ $operands_i != {A}
+ &&
+ $operands_i != {C}
+ &&
+ $operands_i != {/C}
+ } {
+ incr i
+ continue
+ }
+
+ set operands $operands_org
+ set operands_changed $operands
+ set operand_types $operand_types_org
+
+ if {$operands_i == {A}} {
+ lset operands $i {224}
+ lset operands_changed $i {ACC}
+ lset operand_types $i {data}
+
+ } elseif {$operands_i == {C}} {
+ lset operands $i {215}
+ lset operands_changed $i {CY}
+ lset operand_types $i {bit}
+
+ } elseif {$operands_i == {/C}} {
+ lset operands $i {/215}
+ lset operands_changed $i {/CY}
+ lset operand_types $i {/bit}
+
+ }
+ break
+ }
+ }
+
+ # No matching operand set found -> error
+ if {!$match} {
+ SyntaxError $lineNum $fileNum [mc "Invalid operand set: %s %s" $instruction [join $operands {,}]]
+ return {}
+ }
+
+ # Return result
+ return [list $instr_len $operand_types $operands]
+ }
+
+ ## Determinate type of the given operand
+ # @parm String instruction - instruction name
+ # @parm String operand - operand to evaluate
+ # @parm Int address - instruction address
+ # @return List - list of possible types
+ proc operandType {operand instruction address} {
+ variable labels ;# Array: Values of defined labels ($labels($label) == $address)
+ variable const_DATA ;# Array: Constants defined by directive 'DATA'
+ variable const_IDATA ;# Array: Constants defined by directive 'IDATA'
+ variable const_XDATA ;# Array: Constants defined by directive 'XDATA'
+ variable defined_LABEL ;# List of defined labels
+ variable defined_BIT ;# List of defined bits (directove 'BIT')
+ variable defined_DATA ;# List of constants defined by 'DATA'
+ variable defined_IDATA ;# List of constants defined by 'IDATA'
+ variable defined_XDATA ;# List of constants defined by 'XDATA'
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # To lowercase
+ set operand [string tolower $operand]
+
+ # Fixed value
+ if {[lsearch -exact -ascii ${CompilerConsts::FixedOperands} $operand] != -1} {
+ return [string toupper $operand]
+ }
+
+ # Immediate or bit address
+ switch -regexp -- $operand {
+ {^/.*$} { return {/bit} }
+ {^#.*$} { return {imm8 imm16} }
+ }
+
+ # Variable length operand (pseudo-instructions: "CALL <code>" and "JMP <code>")
+ if {$instruction == {jmp} || $instruction == {call}} {
+ # Value is an expression
+ if {[isExpression $operand]} {
+ set operand [ComputeExpr $operand 1 $address]
+ # Value is regular symbolic name
+ } elseif {[isSymbolicName $operand]} {
+ set operand [getValueOfSymbolicName \
+ $operand {labels code equset} \
+ $address 1 \
+ ]
+ # Direct value (some number)
+ } else {
+ set operand [COprToDec $operand]
+ Warning $lineNum $fileNum [mc "Direct value used as operand for %s" $instruction]
+ }
+
+ # Determinate appropriate operand type
+ if {$operand == {}} {
+ return {code16}
+ } elseif {$operand >= 0x800} {
+ return {code16}
+ } elseif {(abs($address - $operand) > 126) || $instruction == {call}} {
+ return {code11}
+ } {
+ return {code8}
+ }
+
+ # Register in SFR area
+ } elseif {[lsearch ${::CompilerConsts::defined_SFR} $operand] != -1} {
+ return {data}
+
+ # Bit in SFB area
+ } elseif {[lsearch ${::CompilerConsts::defined_SFRBitArea} $operand] != -1} {
+ return {bit /bit}
+
+ # Interrupt vector
+ } elseif {[lsearch ${::CompilerConsts::defined_progVectors} $operand] != -1} {
+ return {code16 code11 code8}
+
+ # Another type
+ } else {
+ return {data code16 code11 code8 bit /bit}
+ }
+ }
+
+ ## Expand macro instructions
+ # @return Bool - macro expanded
+ proc expand_macro_instructions {} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable macro ;# Array: Code of defined macro instructions
+ variable defined_MACRO ;# List of defined macro instructions
+ variable idx ;# Current position in asm list
+
+ # Skip procedure if there are no defined macro instructions
+ if {![llength $defined_MACRO]} {
+ return 0
+ }
+
+ set label {}
+ set operands {}
+ set instruction {}
+ set macro_code {}
+ set tmp_asm {}
+ set idx -1
+ set del_line 0
+
+ set repeat 0 ;# Bool: Macro expanded
+
+ # Iterate over the code
+ foreach line $asm {
+ incr idx
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Determinate line number and line content
+ set lineNum [lindex $line 0]
+ set fileNum [lindex $line 1]
+ set line [lindex $line 2]
+ # Make line backup
+ set original_line $line
+
+ # Determinate label, instruction and operands
+ set label {}
+ if {[regexp {^\w+:} $line label]} {
+ regsub {^\w+:\s*} $line {} line
+ }
+ if {![regexp {^\s*\.?\w+} $line instruction]} {
+ set instruction {}
+ } {
+ set instruction [string tolower [string trim $instruction]]
+ }
+ regsub {^\.?\w+\s*} $line {} operands
+
+ # Check if the instruction is macro
+ if {[lsearch -exact -ascii $defined_MACRO $instruction] == -1} {
+ lappend tmp_asm [list $lineNum $fileNum $original_line]
+ continue
+ }
+
+ set repeat 1
+
+ # Get code of the macro
+ set macro_code [getMacro $instruction [getOperands $operands 0]]
+ if {$macro_code == {}} {continue}
+
+ # Adjust the precompiled code and code listing
+ if {$label != {}} {
+ lappend tmp_asm [list $lineNum $fileNum $label]
+ set del_line 0
+ } {
+ set del_line 1
+ }
+
+ CodeListing::macro $idx $macro_code
+ if {$del_line} {
+ CodeListing::delete_line $idx
+ incr idx -1
+ }
+
+ foreach line $macro_code {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ incr idx
+ }
+ }
+
+ # Replace old code with the new one and return result
+ set asm $tmp_asm
+ return $repeat
+ }
+
+ ## Debuging procedure
+ # Write current content of the precompiled code to stdout
+ # @return void
+ proc write_asm {} {
+ variable asm ;# Resulting precompiled code
+ puts ""
+ set idx -1
+ foreach line $asm {
+ incr idx
+ puts "$idx:\t$line"
+ }
+ }
+
+ ## Debuging procedure
+ # Write current content of the tempotary precompiled code to stdout
+ # @return void
+ proc write_tmp_asm {} {
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ puts ""
+ set idx -1
+ foreach line $tmp_asm {
+ incr idx
+ puts "$idx:\t$line"
+ }
+ }
+
+ ## Get adjusted code of the given macro instruction
+ # @parm String macro_name - Macro name
+ # @parm List args - Expansion arguments (wrapped in '{}')
+ # @return List - code of the macro
+ proc getMacro {macro_name args} {
+ variable macro ;# Array: Code of defined macro instructions
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # Adjust list of armuments
+ set args [join $args]
+
+ # Local variables
+ set new_operands {} ;# Instruction operands
+ set result {} ;# Resulting list
+
+ # Determinate code of the macro and its operands
+ set macro_code $macro($macro_name)
+ set m_args [lindex $macro_code 0]
+ set macro_code [lindex $macro_code 1]
+
+ # Check for valid number of arguments
+ set arg_len_diff [expr {[llength $args] - [llength $m_args]}]
+ if {$arg_len_diff < 0} {
+ set arg_len_diff [expr {$arg_len_diff * -1}]
+ SyntaxError $lineNum $fileNum [mc "Too few arguments, %s argument(s) missing: %s ..." $arg_len_diff $macro_name]
+ return {}
+ } elseif {$arg_len_diff > 0} {
+ SyntaxError $lineNum $fileNum [mc "Too many arguments, $s extra argument(s)" $arg_len_diff]
+ return {}
+ }
+
+ # Substitute macro arguments
+ foreach line $macro_code {
+ set new_operands {}
+
+ # Determinate instruction and operands
+ if {![regexp {^\.?\w+\s*} $line instruction]} {
+ set instruction {}
+ }
+ regsub {^\.?\w+\s*} $line {} operands
+ if {$operands == {}} {
+ lappend result $instruction
+ continue
+ }
+ set operands [getOperands $operands 0]
+
+ # Perform substitution
+ foreach opr $operands {
+
+ # Adjust operand
+ set char [string index $opr 0]
+ if {
+ ($char == {/}) ||
+ ($char == {#}) ||
+ ($char == {@})
+ } {
+ set opr [string range $opr 1 end]
+ } {
+ set char {}
+ }
+
+ # Find operand in macro armunets
+ set idx [lsearch -exact -ascii $m_args $opr]
+ if {$idx != -1} {
+ set opr [lindex $args $idx]
+ }
+
+ lappend new_operands "$char$opr"
+ }
+
+ # Recomposite line of macro instruction code
+ set operands [join $new_operands {, }]
+ append instruction "\t"
+ append instruction $operands
+ lappend result $instruction
+ }
+
+ # Return resulting list
+ return $result
+ }
+
+ ## Determinate list of operands
+ # @parm String operands - Operands (eg. 'A, #55d,main')
+ # @parm Bool keep_case - Keep letters case
+ # @return List - list of operands (eg. {A #55d main})
+ proc getOperands {operands keep_case} {
+ if {$operands == {}} {return {}}
+
+ # Local variables
+ set simple_operands $operands ;# Original string without strings and chars
+ set result {} ;# Resulting list
+
+ # Convert strings and quoted charaters to underscores
+ while 1 {
+ if {![regexp {'[^']*'} $simple_operands str]} {break}
+
+ set padding [string repeat {_} [string length $str]]
+ regsub {'[^']*'} $simple_operands $padding simple_operands
+ }
+
+ # Determinate oprands
+ while 1 {
+ set idx [string first {,} $simple_operands]
+ if {$idx == -1} {break}
+
+ incr idx -1
+ set operand [string range $operands 0 $idx]
+ set operand [string trimleft $operand { }]
+ set operand [string trimright $operand { }]
+ lappend result $operand
+ incr idx 2
+
+ set operands [string range $operands $idx end]
+ set simple_operands [string range $simple_operands $idx end]
+ }
+ set operands [string trim $operands]
+
+ lappend result $operands
+ if {$keep_case} {
+ return $result
+ } {
+ return [string tolower $result]
+ }
+ }
+
+ ## Parse and remove definitions of macro instructions
+ # @return void
+ proc define_macro_instructions {} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable macro ;# Array: Code of defined macro instructions
+ variable defined_MACRO ;# List of defined macro instructions
+ variable idx ;# Current position in asm list
+ variable macro_name_to_append ;# Name of currently defined macro instruction
+
+ # Reset NS variables
+ set tmp_asm {}
+ set idx -1
+
+ # Local variables
+ set Macro 0 ;# Bool: definition opened
+ set Exitm 0 ;# Bool: Definition terminated by directive 'EXITM'
+ set NoMacro 0 ;# Definition failed
+ set del_line 1 ;# Bool: remove this line
+ set macro_name {} ;# Name of the macro
+ set macro_args {} ;# List of arguments for the macro
+ set rept_macro 0 ;# Bool: repeat macro starts
+
+ # Iterate over the code
+ foreach line $asm {
+ incr idx
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ set del_line 1 ;# Flag "remove this line"
+
+ # Determinate line number and line content
+ set lineNum [lindex $line 0]
+ set fileNum [lindex $line 1]
+ set line [lindex $line 2]
+
+ # Spilt line into first 2 separate fields
+ if {![regexp {^\s*\.?\w+} $line field0]} {
+ set field0 {}
+ } {
+ set field0 [string trim $field0]
+ }
+ if {![regexp {^\s*\.?\w+:?\s+\.?\w+} $line field1]} {
+ set field1 {}
+ } {
+ regexp {\.?\w+$} $field1 field1
+ }
+ set field0_l [regsub {^\.} [string tolower $field0] {}]
+ set field1_l [regsub {^\.} [string tolower $field1] {}]
+
+ # Repeat macro
+ if {$field0_l == {rept} || $field0_l == {times}} {
+ if {$Macro} {
+ SyntaxError $lineNum $fileNum \
+ [mc "Cannot define macro inside anoner one -- macro processing failed"]
+ } {
+ regsub {^\s*\.?\w+\s*} $line {} macro_args
+ set macro_args [ComputeExpr $macro_args]
+ if {$macro_args == {}} {
+ SyntaxError $lineNum $fileNum [mc "Missign number of repeats"]
+ set NoMacro 1
+ } elseif {$macro_args < 0} {
+ Warning $lineNum $fileNum [mc "Number of repeats is lower than zero"]
+ set NoMacro 1
+ } elseif {$macro_args == 0} {
+ Notice $lineNum $fileNum [mc "Zero number of repeats"]
+ set NoMacro 1
+ }
+ set macro_name ${idx}
+
+ set macro_name_to_append $macro_name
+ set macro($macro_name) {}
+ set Macro 1
+ set rept_macro 1
+ }
+
+ # Open macro definition
+ } elseif {$field1_l == {macro}} {
+ if {$Macro} {
+ SyntaxError $lineNum $fileNum \
+ [mc "Cannot define macro inside anoner one -- macro processing failed"]
+ } {
+ # Determinate name and arguments
+ regsub {^\w+\s+\.?\w+\s*} $line {} macro_args
+ set macro_args [getOperands $macro_args 0]
+ set macro_name $field0_l
+
+ # Check for validity of the name
+ if {
+ ([lsearch -exact -ascii ${CompilerConsts::AllInstructions} $macro_name] != -1)
+ ||
+ ([lsearch -exact -ascii ${CompilerConsts::AllDirectives} $macro_name] != -1)
+ } {
+ # Invalid name
+ SyntaxError $lineNum $fileNum [mc "Macro name is reserved keyword: %s" $macro_name]
+ set NoMacro 1
+ } {
+ # Valid name
+ if {[lsearch -exact -ascii $defined_MACRO $macro_name] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Macro `%s' is already defined" $macro_name]
+ set NoMacro 1
+ } {
+ set macro_name_to_append $macro_name
+ set macro($macro_name) {}
+ }
+ set Macro 1
+ }
+ }
+
+ # Exit macro definition
+ } elseif {$field0_l == {exitm}} {
+ if {!$Macro} {
+ Warning $lineNum $fileNum [mc "Unable to exit macro, no macro is opened"]
+ }
+ set Exitm 1
+ set rept_macro 0
+
+ # Directive takes no arguments
+ if {[string length $field1_l]} {
+ Warning $lineNum $fileNum [mc "Directive %s takes no arguments" [string toupper $field0_l]]
+ }
+
+ # Close macro definition
+ } elseif {$field0_l == {endm}} {
+ # No macro was opened
+ if {!$Macro} {
+ SyntaxError $lineNum $fileNum [mc "Unable to close macro, no macro is opened"]
+ # Close macro
+ } {
+ if {$rept_macro} {
+ set line $macro($macro_name)
+ set macro($macro_name) [list]
+ for {set i 0} {$i < $macro_args} {incr i} {
+ set macro($macro_name) [concat $macro($macro_name) $line]
+ }
+
+ set macro_args {}
+ set del_line 0
+ lappend tmp_asm [list $lineNum $fileNum $macro_name]
+ }
+
+ if {!($Exitm || $NoMacro)} {
+ set macro($macro_name) [list $macro_args $macro($macro_name)]
+ regsub -all {\s+} $macro($macro_name) { } macro($macro_name)
+ regsub -all "\\\{ " $macro($macro_name) "\{" macro($macro_name)
+
+ lappend defined_MACRO $macro_name_to_append
+ }
+ }
+
+ # Reset some local variables
+ set Macro 0
+ set Exitm 0
+ set NoMacro 0
+ set rept_macro 0
+
+ # Directive takes no arguments
+ if {[string length $field1_l]} {
+ Warning $lineNum $fileNum [mc "Directive %s takes no arguments" [string toupper $field0_l]]
+ }
+
+ # Regular line
+ } else {
+ # Part of macro definition
+ if {$Macro} {
+ if {[regexp {^\w+:} $line]} {
+ Warning $lineNum $fileNum [mc "Bad layout: Macros cannot contain labels -- label deleted"]
+ regsub {^\w+:\s*} $line {} line
+ }
+ if {!($Exitm || $NoMacro)} {
+ lappend macro($macro_name) $line
+ }
+ # Common line
+ } {
+ if {$field0_l == {macro}} {
+ SyntaxError $lineNum $fileNum [mc "Missing name of macro"]
+ } elseif {[regexp {^\s*\w+:} $line] && ($field1_l == {endm} || $field1_l == {exitm})} {
+ SyntaxError $lineNum $fileNum [mc "Labels are not allowed before directives ENDM and EXITM"]
+ } {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ }
+ set del_line 0
+ }
+ }
+
+ # Remove the current line
+ if {$del_line} {
+ CodeListing::delete_line $idx
+ incr idx -1
+ }
+ }
+
+ # Replace old code with the new one
+ set asm $tmp_asm
+ }
+
+ ## Evaluate and remove inclusion directives
+ # @parm String dir - path to the current working directory
+ # @return Bool - code included
+ proc include_directive {dir} {
+ variable included_files ;# List: Unique unsorted list of included files
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable idx ;# Current position in asm list
+
+ # Reset NS variables
+ set tmp_asm {}
+
+ # Local variables
+ set repeat 0 ;# Flag "code included"
+
+ # Iterate over the code
+ set asm_len [llength $asm]
+ for {set idx 0} {$idx < $asm_len} {incr idx} {
+ set line [lindex $asm $idx]
+ set line_org $line
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ set file {} ;# File to include
+ set lineNum [lindex $line 0] ;# Number of the current line
+ set fileNum [lindex $line 1] ;# Number of the current file
+ set line [lindex $line 2] ;# Code of the current line
+
+ # Remove comment
+ regsub {\s*;.*$} $line {} line
+
+ # Determinate label
+ if {[regexp {^\s*\w+:} $line label]} {
+ regsub {^\s*\w+:\s*} $line {} line
+ set label [string trimleft $label " \t"]
+ set label [string trimright $label " \t"]
+ } {
+ set label {}
+ }
+
+ # Determinate directive
+ if {![regexp {^\s*\.?\w+} $line directive]} {
+ set directive {}
+ } {
+ set directive [string trim $directive]
+ }
+ set directive_l [string tolower $directive]
+
+ # Directive 'INCLUDE file'
+ if {[regsub {^\.} $directive_l {}] == {include}} {
+ regsub {^\s*\.?\w+} $line {} file_name
+ regsub {^\s+} $file_name {} file_name
+ if {![string length $file_name]} {
+ SyntaxError $lineNum $fileNum [mc "Missing filename"]
+ }
+ set asm [lreplace $asm $idx $idx [list $lineNum $fileNum $label]]
+
+ # Control sequence '$INCLUDE(file)'
+ } elseif {[regexp -nocase -- {^[\s ]*\$inc(lude)?[\s ]*\([^\(\)]*\)} $line file_name]} {
+ set file_name [regsub -nocase -- {^[\s ]*\$include[\s ]*} $file_name {}]
+ set file_name [string range $file_name 1 end-1]
+ if {![string length $file_name]} {
+ SyntaxError $lineNum $fileNum [mc "Missing filename"]
+ }
+ set asm [lreplace $asm $idx $idx [list $lineNum $fileNum $label]]
+
+ # Nothing interesting
+ } else {
+ set file_name {}
+ }
+
+ # Read file if any
+ if {$file_name != {}} {
+ # Determinate final file name
+ set file_name [regsub -all "\\\\\"" [string trim $file_name] "\""]
+ if {
+ ([string index $file_name 0] == "\"" && [string index $file_name end] == "\"")
+ ||
+ ([string index $file_name 0] == {'} && [string index $file_name end] == {'})
+ } {
+ set file_name [string range $file_name 1 end-1]
+ }
+ set file_name [string trim $file_name]
+ set file_name [file normalize [file join $dir $file_name]]
+
+ # Determinate file number
+ set file_number [lsearch -ascii -exact $included_files $file_name]
+ if {$file_number == -1} {
+ set file_number [llength $included_files]
+ lappend included_files $file_name
+ }
+
+ # Read file and adjust $asm
+ set file [getFile $dir $file_name $file_number]
+ }
+
+ # File is not empty
+ if {[string length $file]} {
+ set repeat 1
+
+ CodeListing::include $idx [concat [list $line_org] $file]
+ set idx_plus_1 [expr {$idx + 1}]
+ if {$idx_plus_1 >= $asm_len} {
+ lappend CodeListing::sync_map {}
+ lappend asm [list $lineNum $fileNum {}]
+ }
+ set tmp_asm [lrange $asm $idx_plus_1 end]
+ set asm [lreplace $asm $idx_plus_1 end]
+ append asm { }
+ append asm $file
+ append asm { }
+ append asm $tmp_asm
+
+ set file_len [llength $file]
+ incr asm_len $file_len
+ incr idx $file_len
+ }
+ }
+
+ # Return flag "code included"
+ return $repeat
+ }
+
+ ## Get content of the specified file
+ # @parm String dir - Current working directory
+ # @parm String file - Name of file to include
+ # @parm Int file_number - Index in $included_files
+ # @return Bool - content of the file
+ proc getFile {dir file file_number} {
+ variable fileNum ;# Number of the current file
+ variable lineNum ;# Number of the current line
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+
+ set tmp_asm {}
+
+ # File name enclosed by quotes
+ if {[string index $file 0] == {'}} {
+ if {[string index $file end] != {'}} {
+ SyntaxError $lineNum $fileNum [mc "Invalid expression: `%s'" $file]
+ } {
+ set file [string range $file 1 {end-1}]
+ }
+ } elseif {[string index $file 0] == "\""} {
+ if {[string index $file end] != "\""} {
+ SyntaxError $lineNum $fileNum [mc "Invalid expression: `%s'" $file]
+ } {
+ set file [string range $file 1 {end-1}]
+ }
+ }
+
+ # File exists
+ if {[file exists $file]} {
+ if {[catch {
+ set file [open $file r]
+ set data [read $file]
+ close $file
+ }]} {
+ CompilationError $lineNum $fileNum [mc "Unable to open file: %s" $file]
+ return {}
+ } {
+ # Any EOL to LF
+ regsub -all {\r\n?} $data "\n" data
+
+ # Adjust file content
+ set line_number 1
+ foreach line [split $data "\n"] {
+ lappend tmp_asm [list $line_number $file_number $line]
+ incr line_number
+ }
+
+ return $tmp_asm
+ }
+ # File does not exist
+ } {
+ CompilationError $lineNum $fileNum [mc "File not found: %s" $file]
+ return {}
+ }
+ }
+
+ ## Parse and remove directive(s) 'END'
+ # @return void
+ proc end_of_code {} {
+ variable asm ;# Resulting precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable idx ;# Current position in asm list
+
+ # Reset NS variables
+ set idx -1
+
+ # Local variables
+ set end 0
+ set last_line {}
+
+ # Iterate over the code
+ foreach line $asm {
+ incr idx
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Determinate line number and line content
+ set lineNum [lindex $line 0]
+ set fileNum [lindex $line 1]
+ set line [lindex $line 2]
+
+ # Skip lines without word 'END'
+ if {![regexp -nocase {\.?end} $line]} {
+ continue
+ }
+
+ # Determinate 1st and 2nd field of the line
+ if {![regexp {^\s*\.?\w+} $line field0]} {
+ set field0 {}
+ } {
+ set field0 [string trim $field0]
+ }
+ if {![regexp {^\s*\.?\w+\s+\.?\w+} $line field1]} {
+ set field1 {}
+ } {
+ regexp {\.?\w+$} $field1 field1
+ }
+ set field0 [string tolower [regsub {^\.} $field0 {}]]
+ set field1 [string tolower [regsub {^\.} $field1 {}]]
+
+ # Directive 'end' detected in the 1st field
+ if {$field0 == {end}} {
+ set end 1
+ break
+
+ # Directive 'end' and some label
+ } elseif {
+ [regexp {^\w+:$} $field0]
+ &&
+ ($field1 == {end})
+ } {
+ # Determinate content of the last line of the code (that label)
+ if {![regexp {^\w+:$} $field0 last_line]} {
+ set last_line {}
+ }
+
+ # Check if the line does not contain anything except the label and 'END'
+ regsub {^\w+:\s*} $line {} line
+ set line [string tolower $line]
+ if {$line != {end}} {
+ SyntaxError $lineNum $fileNum [mc "Extra symbols after `END' directive"]
+ }
+
+ set end 1
+ break
+ }
+ }
+
+ # Directive 'end' detected -> adjust the code
+ if {$end} {
+ set asm [lreplace $asm $idx end]
+ if {$last_line != {}} {
+ lappend asm [list $lineNum $fileNum $last_line]
+ }
+ CodeListing::end_directive $idx
+ incr idx
+ # Directive 'end' not found -> invoke warning
+ } {
+ Warning 0 0 [mc "Missing `END' directive"]
+ }
+ }
+
+ ## Parse and remove directive(s) 'ORG' and reorganize the current code
+ # @return void
+ proc origin_directive {} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable idx ;# Current position in asm list
+ variable defined_LABEL ;# List of defined labels
+ variable labels ;# Array: Values of defined labels ($labels($label) == $address)
+ variable ErrorAtLine ;# Bool: Error occured on the current line
+ variable origin_d_addr ;# List: Addresses of static program blocks
+
+ # Reset NS variables
+ set tmp_asm {}
+ set idx -1
+ set origin_d_addr {}
+
+ ## Map of program memory organization
+ # {
+ # {lineNumber fileNumber address}
+ # ...
+ # }
+ set organization {}
+
+ # Create code organization map and remove lines containing directive 'ORG'
+ set last_value 0
+ foreach line $asm {
+ incr idx
+ set ErrorAtLine 0
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Determinate line number and line content
+ set lineNum [lindex $line 0]
+ set fileNum [lindex $line 1]
+ set line [lindex $line 2]
+
+ # Skip lines without word 'ORG'
+ if {![regexp -nocase {\.?org} $line]} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ continue
+ }
+
+ # Determinate label
+ if {![regexp {^\w+:} $line label]} {
+ set label {}
+ }
+
+ # Remove label from the line
+ regsub {^\w+:} $line {} line
+ set line [string tolower $line]
+
+ # Directive ORG detected
+ if {![regexp {^\s*\.?\w+} $line field0]} {
+ set field0 {}
+ } {
+ set field0 [string trim $field0]
+ }
+ if {[regsub {^\.} $field0 {}] == {org}} {
+ # Determinate argument
+ set line [lreplace $line 0 0]
+ set value {}
+ set error 0
+ if {$line == {}} {
+ SyntaxError $lineNum $fileNum [mc "Missing address"]
+ set error 1
+ } {
+ set value [ComputeExpr $line]
+ }
+
+ # Adjust label and check if it is not already defined
+ if {$label != {}} {
+ set label [string trimright $label {:}]
+ if {[regexp {^[a-zA-Z]\w*$} $label]} {
+ if {[lsearch -exact -ascii $defined_LABEL $label] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Label already defined: `%s'" $label]
+ set error 1
+ }
+ } {
+ SyntaxError $lineNum $fileNum [mc "Invalid label: `%s'" $label]
+ set error 1
+ }
+ }
+
+ # Empty argument -> error
+ if {!$error && $value == {}} {
+ SyntaxError $lineNum $fileNum [mc "Invalid expression `%s'" $line]
+ set error 1
+ }
+
+ # Skip lines containing error
+ if {$error} {continue}
+
+ # Define the label
+ if {$label != {}} {
+ lappend defined_LABEL $label
+ set labels($label) $value
+ }
+
+ # Adjust the code and organization map
+ lappend tmp_asm [list $lineNum $fileNum [list {ORG} $value]]
+ lappend organization [list $lineNum $fileNum $value]
+ if {$last_value > $value} {
+ Warning $lineNum $fileNum [mc "This ORG has lower value than the previous one"]
+ }
+ set last_value $value
+
+ # Directive ORG wasn't detected
+ } {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ }
+ }
+
+ # Replace old code with the new one
+ set asm $tmp_asm
+
+ # Empty organization map -> abort
+ if {$organization == {}} {return}
+
+ ## Convert map of program organization to this form:
+ # {
+ # {lineNumber_start fileNum_start lineNumber_end fileNum_end address}
+ # ...
+ # }
+
+ # Sort organization map by start line
+ set organization [lsort -index 0 -integer $organization]
+
+ set last_line {} ;# Last line number
+ set last_addr {} ;# Last address or origin
+ set new_organization {} ;# New organization map
+
+ # Reformat organization map
+ foreach org $organization {
+ set line [lindex $org 0] ;# Line number
+ set file [lindex $org 1] ;# File number
+ set addr [lindex $org 2] ;# Address or origin
+
+ # Adjust new organization map
+ if {$last_line != {}} {
+ incr line -1
+ lappend new_organization [list $last_line $last_file $line $file $last_addr]
+ incr line
+ }
+ set last_line $line ;# Last line number
+ set last_file $file ;# Last file number
+ set last_addr $addr ;# Last address or origin
+
+ }
+ lappend new_organization [list $last_line $last_file [lindex $asm {end 0}] [lindex $asm {end 1}] $addr]
+
+ # Sort organization map by address
+ set organization [lsort -index 4 -integer $new_organization]
+
+ ## Reassemble the code
+ set tmp_asm {}
+ set new_organization {}
+ foreach org $organization {
+ set start [lineNum2idx [lindex $org 0] [lindex $org 1] 1] ;# Line of the start
+ set end [lineNum2idx [lindex $org 2] [lindex $org 3] 0] ;# Line of the end
+
+ lappend origin_d_addr [lindex $org 4]
+ lappend new_organization [list $start $end]
+
+ append tmp_asm { }
+ append tmp_asm [lrange $asm $start $end]
+ set asm [lreplace $asm $start $end]
+ }
+ if {$asm != {}} {
+ append tmp_asm { }
+ append tmp_asm $asm
+ }
+ set asm $tmp_asm
+
+ # Adjust code listing
+ CodeListing::org $new_organization
+ }
+
+ ## Convert pair line number and file number to index in the code list
+ # @parm Int line_number - line number
+ # @parm Int file_number - file number
+ # @parm Bool first - match the first
+ # @return Int - list index
+ proc lineNum2idx {line_number file_number first} {
+ variable asm ;# Resulting precompiled code
+
+ set idx -1
+ set ln 0
+ foreach line $asm {
+ incr idx
+
+ if {[lindex $line 1] != $file_number} {
+ continue
+ }
+
+ set ln [lindex $line 0]
+
+ if {($first && ($ln >= $line_number)) || (!$first && ($ln > $line_number))} {
+ if {$ln > $line_number} {
+ incr idx -1
+ }
+ if {$idx < 0} {
+ return 0
+ } {
+ return $idx
+ }
+ }
+ }
+ set len [llength $asm]
+ incr len -1
+ return $len
+ }
+
+ ## Convert the current code into numbered list (see proc. 'compile')
+ # @return void
+ proc line_numbers {} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # Reset NS variables
+ set tmp_asm {}
+ set lineNum 0
+ set idx -1
+
+ # Adjust some special characters
+ regsub -all {\r\n?} $asm "\n" asm
+ regsub -all {\\} $asm "\\\\" asm
+ regsub -all {\{} $asm "\\\{" asm
+ regsub -all {\}} $asm "\\\}" asm
+ regsub -all {\"} $asm "\\\"" asm
+
+ # Create new code list
+ foreach line [split $asm "\n"] {
+ incr idx
+ incr lineNum
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+ # Append adjusted line to the code
+ lappend tmp_asm [list $lineNum 0 $line]
+ }
+
+ # Replace old code with the new one
+ set asm $tmp_asm
+
+ # Create code listing
+ CodeListing::create_listing $asm
+ }
+
+ ## Evaluate and remove directives related to:
+ # - Donditional compilation (IF, ELSE, ENDIF) (group 0)
+ # - Code listing enable/disable (LIST, NOLIST) (group 1)
+ # - Active bank selection (USING) (group 2)
+ # - Data memory segment selection (BSEG, DSEG, ISEG, XSEG) (group 3)
+ # - Constant definitions (SET, EQU, BIT, DATA, IDATA, XDATA) (group 4)
+ # - Data memory reservation (DS, DBIT) (group 5)
+ # @parm List on 6 Bools - Groups to parse
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names
+ # @return Bool - Anything expanded
+ proc parse_Consts_and_ConditionalCompilation {groups ignore_undefined} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable ErrorAtLine ;# Bool: Error occured on the current line
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable idx ;# Current position in asm list
+ variable Enable ;# Bool: Compilation enabled (conditional compilation)
+ variable memory_reservation_map ;# Array: memory reservation map (see code)
+ variable defined_SET ;# List of variables defined by 'SET'
+ variable const_SET ;# Array: Constants defined by directive 'CODE'
+
+ # Reset NS variables
+ set idx -1
+ set tmp_asm {}
+ set Enable 1
+
+ # Local variables
+ set deleteLine 1 ;# Remove the current line
+ set fin_result 0 ;# Anything expanded
+ set loc_result 0
+
+ # Iterate over the code
+ foreach line $asm {
+ incr idx
+
+ # Final stage -- skip lines without constant definition
+ if {[llength $line] != 3 && [lindex $line 2] != {C}} {
+ lappend tmp_asm $line
+ continue
+ }
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return $fin_result
+ }
+
+ ## Determinate line number and line content
+ set lineNum [lindex $line 0]
+ set fileNum [lindex $line 1]
+ # Firts level pass
+ if {[llength $line] == 3} {
+ set line [lindex $line 2]
+ regsub -nocase -- {if\(} $line {if (} line ;# Make construction "IF(something)" valid
+ # Final level pass
+ } {
+ set line [lindex $line 3]
+ }
+
+ set ErrorAtLine 0 ;# Reset last error
+ set deleteLine 1 ;# Remove the current error
+
+ # Determinate 1st field of the line
+ if {![regexp {^\s*\.?\w+:?} $line line_first_field]} {
+ set line_first_field {}
+ } {
+ set line_first_field [string trim $line_first_field]
+ }
+ set directive0 [string tolower $line_first_field]
+ set directive0 [regsub {^\.} $directive0 {}]
+
+ # Determinate 2nd field of the line
+ if {![regexp {^\s*\.?\w+:?\s*\.?\w+} $line directive1]} {
+ set directive1 {}
+ } {
+ regsub {^\s*\.?\w+:?\s*} $directive1 {} directive1
+ set directive1 [string trim $directive1]
+ }
+ set directive1 [string tolower $directive1]
+ set directive1 [regsub {^\.} $directive1 {}]
+
+ set label {}
+
+ # Constant definition (SET EQU BIT ...) without constant to define (syntax error)
+ if {
+ [lindex $groups 4] && $Enable &&
+ ([lsearch -exact -ascii ${CompilerConsts::ConstDefinitionDirectives} $directive0] != -1)
+ } {
+ if {[regexp {^\s*\.?\w+\s+\w+\s*\,\s*.+$} $line]} {
+ Warning $lineNum $fileNum [mc "This formulation is deprecated, consider usage of \"<Const> <Directive> <Value>\" instead"]
+
+ set line_expr {}
+ regsub {^\s*\.?\w+\s+\w+\s*\,\s*} $line {} line_expr
+ set line_aux $directive1
+ append line_aux { } $directive0 { } $line_expr
+
+ set loc_result [define_const $directive0 $line_aux $idx $ignore_undefined]
+ if {$loc_result == 2} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ set deleteLine 0
+ } elseif {$loc_result == 0} {
+ set fin_result 1
+ }
+ } {
+ SyntaxError $lineNum $fileNum [mc "Missing name of constant to define"]
+ }
+
+ # Constant definition (SET EQU BIT ...)
+ } elseif {
+ [lindex $groups 4] && $Enable &&
+ ([lsearch -exact -ascii ${CompilerConsts::ConstDefinitionDirectives} $directive1] != -1)
+ } {
+ set loc_result [define_const $directive1 $line $idx $ignore_undefined]
+ if {$loc_result == 2} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ set deleteLine 0
+ } elseif {$loc_result == 0} {
+ set fin_result 1
+ }
+
+ # Listing control (LIST, NOLIST)
+ } elseif {
+ [lindex $groups 1] && (
+ ($directive0 == {list}) ||
+ ($directive0 == {nolist}) ||
+ ($directive1 == {list} && [regexp {^\w+:$} $directive0 label]) ||
+ ($directive1 == {nolist} && [regexp {^\w+:$} $directive0 label])
+ )
+ } {
+ # Warning messages
+ if {($directive0 == {list} || $directive0 == {nolist}) && [string length $directive1]} {
+ Warning $lineNum $fileNum [mc "Directive %s takes no arguments" [string toupper $directive0]]
+ } elseif {($directive1 == {list} || $directive1 == {nolist}) && [string length [regsub {^\s*\.?\w+:?\s+\.?\w+} $line {}]]} {
+ Warning $lineNum $fileNum [mc "Directive %s takes no arguments" [string toupper $directive1]]
+ }
+
+ if {($directive0 == {nolist}) || ($directive1 == {nolist})} {
+ CodeListing::directive_nolist $idx
+ } {
+ CodeListing::directive_list $idx
+ }
+
+ if {($label != {}) && $Enable} {
+ lappend tmp_asm [list $lineNum $fileNum $label]
+ set deleteLine 0
+ }
+
+ # Active bank selection directive -- in 1st field (USING)
+ } elseif {[lindex $groups 2] && $Enable && ($directive0 == {using})} {
+ set loc_result [define_active_bank \
+ [regsub {^\.?\w+\s*} $line {}] $ignore_undefined \
+ ]
+ if {$loc_result == 2} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ set deleteLine 0
+ } elseif {$loc_result == 0} {
+ set fin_result 1
+ }
+
+ # Active bank selection directive -- in 2nd field (USING)
+ } elseif {
+ [lindex $groups 2] && ($directive1 == {using}) && $Enable
+ &&
+ ([regexp {^\w+:$} $directive0 label])
+ } {
+ set loc_result [define_active_bank \
+ [regsub {^\w+:\s*\.?\w+\s*} $line {}] $ignore_undefined \
+ ]
+ set deleteLine 0
+ if {$loc_result == 2} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ } elseif {$loc_result == 0} {
+ lappend tmp_asm [list $lineNum $fileNum $label]
+ set fin_result 1
+ } else {
+ lappend tmp_asm [list $lineNum $fileNum $label]
+ }
+
+ # Data segment selection (XSEG DSEG ...)
+ } elseif {
+ [lindex $groups 3] && $Enable &&
+ ([lsearch -exact -ascii ${CompilerConsts::ConstDataSegmentSelectionDirectives} $directive0] != -1)
+ } {
+ set loc_result [data_segment_selection \
+ $directive0 $directive1 $line $idx $ignore_undefined \
+ ]
+ if {$loc_result == 2} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ set deleteLine 0
+ } elseif {$loc_result == 0} {
+ set fin_result 1
+ }
+
+ # Data memory reservation -- without label (DBIT 125)
+ } elseif {
+ [lindex $groups 5] && $Enable &&
+ ([lsearch -exact -ascii ${CompilerConsts::ConstDataMemoryReservationDirectives} $directive0] != -1)
+ } {
+ regsub {^\.?\w+\s*} $line {} value
+ set loc_result [data_memory_reservation {} $directive0 $value $idx $ignore_undefined]
+ if {$loc_result == 2} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ set deleteLine 0
+ } elseif {$loc_result == 0} {
+ set fin_result 1
+ }
+
+ # Data memory reservation -- with label (ram: DS 4Fh)
+ } elseif {
+ [lindex $groups 5] && [regexp {^\w+:$} $line_first_field] && $Enable
+ &&
+ ([lsearch -exact -ascii ${CompilerConsts::ConstDataMemoryReservationDirectives} $directive1] != -1)
+ } {
+ regsub {^\s*\w+:\s*\.?\w+\s*} $line {} value
+ set loc_result [data_memory_reservation \
+ $line_first_field $directive1 $value $idx $ignore_undefined \
+ ]
+ if {$loc_result == 2} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ set deleteLine 0
+ } elseif {$loc_result == 0} {
+ set fin_result 1
+ }
+
+ # Conditional compilation statement -- in 2nd field (IF ELSE ENDIF IFNDEF IFDEF IFN)
+ } elseif {
+ [lindex $groups 0] && (
+ [lsearch -ascii -exact {if else endif ifndef ifdef ifn} $directive1] != -1
+ ) && (
+ [regexp {^\w+:$} $line_first_field label]
+ )
+ } {
+ # Is compilation enabled ?
+ if {$Enable} {
+ lappend tmp_asm [list $lineNum $fileNum $label]
+ set deleteLine 0
+ }
+
+ regsub {^\w+:\s*\.?\w+\s*} $line {} value
+ If_Else_Endif $directive1 $value
+
+ # Directive takes no arguments
+ if {($directive1 == {else} || $directive1 == {endif}) && [string length $value]} {
+ Warning $lineNum $fileNum [mc "Directive %s takes no arguments" [string toupper $directive1]]
+ }
+
+ } else {
+ # Conditional compilation statement -- in 1st field (IF ELSE ENDIF IFNDEF IFDEF IFN)
+ if {
+ [lindex $groups 0] && (
+ [lsearch -ascii -exact {if else endif ifndef ifdef ifn} $directive0] != -1
+ )
+ } {
+
+ regsub {^\.?\w+\s*} $line {} value
+
+ # Directive takes no arguments
+ if {($directive1 == {else} || $directive1 == {endif}) && [string length $value]} {
+ Warning $lineNum $fileNum [mc "Directive %s takes no arguments" [string toupper $directive0]]
+ }
+
+ If_Else_Endif $directive0 $value
+ } {
+ # Is compilation enabled ?
+ if {$Enable} {
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ set deleteLine 0
+ }
+ }
+ }
+
+ if {$deleteLine} {
+ CodeListing::delete_line $idx
+ incr idx -1
+ }
+ }
+
+ # Sort list of SET variables by line numbers
+ foreach const $defined_SET {
+ set const_SET($const) [lsort -integer -index 0 $const_SET($const)]
+ }
+
+ # Replace old code with the new one
+ set asm $tmp_asm
+
+ return $fin_result
+ }
+
+ ## Set active register bank
+ # @parm String expr - expression defining bank number
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names in declaration
+ # @return Bool - 0 == Resolved; 1 == Unresolved (discard line); 2 == Unresolved (keep line)
+ proc define_active_bank {expr ignore_undefined} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ # Expression must not be empty
+ if {$expr == {}} {
+ SyntaxError $lineNum $fileNum [mc "Empty expression"]
+ return 1
+ }
+
+ # Determinate expression value
+ set value [ComputeExpr $expr $ignore_undefined]
+ if {$value == {}} {
+ if {$ignore_undefined} {
+ return 2
+ }
+ SyntaxError $lineNum $fileNum [mc "Invalid expression: `%s'" $expr]
+ return 1
+ }
+
+ # Check for value validity
+ if {($value > 3) || ($value < 0)} {
+ SyntaxError $lineNum $fileNum [mc "Argument value is out of range ({0 1 2 3}) : `%s'" $value]
+ return 1
+ }
+
+ # Define variables AR0..7
+ set value [expr {$value * 8}]
+ for {set i 0} {$i < 8} {incr i} {
+ define_variable "ar$i" $value 0
+ incr value
+ }
+
+ return 0
+ }
+
+ ## Reserve space in data memory
+ # --auxiliary procedure for 'parse_Consts_and_ConditionalCompilation'
+ # @parm String label - Label
+ # @parm String directive - Directive
+ # @parm String expr - Directive argument
+ # @parm Int idx - Current index in the code list
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names in declaration
+ # @return Bool - 0 == Resolved; 1 == Unresolved (discard line); 2 == Unresolved (keep line)
+ proc data_memory_reservation {label directive expr idx ignore_undefined} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable selected_segment ;# Current memory segment (one of {cseg bseg dseg iseg xseg})
+
+ # Compute expression value
+ if {![string length $expr]} {
+ SyntaxError $lineNum $fileNum [mc "Missing size"]
+ set value 1
+ } {
+ set value [ComputeExpr $expr $ignore_undefined]
+ }
+
+ # Check for value validity
+ if {$value == {}} {
+ if {$ignore_undefined} {
+ return 2
+ }
+ SyntaxError $lineNum $fileNum [mc "Invalid expression `%s'" $expr]
+ return 1
+ } elseif {$value < 0} {
+ SyntaxError $lineNum $fileNum [mc "Length of data area cannot be negative number: %s" $value]
+ return 1
+ }
+
+ # Adjust label
+ set label [string tolower $label]
+
+ # Reserve bit
+ if {$directive == {dbit}} {
+ # Check if the active segment is (BSEG)
+ if {$selected_segment != {bseg}} {
+ Warning $lineNum $fileNum [mc "Using `DBIT' directive, but active segment is `%s' (should be BSEG)" [string toupper $selected_segment]]
+ }
+
+ # Reserve memory
+ return [reserve_memory $label bseg $value $idx]
+
+ # Reserve byte
+ } elseif {$directive == {ds}} {
+ # Check if the active segment is one of {DSEG ISEG XSEG}
+ if {
+ ($selected_segment != {dseg}) &&
+ ($selected_segment != {iseg}) &&
+ ($selected_segment != {xseg})
+ } {
+ Warning $lineNum $fileNum [mc "Using `%s' directive, but currently active segment is `%s'" [string toupper $directive] [string toupper $selected_segment]]
+ set seg {dseg}
+ } {
+ set seg $selected_segment
+ }
+
+ # Reserve memory
+ return [reserve_memory $label $seg $value $idx]
+
+ # Unknown request -> compilation error
+ } {
+ CompilationError $lineNum $fileNum "Unknown error 4"
+ return 1
+ }
+
+ return 0
+ }
+
+ ## Reserve bits or bytes of data memory
+ # --auxiliary procedure for 'data_memory_reservation'
+ # @parm String label - Symbolic name
+ # @parm String segment - Target memory segment (one of {dseg iseg xseg bseg})
+ # @parm Int value - Number of bits/bytes to reserve
+ # @parm Int idx - Current index in the code list
+ # @return Bool - 0 == Resolved; 1 == Unresolved
+ proc reserve_memory {label segment value idx} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable segment_pointer ;# Current memory segment pointer
+ variable memory_reservation_map ;# Array: memory reservation map (see code)
+ variable const_BIT ;# Array: Bit values -- ($const_BIT($bit_name) == $value)
+ variable const_DATA ;# Array: Constants defined by directive 'DATA'
+ variable const_IDATA ;# Array: Constants defined by directive 'IDATA'
+ variable const_XDATA ;# Array: Constants defined by directive 'XDATA'
+ variable defined_BIT ;# List of defined bits (directove 'BIT')
+ variable defined_DATA ;# List of constants defined by 'DATA'
+ variable defined_IDATA ;# List of constants defined by 'IDATA'
+ variable defined_XDATA ;# List of constants defined by 'XDATA'
+
+ ## Determinate these things:
+ # - Type of the defined constant :: const_type
+ # - Recomended maximum :: recomended_max
+ # - Name of the target memory segment :: segment_name
+ # - Maximum value :: max
+ # - Unit (Bytes or Bits) :: Bytes
+ switch -- $segment {
+ {dseg} { ;# General data memory
+ set const_type {DATA}
+ set recomended_max 235
+ set segment_name {general data memory}
+ set area_name {byte}
+ set max 255
+ set unit {Bytes}
+ }
+ {iseg} { ;# Internal data memory
+ set const_type {IDATA}
+ set recomended_max 235
+ set segment_name {internal data memory}
+ set area_name {byte}
+ set max 255
+ set unit {Bytes}
+ }
+ {xseg} { ;# External data memory
+ set const_type {XDATA}
+ set recomended_max 60000
+ set segment_name {external data memory}
+ set area_name {byte}
+ set max 65535
+ set unit {Bytes}
+ }
+ {bseg} { ;# Bit addressable area
+ set const_type {BIT}
+ set recomended_max 117
+ set segment_name {bit}
+ set area_name {bit addressable}
+ set max 127
+ set unit {bites}
+ }
+ default { ;# Fatal error
+ CompilationError $lineNum $fileNum "Unknown error 5"
+ }
+ }
+
+ # Check if there is enought free space in the segment
+ set end [expr {$segment_pointer($segment) + $value}]
+ if {$end > $max} {
+ Warning $lineNum $fileNum [mc "Exceeding %s segment boundary by %s $unit." $segment_name [expr {$max - $end}]]
+ } elseif {$end > $recomended_max} {
+ Notice $lineNum $fileNum [mc "Nearing %s segment boundary" $segment_name]
+ }
+
+ # Check if the requested area if not already reserved
+ set area [string range $memory_reservation_map($segment) $segment_pointer($segment) $end]
+ if {[string first 1 $area] != -1} {
+ set idx 0
+ set overflow {}
+ foreach bit [split $area {}] {
+ if {$bit} {
+ lappend overwrite [expr {$idx + $segment_pointer($segment)}]
+ }
+ incr idx
+ }
+
+ set overwrite_dec_hex {}
+ foreach val $overwrite {
+ set val [format %X $val]
+ if {[string length $val] < 4} {
+ set val "[string repeat 0 [expr {4 - [string length $val]}]]$val"
+ }
+ append overwrite_dec_hex { 0x} $val
+ }
+
+ Warning $lineNum $fileNum [mc "Overwriting reserved memory -- in %s area at addresses: %s" $area_name $overwrite_dec_hex]
+ }
+
+ # Adjust map of reserved memory
+ set memory_reservation_map($segment) \
+ [string replace $memory_reservation_map($segment) \
+ $segment_pointer($segment) $end [string repeat 1 $value] \
+ ]
+
+ # Abort if there is no label
+ if {$label == {}} {return}
+
+ # Check for label validity
+ if {![regexp {^[a-zA-Z_]\w*:$} $label]} {
+ SyntaxError $lineNum $fileNum [mc "Invalid label: `%s'" $label]
+ return 1
+ }
+ # Determinate name of the constant
+ set const [string trimright $label {:}]
+
+ # Assing block pointer to symbolic name specified by label
+ if {[lsearch -exact -ascii [subst "\$defined_$const_type"] $const] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Unable redefine constant: %s" $const]
+ return 1
+ } {
+ # Check if this symbol is not already defined
+ if {[isConstAlreadyDefined $const]} {
+ Warning $lineNum $fileNum [mc "Ambiguous symbol definition: %s" $const]
+ }
+
+ # Adjust code listing
+ CodeListing::set_addr $idx $segment_pointer($segment)
+ # Define the symbolic name
+ set const_${const_type}($const) $segment_pointer($segment)
+ lappend defined_${const_type} $const
+ # Adjust segment pointer
+ incr segment_pointer($segment) $value
+ }
+
+ return 0
+ }
+
+ ## Determinate whether the given symbolic name is aleady defined
+ # @parm String const_name - Symbolic name to evaluate
+ # @return Bool - result (1 == aleady defined; 0 == not defined yet)
+ proc isConstAlreadyDefined {const_name} {
+ variable defined_BIT ;# List of defined bits (directove 'BIT')
+ variable defined_CODE ;# List of constants defined by 'CODE'
+ variable defined_DATA ;# List of constants defined by 'DATA'
+ variable defined_IDATA ;# List of constants defined by 'IDATA'
+ variable defined_XDATA ;# List of constants defined by 'XDATA'
+ variable defined_SET ;# List of variables defined by 'SET'
+ variable defined_EQU ;# List of constants defined by 'EQU'
+ variable defined_MACRO ;# List of defined macro instructions
+ variable defined_SET_SPEC ;# List of special variables defined by 'SET'
+ variable defined_EQU_SPEC ;# List of special constants defined by 'EQU'
+
+ # Adjust symbolic name
+ set const_name [string tolower $const_name]
+
+ # Search all lists of symbolic names
+ if {[lsearch -exact -ascii [concat \
+ $defined_BIT $defined_CODE $defined_DATA \
+ $defined_IDATA $defined_XDATA $defined_SET \
+ $defined_EQU $defined_MACRO $defined_SET_SPEC \
+ $defined_EQU_SPEC] $const_name] != -1} {
+ return 1
+ }
+ return 0
+ }
+
+ ## Change selected data memory segment
+ # --auxiliary procedure for proc. 'parse_Consts_and_ConditionalCompilation'
+ # @parm String directive - Directive of segment selection
+ # @parm String operator - Operator (should be 'AT')
+ # @parm String line - Code of the current line
+ # @parm Int idx - Current index in the code list
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names in declaration
+ # @return Bool - 0 == Resolved; 1 == Unresolved (discard line); 2 == Unresolved (keep line)
+ proc data_segment_selection {directive operator line idx ignore_undefined} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable selected_segment ;# Current memory segment (one of {cseg bseg dseg iseg xseg})
+ variable segment_pointer ;# Current memory segment pointer
+
+ # Change memory segment
+ set selected_segment $directive
+ if {[regsub {^\.} [string tolower $line] {}] == $directive} {
+ return 0
+ }
+
+ # Check for operator validity
+ if {$operator != {at}} {
+ SyntaxError $lineNum $fileNum [mc "Unknown operator: `%s', should be `%s at <address>', e.g. `%s at X+0FFh'" $operator $directive $directive]
+ return 1
+ }
+
+ # Determinate and evaluate expression
+ regsub {^\.?\w+\s+\w+\s*} $line {} expr
+ set value [ComputeExpr $expr $ignore_undefined]
+ if {$value == {}} {
+ if {$ignore_undefined} {
+ return 2
+ }
+ SyntaxError $lineNum $fileNum [mc "Invalid expression `%s'" $expr]
+ return 1
+ }
+
+ # Determinate maximum value of the segment pointer
+ switch -- $selected_segment {
+ {bseg} {set max 127}
+ {dseg} {set max 255}
+ {iseg} {set max 255}
+ {xseg} {set max 65535}
+ default {
+ return 1
+ CompilationError $lineNum $fileNum "Unknown error 6"
+ }
+ }
+
+ # Check for valid pointer value
+ if {$value > $max} {
+ SyntaxError $lineNum $fileNum [mc "Segment pointer is too high: %s / %s" $value $max]
+ } elseif {$value < 0} {
+ SyntaxError $lineNum $fileNum [mc "Segment pointer cannot be negative: `%s'" $value]
+ } else {
+ set segment_pointer($selected_segment) $value
+ CodeListing::set_addr $idx $value
+ return 0
+ }
+ return 1
+ }
+
+ ## Take care of conditional compilation control directives (IF, ELSE, ENDIF)
+ # --auxiliary procedure for 'parse_Consts_and_ConditionalCompilation'
+ # @parm String directive - Directive
+ # @parm String cond - Expression of the condition
+ # @return void
+ proc If_Else_Endif {directive cond} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable IfElse_map ;# Array: Conditional compilation map ($IfElse_map($level) == $bool)
+ variable IfElse_level ;# Current level of conditional compilation evaluation
+ variable Enable ;# Bool: Compilation enabled (conditional compilation)
+
+ switch -- $directive {
+ {if} {
+ # Missing condition expression
+ if {![string length $cond]} {
+ SyntaxError $lineNum $fileNum [mc "Missing condition"]
+ set cond 1
+ }
+
+ # Evaluate the condition expression
+ set cond [ComputeExpr $cond]
+ if {$cond == {}} {
+ SyntaxError $lineNum $fileNum [mc "Invalid expression `%s'" $cond]
+ set cond 1
+ }
+
+ # Increment counter of nested block level
+ incr IfElse_level
+
+ # Adjust map of conditional compilation map and flag "Enable"
+ set IfElse_map($IfElse_level) $cond
+ if {!$Enable || !$cond} {
+ set Enable 0
+ }
+ }
+ {ifn} { ;# IF Not
+ # Missing condition expression
+ if {![string length $cond]} {
+ SyntaxError $lineNum $fileNum [mc "Missing condition"]
+ set cond 1
+ }
+
+ # Evaluate the condition expression
+ set cond [ComputeExpr $cond]
+ if {$cond == {}} {
+ SyntaxError $lineNum $fileNum [mc "Invalid expression `%s'" $cond]
+ set cond 1
+ }
+
+ # Invert the condition
+ set cond [expr {!$cond}]
+
+ # Increment counter of nested block level
+ incr IfElse_level
+
+ # Adjust map of conditional compilation map and flag "Enable"
+ set IfElse_map($IfElse_level) $cond
+ if {!$Enable || !$cond} {
+ set Enable 0
+ }
+ }
+ {ifdef} { ;# IF DEFined
+ # Remove brackets
+ set cond [string trim $cond {()}]
+
+ # Missing condition expression
+ if {![string length $cond]} {
+ SyntaxError $lineNum $fileNum [mc "Missing condition"]
+ set cond 1
+ }
+
+ # Evaluate the condition expression
+ set cond [isConstAlreadyDefined $cond]
+
+ # Increment counter of nested block level
+ incr IfElse_level
+
+ # Adjust map of conditional compilation map and flag "Enable"
+ set IfElse_map($IfElse_level) $cond
+ if {!$Enable || !$cond} {
+ set Enable 0
+ }
+ }
+ {ifndef} { ;# IF Not DEFined
+ # Remove brackets
+ set cond [string trim $cond {()}]
+
+ # Missing condition expression
+ if {![string length $cond]} {
+ SyntaxError $lineNum $fileNum [mc "Missing condition"]
+ set cond 1
+ }
+
+ # Evaluate the condition expression
+ set cond [expr {![isConstAlreadyDefined $cond]}]
+
+ # Increment counter of nested block level
+ incr IfElse_level
+
+ # Adjust map of conditional compilation map and flag "Enable"
+ set IfElse_map($IfElse_level) $cond
+ if {!$Enable || !$cond} {
+ set Enable 0
+ }
+ }
+ {else} {
+ if {[llength [array names IfElse_map $IfElse_level]] == 0} {
+ SyntaxError $lineNum $fileNum [mc "Unexpected `ELSE'"]
+ } {
+ set IfElse_map($IfElse_level) [expr {!$IfElse_map($IfElse_level)}]
+ set Enable 1
+ for {set i 1} {$i <= $IfElse_level} {incr i} {
+ set Enable [expr {$IfElse_map($i) && $Enable}]
+ }
+ }
+ }
+ {endif} {
+ incr IfElse_level -1 ;# Decrement counter of nested block level
+ set Enable 1
+
+ # End of nested statement
+ if {$IfElse_level >= 0} {
+ for {set i 1} {$i <= $IfElse_level} {incr i} {
+ set Enable [expr {$IfElse_map($i) && $Enable}]
+ }
+
+ # Invalid directive usage
+ } {
+ incr IfElse_level
+ SyntaxError $lineNum $fileNum [mc "Unexpected `ENDIF'"]
+ }
+ }
+ default {
+ CompilationError $lineNum $fileNum "`$directive' is not a if/else/endif directive (procedure: If_Else_Endif)"
+ }
+ }
+ }
+
+ ## Define symbolic name
+ # --auxiliary procedure for 'parse_Consts_and_ConditionalCompilation'
+ # @parm String directive - Definition directive
+ # @parm String line - Line of source code
+ # @parm Int idx - Current index in the code list
+ # @parm Bool ignore_undefined - Ignore undefined symbolic names in declaration
+ # @return Bool - 0 == Resolved; 1 == Unresolved (discard line); 2 == Unresolved (keep line)
+ proc define_const {directive line idx ignore_undefined} {
+ variable const_BIT ;# Array: Bit values -- ($const_BIT($bit_name) == $value)
+ variable const_CODE ;# Array: Constants defined by directive 'CODE'
+ variable const_DATA ;# Array: Constants defined by directive 'DATA'
+ variable const_IDATA ;# Array: Constants defined by directive 'IDATA'
+ variable const_XDATA ;# Array: Constants defined by directive 'XDATA'
+ variable const_SET ;# Array: Constants defined by directive 'CODE'
+ variable const_EQU ;# Array: Constants defined by directive 'EQU'
+
+ variable defined_BIT ;# List of defined bits (directove 'BIT')
+ variable defined_CODE ;# List of constants defined by 'CODE'
+ variable defined_DATA ;# List of constants defined by 'DATA'
+ variable defined_IDATA ;# List of constants defined by 'IDATA'
+ variable defined_XDATA ;# List of constants defined by 'XDATA'
+ variable defined_SET ;# List of variables defined by 'SET'
+ variable defined_EQU ;# List of constants defined by 'EQU'
+
+ variable const_SET_SPEC ;# Array: Special constants defined by directive 'CODE'
+ variable const_EQU_SPEC ;# Array: Special constants defined by directive 'EQU'
+ variable defined_SET_SPEC ;# List of special variables defined by 'SET'
+ variable defined_EQU_SPEC ;# List of special constants defined by 'EQU'
+
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable ErrorAtLine ;# Bool: Error occured on the current line
+
+ # Handle directive "FLAG", which has the same meaning as "BIT"
+ if {$directive == {flag}} {
+ set directive {bit}
+ }
+
+ # Detrminate 1st field and the last (3rd) field
+ if {![regexp {^\s*\w+} $line const]} {
+ set const {} ;# symbolic name
+ } {
+ set const [string tolower [string trim $const]] ;# symbolic name
+ }
+ if {![regsub {^\w+\s+\.?\w+\s+} $line {} value]} {
+ SyntaxError $lineNum $fileNum [mc "Missing expression"]
+ return 1
+ }
+
+ # Check for symbolic name validity
+ if {![regexp {^[a-zA-Z_]\w*$} $const]} {
+ SyntaxError $lineNum $fileNum [mc "Invalid symbolic name: %s" $const]
+ return 1
+ }
+
+ # Does value field contain comma ?
+ if {[string first {,} $value] != -1} {
+ # Is const field an instruction ?
+ if {[lsearch -exact -ascii ${CompilerConsts::AllInstructions} $const] != -1} {
+ # yes -> skip this line
+ if {$ignore_undefined} {
+ return 2
+ } {
+ return 1
+ }
+ } {
+ # no -> remove line & report syntax error
+ SyntaxError $lineNum $fileNum [mc "Invalid expression: `%s'" $value]
+ return 1
+ }
+ }
+
+ # Is the 1st field a label ? (label:)
+ if {[regexp {^\w+:$} $const]} {
+ SyntaxError $lineNum $fileNum [mc "Expected symbol to define, but got label: `%s'" $const]
+ return 1
+ }
+
+ # Check if the 1st field contain only allowed symbols
+ if {![regexp {^[a-zA-Z_]\w*$} $const]} {
+ SyntaxError $lineNum $fileNum [mc "Invalid symbol name: `%s'" $const]
+ return 1
+ }
+
+ # Determinate value of expression
+ set special_value 0
+ if {[regexp {^\w+\.\w+$} $value]} {
+ set value [getBitAddr $value $ignore_undefined]
+ if {$value == {}} {
+ set value 0
+ }
+ } elseif {
+ [lsearch -ascii -exact ${::CompilerConsts::FixedOperands} [string tolower $value]] != -1
+ && ($directive == {equ} || $directive == {set})
+ } then {
+ Notice $lineNum $fileNum [mc "Special value (with no numerical representation) assigned to constant: %s <- %s" [string toupper $const] [string toupper $value]]
+ set special_value 1
+ } else {
+ set value [ComputeExpr $value $ignore_undefined]
+ }
+
+ # Check for value validity
+ if {$value == {}} {
+ if {$ignore_undefined} {
+ return 2
+ }
+ SyntaxError $lineNum $fileNum [mc "Invalid expression `%s'" $value]
+ return 1
+ }
+
+ # Adjust code listing
+ if {$special_value} {
+ CodeListing::set_spec_value $idx $value
+ } {
+ CodeListing::set_value $idx $value
+ }
+ # Define symbolic name
+ switch -- $directive {
+ {bit} {
+ if {[lsearch -exact -ascii $defined_BIT $const] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Trying to overwrite constant: %s" $const]
+ return 1
+ }
+ if {$value > 255} {
+ SyntaxError $lineNum $fileNum [mc "Expression out of range"]
+ return 1
+ }
+ if {[isConstAlreadyDefined $const]} {
+ Warning $lineNum $fileNum [mc "Ambiguous symbol definition: %s" $const]
+ }
+ set const_BIT($const) $value
+ lappend defined_BIT $const
+ }
+ {code} {
+ if {[lsearch -exact -ascii $defined_CODE $const] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Trying to overwrite constant: %s" $const]
+ return 1
+ }
+ if {$value > 0xFFFF} {
+ SyntaxError $lineNum $fileNum [mc "Expression out of range"]
+ return 1
+ } elseif {$value >= ${::Compiler::Settings::code_size}} {
+ Warning $lineNum $fileNum [mc "Exceeding code memory capacity: %s <- %s" $const $value]
+ }
+ if {[isConstAlreadyDefined $const]} {
+ Warning $lineNum $fileNum [mc "Ambiguous symbol definition: %s" $const]
+ }
+ set const_CODE($const) $value
+ lappend defined_CODE $const
+ }
+ {data} {
+ if {
+ ([lsearch -exact -ascii $defined_IDATA $const] != -1)
+ ||
+ ([lsearch -exact -ascii $defined_DATA $const] != -1)
+ } {
+ SyntaxError $lineNum $fileNum [mc "Trying to overwrite constant: %s" $const]
+ return 1
+ }
+ if {$value > 0xFF} {
+ SyntaxError $lineNum $fileNum [mc "Expression out of range"]
+ return 1
+ } elseif {$value >= ${::Compiler::Settings::iram_size}} {
+ Warning $lineNum $fileNum [mc "Exceeding internal data memory capacity: %s <- %s" $const $value]
+ }
+ if {[isConstAlreadyDefined $const]} {
+ Warning $lineNum $fileNum [mc "Ambiguous symbol definition: %s" $const]
+ }
+ set const_DATA($const) $value
+ lappend defined_DATA $const
+ }
+ {idata} {
+ if {
+ ([lsearch -exact -ascii $defined_IDATA $const] != -1)
+ ||
+ ([lsearch -exact -ascii $defined_DATA $const] != -1)
+ } {
+ SyntaxError $lineNum $fileNum [mc "Trying to overwrite constant: %s" $const]
+ return 1
+ }
+ if {$value > 0xFF} {
+ SyntaxError $lineNum $fileNum [mc "Expression out of range"]
+ return 1
+ } elseif {$value >= ${::Compiler::Settings::iram_size}} {
+ Warning $lineNum $fileNum [mc "Exceeding internal data memory capacity: %s <- %s" $const $value]
+ }
+ if {[isConstAlreadyDefined $const]} {
+ Warning $lineNum $fileNum [mc "Ambiguous symbol definition: %s" $const]
+ }
+ set const_IDATA($const) $value
+ lappend defined_IDATA $const
+ }
+ {xdata} {
+ if {[lsearch -exact -ascii $defined_XDATA $const] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Trying to overwrite constant: %s" $const]
+ return 1
+ }
+ if {$value > 0xFFFF} {
+ SyntaxError $lineNum $fileNum [mc "Expression out of range"]
+ } elseif {$value >= ${::Compiler::Settings::xram_size}} {
+ Warning $lineNum $fileNum [mc "Exceeding external data memory capacity: %s <- %s" $const $value]
+ }
+ if {[isConstAlreadyDefined $const]} {
+ Warning $lineNum $fileNum [mc "Ambiguous symbol definition: %s" $const]
+ }
+ set const_XDATA($const) $value
+ lappend defined_XDATA $const
+ }
+ {equ} {
+ if {[lsearch -exact -ascii $defined_EQU $const] != -1 || [lsearch -exact -ascii $defined_EQU_SPEC $const] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Trying to overwrite constant: %s" $const]
+ return 1
+ }
+ if {[lsearch -exact -ascii $defined_SET $const] != -1 || [lsearch -exact -ascii $defined_SET_SPEC $const] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Trying to change variable `%s' with wrong directive (EQU)" $const]
+ set idx [lsearch -exact -ascii $defined_SET $const]
+ if {$idx != -1} {
+ set defined_SET [lreplace $defined_SET $idx $idx]
+ } {
+ set idx [lsearch -exact -ascii $defined_SET_SPEC $const]
+ if {$idx != -1} {
+ set defined_SET_SPEC [lreplace $defined_SET_SPEC $idx $idx]
+ }
+ }
+ return 1
+ }
+ if {[isConstAlreadyDefined $const]} {
+ Warning $lineNum $fileNum [mc "Ambiguous symbol definition: %s" $const]
+ }
+ if {$special_value} {
+ set const_EQU_SPEC($const) [string tolower $value]
+ lappend defined_EQU_SPEC $const
+ } {
+ set const_EQU($const) $value
+ lappend defined_EQU $const
+ }
+ }
+ {set} {
+ # note:
+ # $const_SET($const) == { { line value } ... }
+ #
+ return [define_variable $const $value $special_value]
+ }
+ }
+
+ return 0
+ }
+
+ ## Define variable (directive 'SET')
+ # --auxiliary procedure for 'define_const'
+ # @parm String const - Name of the variable
+ # @parm Int value - Current value of the variable
+ # @parm Bool special_value - Assign special value like (A, AB, R0, etc.)
+ # @return Bool - 0 == Resolved; 1 == Unresolved
+ proc define_variable {const value special_value} {
+ variable defined_EQU ;# List of constants defined by 'EQU'
+ variable defined_SET ;# List of variables defined by 'SET'
+ variable const_SET ;# Array: Constants defined by directive 'CODE'
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ variable const_SET_SPEC ;# Array: Special constants defined by directive 'CODE'
+ variable const_EQU_SPEC ;# Array: Special constants defined by directive 'EQU'
+ variable defined_SET_SPEC ;# List of special variables defined by 'SET'
+ variable defined_EQU_SPEC ;# List of special constants defined by 'EQU'
+
+ # Check if the variable is not already defined as a constant
+ if {[lsearch -exact -ascii $defined_EQU $const] != -1} {
+ SyntaxError $lineNum $fileNum [mc "Trying to overwrite constant: %s" $const]
+ return 1
+ }
+
+ # Set (new) variable value
+ if {[lsearch -exact -ascii $defined_SET $const] != -1} {
+ Notice $lineNum $fileNum [mc "Setting new variable value: %s <- %s" $const $value]
+ } {
+ if {[isConstAlreadyDefined $const]} {
+ Warning $lineNum $fileNum [mc "Ambiguous symbol definition: %s" $const]
+ }
+ if {$special_value} {
+ lappend defined_SET_SPEC $const
+ } {
+ lappend defined_SET $const
+ }
+ }
+ if {$special_value} {
+ lappend const_SET_SPEC($const) [list $lineNum $value]
+ } {
+ lappend const_SET($const) [list $lineNum $value]
+ }
+ return 0
+ }
+
+ # Check if given constant/variable is defined
+ # @parm string const - constant/variable name
+ # @return bool
+ proc const_exists {const} {
+ variable defined_SET ;# List of variables defined by 'SET'
+ variable defined_EQU ;# List of constants defined by 'EQU'
+
+ if {
+ ([lsearch -exact -ascii $defined_SET $const] != -1) ||
+ ([lsearch -exact -ascii $defined_EQU $const] != -1)
+ } {
+ return 1
+ } {
+ return 0
+ }
+ }
+
+ ## Get constant/variable value
+ # @parm list args - {const_name [lineNumber]}
+ # @parm Bool special_value = 0 - Allow special values like (A, AB, R0, etc.)
+ # @return mixed - value or emty string if nothing found
+ proc const_value args {
+ variable defined_SET ;# List of variables defined by 'SET'
+ variable defined_EQU ;# List of constants defined by 'EQU'
+ variable const_SET ;# Array: Constants defined by directive 'CODE'
+ variable const_EQU ;# Array: Constants defined by directive 'EQU'
+
+ variable const_SET_SPEC ;# Array: Special constants defined by directive 'CODE'
+ variable const_EQU_SPEC ;# Array: Special constants defined by directive 'EQU'
+ variable defined_SET_SPEC ;# List of special variables defined by 'SET'
+ variable defined_EQU_SPEC ;# List of special constants defined by 'EQU'
+
+
+ # Determinate name of the constant and line number
+ set const [lindex $args 0]
+ set line [lindex $args 1]
+
+ set special_value [lindex $args 2]
+ if {$special_value != 1} {
+ set special_value 0
+ }
+
+ # Constants defined by directive 'EQU'
+ if {[lsearch -exact -ascii $defined_EQU $const] != -1} {
+ return $const_EQU($const)
+ }
+
+ # Constants defined by directive 'EQU'
+ if {$special_value && [lsearch -exact -ascii $defined_EQU_SPEC $const] != -1} {
+ return $const_EQU_SPEC($const)
+ }
+
+ # Variables defined by directive 'SET'
+ if {$line != {}} {
+ # Know line number ... search
+ if {[lsearch -exact -ascii $defined_SET $const] != -1} {
+ set value {}
+ # Iterate over definitions
+ foreach item $const_SET($const) {
+ if {[lindex $item 0] > $line} {break}
+ set value [lindex $item 1]
+ }
+ return $value
+ }
+ }
+ # Special variables defined by directive 'SET'
+ if {$special_value && $line != {}} {
+ # Know line number ... search
+ if {[lsearch -exact -ascii $defined_SET_SPEC $const] != -1} {
+ set value {}
+ # Iterate over definitions
+ foreach item $const_SET_SPEC($const) {
+ if {[lindex $item 0] > $line} {break}
+ set value [lindex $item 1]
+ }
+ return $value
+ }
+ }
+
+ # Nothing found -> failure
+ return {}
+ }
+
+ ## Compute value of the given expression
+ # @parm String - Expression to evaluate
+ # @parm Bool = 0 - Ignore undefined symbolic names
+ # @parm Int = {} - Current instruction address (for `$' expansion)
+ # @return Int - result or {}
+ proc ComputeExpr args {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable original_expression ;# Auxiliary variable (see proc. 'ComputeExpr')
+ variable tmp ;# General purpose tempotary variable
+ variable ErrorAtLine ;# Bool: Error occured on the current line
+ variable check_sfr_usage ;# Bool: Check for legal usage of SFR and SFB
+ variable avaliable_SFR ;# List: Avaliable SFR and SFB on the target MCU
+
+ variable const_BIT ;# Array: Bit values -- ($const_BIT($bit_name) == $value)
+ variable const_CODE ;# Array: Constants defined by directive 'CODE'
+ variable const_DATA ;# Array: Constants defined by directive 'DATA'
+ variable const_IDATA ;# Array: Constants defined by directive 'IDATA'
+ variable const_XDATA ;# Array: Constants defined by directive 'XDATA'
+ variable const_SET ;# Array: Constants defined by directive 'CODE'
+ variable const_EQU ;# Array: Constants defined by directive 'EQU'
+
+ variable defined_BIT ;# List of defined bits (directove 'BIT')
+ variable defined_CODE ;# List of constants defined by 'CODE'
+ variable defined_DATA ;# List of constants defined by 'DATA'
+ variable defined_IDATA ;# List of constants defined by 'IDATA'
+ variable defined_XDATA ;# List of constants defined by 'XDATA'
+ variable defined_SET ;# List of variables defined by 'SET'
+ variable defined_EQU ;# List of constants defined by 'EQU'
+
+ variable labels ;# Array: Values of defined labels ($labels($label) == $address)
+ variable defined_LABEL ;# List of defined labels
+
+ set ErrorAtLine 0
+
+ # Parse arguments
+ set expression [lindex $args 0]
+ set ignore_undefined [lindex $args 1]
+ set address [lindex $args 2]
+ if {$ignore_undefined == {}} {
+ set ignore_undefined 0
+ }
+
+ # Make backup copy of the original expression
+ set original_expression $expression
+ set expression " $expression "
+
+ # Hide parantesis in strings
+ set expression [replace_in_strings $expression {\(} "\a"]
+ set expression [replace_in_strings $expression {\)} "\b"]
+
+ # Check if parantesis are balanced
+ if {[regexp {[\(\)]} $expression]} {
+ set left_p 0
+ set idx 0
+ while 1 {
+ set idx [string first {(} $expression $idx]
+ if {$idx == -1} {break}
+ incr idx
+ incr left_p
+ }
+ set right_p 0
+ set idx 0
+ while 1 {
+ set idx [string first {)} $expression $idx]
+ if {$idx == -1} {break}
+ incr idx
+ incr right_p
+ }
+
+ if {$right_p != $left_p} {
+ SyntaxError $lineNum $fileNum [mc "Invalid expression - paranthesis are not balanced: `%s'" $original_expression]
+ }
+ }
+
+ ## Operators replacement
+ # symbol operators (like % or >=)
+ foreach ASM_operator {\\=\\= !\\= \\= <> % \\* / \\- \\+ > < >\\= <\\= \\( \\) } \
+ TCL_operator {== != == != % * / - + > < >= <= ( ) } {
+ regsub -all -- $ASM_operator $expression " $TCL_operator " expression
+ }
+ # word operators (like MOD or GE)
+ foreach ASM_oprator {mod xor or and not eq ne gt ge lt le shr shl } \
+ TCL_operator { % \^ | \\& \~ == != > >= < <= >> << } {
+ regsub -all -nocase -- \
+ "\[\\s \]$ASM_oprator\[\\s \]" $expression \
+ " $TCL_operator " expression
+ }
+
+ # operators "HIGH" and "LOW" (case-insensitive)
+ if {
+ ([string first {low} [string tolower $expression]] != -1)
+ ||
+ ([string first {high} [string tolower $expression]] != -1)
+ } {
+ foreach operator {low high} \
+ before {0xFF&int( int(} \
+ after {) )/0x100} \
+ {
+ while 1 {
+ if {![regexp -nocase -- "\\s$operator\\s+((\\w+)|(\\(\[^\\(\\)\]+\\)))" $expression str]} {
+ break
+ }
+ set idx [string first $str $expression]
+ set len [string length $str]
+
+ set str [string replace $str 0 4]
+ set str " (${before} ${str} ${after})"
+ set expression [string replace $expression $idx [expr {$idx + $len - 1}] $str]
+ }
+ }
+ }
+
+ # Unhide parantesis in strings
+ regsub -all "\a" $expression {(} expression
+ regsub -all "\b" $expression {)} expression
+
+ # Split expression into a list
+ set expression [split [string trim $expression]]
+ set tmp {}
+
+ # Convert all numbers to decimal
+ foreach word [replace_in_strings $expression { } "\a"] {
+ if {$word == {}} {continue}
+
+ if {[regexp {^\d\w+$} $word] && ![regexp {^\d+$} $word]} {
+ set base [string index $word end]
+ set word [string range $word 0 {end-1}]
+
+ switch -- [string tolower $base] {
+ {d} {
+ if {![NumSystem::isdec $word]} {
+ SyntaxError $lineNum $fileNum [mc "Invalid numeric value: %s (should be decimal number)" "${word}d"]
+ }
+ }
+ {h} {
+ if {![NumSystem::ishex $word]} {
+ SyntaxError $lineNum $fileNum [mc "Invalid numeric value: %s (should be hexadecimal number)" "${word}h"]
+ } {
+ set word [expr "0x$word"]
+ }
+ }
+ {b} {
+ if {![NumSystem::isbin $word]} {
+ SyntaxError $lineNum $fileNum [mc "Invalid numeric value: %s (should be binary number)" "${word}b"]
+ } {
+ set word [NumSystem::bin2dec $word]
+ }
+ }
+ {o} {
+ if {![NumSystem::isoct $word]} {
+ SyntaxError $lineNum $fileNum [mc "Invalid numeric value: %s (should be octal number)" "${word}o"]
+ } {
+ set word [NumSystem::oct2dec $word]
+ }
+ }
+ {q} {
+ if {![NumSystem::isoct $word]} {
+ SyntaxError $lineNum $fileNum [mc "Invalid numeric value: %s (should be octal number)" "${word}q"]
+ } {
+ set word [NumSystem::oct2dec $word]
+ }
+ }
+ }
+ } {
+ if {[string index $word end] == {'}} {
+ if {[string index $word 0] != {'}} {
+ SyntaxError $lineNum $fileNum [mc "Invalid value: `%s' (should be char)" $word]
+ } {
+ set word [string range $word 1 end-1]
+ regsub -all "\a" $word { } word
+ set word [character2number [subst -nocommands -novariables $word]]
+ }
+ }
+ }
+ lappend tmp $word
+ }
+ set expression $tmp
+ set tmp {}
+
+ # Expand possible constants and variables
+ foreach word $expression {
+ if {$word == {}} {continue}
+ # Current instruction address `$'
+ if {$address != {} && $word == {$}} {
+ set word $address
+ lappend tmp $word
+ continue
+ }
+
+ # Normal symbolic name
+ if {![regexp {^[A-Za-z_].*$} $word]} {
+ lappend tmp $word
+ continue
+ }
+ set word [string tolower $word]
+
+ # Search in SET and EQU
+ if {[const_exists $word]} {
+ CodeListing::symbol_used $word {equset}
+ set word [const_value $word $lineNum]
+
+ # Search in DATA
+ } elseif {[lsearch -exact -ascii $defined_DATA $word] != -1} {
+ if {$check_sfr_usage} {
+ if {
+ [lsearch -ascii -exact $::CompilerConsts::defined_SFR $word] != -1
+ &&
+ [lsearch -ascii -exact $avaliable_SFR $word] == -1
+ } {
+ Warning $lineNum $fileNum [mc "Special function register \"%s\" is not avaliable on the target MCU" [string toupper $word]]
+ }
+ }
+ set word $const_DATA($word)
+
+ # Search in IDATA
+ } elseif {[lsearch -exact -ascii $defined_IDATA $word] != -1} {
+ CodeListing::symbol_used $word {idata}
+ set word $const_IDATA($word)
+
+ # Search in XDATA
+ } elseif {[lsearch -exact -ascii $defined_XDATA $word] != -1} {
+ CodeListing::symbol_used $word {xdata}
+ set word $const_XDATA($word)
+
+ # Search in CODE
+ } elseif {[lsearch -exact -ascii $defined_CODE $word] != -1} {
+ CodeListing::symbol_used $word {code}
+ set word $const_CODE($word)
+
+ # Search in BIT
+ } elseif {[lsearch -exact -ascii $defined_BIT $word] != -1} {
+ if {$check_sfr_usage} {
+ if {
+ [lsearch -ascii -exact $::CompilerConsts::defined_SFRBitArea $word] != -1
+ &&
+ [lsearch -ascii -exact $avaliable_SFR $word] == -1
+ } {
+ Warning $lineNum $fileNum [mc "Special function bit \"%s\" is not avaliable on the target MCU" [string toupper $word]]
+ }
+ }
+ CodeListing::symbol_used $word {bit}
+ set word $const_BIT($word)
+
+ # Search in LABEL
+ } elseif {[lsearch -exact -ascii $defined_LABEL $word] != -1} {
+ CodeListing::symbol_used $word {label}
+ set word $labels($word)
+
+ # Requeted symb. name not fount -> syntax error
+ } else {
+ if {$ignore_undefined} {
+ return {}
+ }
+ SyntaxError $lineNum $fileNum [mc "Undefined symbol name: %s" $word]
+ set word 1
+ }
+
+ lappend tmp $word
+ }
+ set expression $tmp
+ set tmp {}
+
+ # Return empty string if evaluation is incomplete
+ if {$ErrorAtLine} {return {}}
+
+ # Compute expression and return possible result
+ if {[catch {
+ set expression [expr "$expression"]
+ }]} {
+ return {}
+ }
+
+ set tmp [expr {int($expression)}]
+ if {($tmp - $expression) != 0} {
+ Notice $lineNum $fileNum [mc "Floating point value converted to integer value `%s' -> `%s'" $expression $tmp]
+ }
+ set expression $tmp
+
+ set tmp $expression
+ while {$expression < 0} {
+ incr expression 0x10000
+ }
+ while {$expression >= 0x10000} {
+ incr expression -0x10000
+ }
+ if {$tmp != $expression} {
+ Notice $lineNum $fileNum [mc "Overflow `%s' -> `%s'" $tmp $expression]
+ }
+
+ return $expression
+ }
+
+ ## Remove comments and redutant white space
+ # @return void
+ proc trim_code {} {
+ variable asm ;# Resulting precompiled code
+ variable tmp_asm ;# Tempotary auxiliary precompiled code
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+ variable idx ;# Current position in asm list
+
+ # Reset NS variables
+ set tmp_asm {}
+ set tmp_line {}
+ set idx -1
+
+ # Iterate over the code
+ foreach line $asm {
+ incr idx
+
+ # Update after each 25 iterations
+ if {[expr {$idx % 25}] == 0} ${::Compiler::Settings::UPDATE_COMMAND}
+ if {${::Compiler::Settings::ABORT_VARIABLE}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} [mc "Aborted"]
+ free_resources
+ return
+ }
+
+ # Determinate line number and line content
+ set lineNum [lindex $line 0]
+ set fileNum [lindex $line 1]
+ set line [lindex $line 2]
+
+ # Skip empty lines
+ if {[regexp {^\s*$} $line]} {
+ CodeListing::delete_line $idx
+ incr idx -1
+ continue
+ }
+
+ # Remove comment
+ set tmp_line $line
+ while 1 {
+ if {[regexp {'[^']*'} $tmp_line str]} {
+ regsub {'[^']*'} $tmp_line [string repeat {_} [string length $str]] tmp_line
+ } {
+ break
+ }
+ }
+ set semicolon_idx [string first {;} $tmp_line]
+ if {$semicolon_idx == 0} {
+ CodeListing::delete_line $idx
+ incr idx -1
+ continue
+ }
+ if {$semicolon_idx > 0} {
+ incr semicolon_idx -1
+ set line [string range $line 0 $semicolon_idx]
+ }
+
+ # Remove leading and trainling white space
+ regsub {^\s+} $line {} line
+ regsub {\s+$} $line {} line
+
+ lappend tmp_asm [list $lineNum $fileNum $line]
+ }
+
+ # Replace old code with the new one
+ set asm $tmp_asm
+ }
+
+ ## Replace certain character by another character only within strings
+ # For instance replace_in_strings("a 'a a' a", "a", "b") --> "a 'b b' a"
+ # @parm String string - Source string
+ # @parm String search - Character or substring to replace
+ # @parm String replacement - Replacement
+ # @return String - result
+ proc replace_in_strings {string search replacement} {
+ set idx 0
+ while 1 {
+ if {![regexp -start $idx -- {'[^']*'} $string str]} {
+ break
+ }
+
+ set len [string length $str]
+ set idx [string first $str $string $idx]
+ regsub -all $search [string range $str 1 end-1] $replacement str
+ set string [string replace $string $idx [expr {$idx + $len - 1}] "'$str'"]
+ incr idx [expr {[string length $str] + 2}]
+ }
+ return $string
+ }
+
+ ## Convert one logical character to a number
+ # It can translate even characters like `''', `\t', `X'
+ # @parm String value - Character to translate
+ # @return Int - Value
+ proc character2number {value} {
+ variable lineNum ;# Number of the current line
+ variable fileNum ;# Number of the current file
+
+ regsub -all {''} $value {'} value
+ if {[string length $value] == 1} {
+ binary scan $value c value
+ return $value
+ } {
+ if {[string index $value 0] == "\\"} {
+ set value [string range $value 1 end]
+ switch -- $value {
+ {0} {return 0}
+ {a} {return 7}
+ {b} {return 8}
+ {t} {return 9}
+ {n} {return 10}
+ {v} {return 11}
+ {f} {return 12}
+ {r} {return 13}
+ {e} {return 101}
+ default {
+ set next [string index $value 0]
+ if {$next == {x}} {
+ set value [string range $value 1 end]
+ if {[string is xdigit -strict $value]} {
+ return [expr "0x$value"]
+ }
+
+ } elseif {[regexp {^[0-7]+$} $value]} {
+ return [expr "0$value"]
+
+ } elseif {$next == {c}} {
+ set value [string range $value 1 end]
+ if {[string length $value] == 1} {
+ binary scan $value c value
+ return [expr {$value & 0x1F}]
+ }
+ }
+
+ SyntaxError $lineNum $fileNum [mc "Cannot to use string `%s' as a valid value" $value]
+ return {}
+ }
+ }
+ } {
+ SyntaxError $lineNum $fileNum [mc "Cannot to use string `%s' as value" $value]
+ return {}
+ }
+ }
+ }
+
+ ## Report error message -- compilation error (bug in compiler ?)
+ # @parm Int LineNumber - Number of line where the error occured
+ # @parm Int FileNumber - Number of file where the error occured, {} == unknown
+ # @parm String ErrorInfo - Error string
+ # @return void
+ proc CompilationError {LineNumber FileNumber ErrorInfo} {
+ variable included_files ;# List: Unique unsorted list of included files
+ variable working_dir ;# String: Current working directory
+ variable idx ;# Current position in asm list
+ variable error_count ;# Number of errors occured
+
+ # Increment error counter
+ incr error_count
+
+ # Adjust code listing
+ CodeListing::Error $idx $ErrorInfo
+
+ # Report the error
+ if {$FileNumber != {}} {
+ set filename [lindex $included_files $FileNumber]
+ if {![string first $working_dir $filename]} {
+ set filename [string replace $filename 0 [string length $working_dir]]
+ }
+ if {[regexp {\s} $filename]} {
+ set filename "\"$filename\""
+ }
+ set filename [mc " in %s" $filename]
+ } {
+ set filename {}
+ }
+ if {${::Compiler::Settings::WARNING_LEVEL} < 3} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EL}][mc "Compilation error at %s: %s" "$LineNumber$filename" $ErrorInfo]
+ } {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[31;1mCompilation error\033\[m at \033\[31;1;4m%s\033\[m%s: %s" $LineNumber $filename $ErrorInfo]
+ }
+ }
+ }
+
+ ## Report notice
+ # @parm Int LineNumber - Number of line where it occured
+ # @parm Int FileNumber - Number of file where the error occured, {} == unknown
+ # @parm String ErrorInfo - Text of the notice
+ # @return void
+ proc Notice {LineNumber FileNumber ErrorInfo} {
+ variable working_dir ;# String: Current working directory
+ variable included_files ;# List: Unique unsorted list of included files
+
+ if {$FileNumber != {}} {
+ set filename [lindex $included_files $FileNumber]
+ if {![string first $working_dir $filename]} {
+ set filename [string replace $filename 0 [string length $working_dir]]
+ }
+ if {[regexp {\s} $filename]} {
+ set filename "\"$filename\""
+ }
+ set filename [mc " in %s" $filename]
+ } {
+ set filename {}
+ }
+ if {${::Compiler::Settings::WARNING_LEVEL} < 1} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {WL}][mc "Notice at %s: %s" "$LineNumber$filename" $ErrorInfo]
+ } {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[33;1mNotice\033\[m at \033\[33;1;4m%s\033\[m%s: %s" $LineNumber $filename $ErrorInfo]
+ }
+ }
+ }
+
+ ## Report warning message
+ # @parm Int LineNumber - Number of line where it occured
+ # @parm Int FileNumber - Number of file where the error occured, {} == unknown
+ # @parm String ErrorInfo - Text of the warning
+ # @return void
+ proc Warning {LineNumber FileNumber ErrorInfo} {
+ variable working_dir ;# String: Current working directory
+ variable included_files ;# List: Unique unsorted list of included files
+ variable idx ;# Current position in asm list
+ variable warning_count ;# Number of warnings occured
+
+ # Increment warning counter
+ incr warning_count
+
+ # Adjust code listing
+ CodeListing::Warning $idx $ErrorInfo
+
+ # Report the warning
+ if {$FileNumber != {}} {
+ set filename [lindex $included_files $FileNumber]
+ if {![string first $working_dir $filename]} {
+ set filename [string replace $filename 0 [string length $working_dir]]
+ }
+ if {[regexp {\s} $filename]} {
+ set filename "\"$filename\""
+ }
+ set filename [mc " in %s" $filename]
+ } {
+ set filename {}
+ }
+ if {${::Compiler::Settings::WARNING_LEVEL} < 2} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {WL}][mc "Warning at %s: %s" "$LineNumber$filename" $ErrorInfo]
+ } {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[33mWarning\033\[m at \033\[33;4m%s\033\[m%s: %s" $LineNumber $filename $ErrorInfo]
+ }
+ }
+ }
+
+ ## Report error message -- syntax error (badly formated input code)
+ # @parm Int LineNumber - Number of line where the error occured
+ # @parm Int FileNumber - Number of file where the error occured, {} == unknown
+ # @parm String ErrorInfo - Error string
+ # @return void
+ proc SyntaxError {LineNumber FileNumber ErrorInfo} {
+ variable working_dir ;# String: Current working directory
+ variable included_files ;# List: Unique unsorted list of included files
+ variable idx ;# Current position in asm list
+ variable error_count ;# Number of errors occured
+ variable ErrorAtLine ;# Bool: Error occured on the current line
+ variable Error ;# Bool: An error occured during precompilation
+
+ # Adjust NS variable
+ incr error_count
+ set ErrorAtLine 1
+ set Error 1
+
+ # Adjust code listing
+ CodeListing::Error $idx $ErrorInfo
+
+ # Report the error
+ if {$FileNumber != {}} {
+ set filename [lindex $included_files $FileNumber]
+ if {![string first $working_dir $filename]} {
+ set filename [string replace $filename 0 [string length $working_dir]]
+ }
+ if {[regexp {\s} $filename]} {
+ set filename "\"$filename\""
+ }
+ set filename [mc " in %s" $filename]
+ } {
+ set filename {}
+ }
+ if {${::Compiler::Settings::WARNING_LEVEL} < 3} {
+ if {${::Compiler::Settings::NOCOLOR}} {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [::Compiler::msgc {EL}][mc "Syntax error at %s: %s" "$LineNumber$filename" $ErrorInfo]
+ } {
+ ${::Compiler::Settings::TEXT_OUPUT_COMMAND} \
+ [mc "\033\[31;1mSyntax error\033\[m at \033\[31;1;4m%s\033\[m%s: %s" $LineNumber $filename $ErrorInfo]
+ }
+ }
+ }
+}
diff --git a/lib/configdialogs/compiler_config.tcl b/lib/configdialogs/compiler_config.tcl
new file mode 100755
index 0000000..87df5e7
--- /dev/null
+++ b/lib/configdialogs/compiler_config.tcl
@@ -0,0 +1,1875 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements compilers configuration dialog
+# --------------------------------------------------------------------------
+
+namespace eval compiler {
+
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened 0 ;# Bool: True if this dialog is already opened
+ variable conf_affected ;# Array of Bool: Affected parts of configuration
+
+ # List of default settings
+ variable defaults {
+ {_symbols 0}
+ {_print 0}
+ {_object 0}
+
+ {_nomod 0}
+ {_paging 0}
+ {_pagelength 0}
+ {_pagewidth 0}
+ {_title 0}
+ {_date 0}
+ {_list 0}
+
+ {CREATE_SIM_FILE 1}
+ {CREATE_BIN_FILE 1}
+ {QUIET 0}
+ {optim_ena 0}
+ }
+
+ # Option variables
+ variable option__symbols ;# Table of symbols (in *.lst)
+ variable option__print ;# Generate code listing
+ variable option__object ;# Generate object code (ihex8)
+ variable option__nomod ;# Ignore controls: $NOMOD
+ variable option__paging ;# Ignore controls: $PAGING, $NOPAGING
+ variable option__pagelength ;# Ignore controls: $PAGELENGTH
+ variable option__pagewidth ;# Ignore controls: $PAGEWIDTH
+ variable option__title ;# Ignore controls: $TITLE
+ variable option__date ;# Ignore controls: $DATE
+ variable option__list ;# Ignore controls: $LIST, $NOLIST, LIST, NOLIST
+ variable option_CREATE_SIM_FILE ;# Generate code for simulator
+ variable option_CREATE_BIN_FILE ;# Generate binary object code
+ variable option_QUIET ;# Verbose
+ variable opt_WARNING_LEVEL ;# Warning level
+ variable option_optim_ena ;# Enable optimalizations
+ variable max_ihex_rec_length ;# Int: Maximum length of IHEX-8 record
+
+ variable primary_tab_asm ;# Widget: Tab "Assembly language"
+ variable primary_tab_c ;# Widget: Tab "C language"
+ variable assembler_tab_compiler ;# Widget: Tab "Compiler"
+ variable assembler_tab_M8I ;# Widget: Tab "MCU8051IDE"
+ variable assembler_tab_ASEM51 ;# Widget: Tab "ASEM-51"
+ variable assembler_tab_ASL ;# Widget: Tab "ASL"
+ variable assembler_tab_AS31 ;# Widget: Tab "AS31"
+ variable tertialy_tab_General ;# Widget: Tab "MAIN/C language/General"
+ variable tertialy_tab_Code ;# Widget: Tab "MAIN/C language/Code generation"
+ variable tertialy_tab_Optim ;# Widget: Tab "MAIN/C language/Optimization"
+ variable tertialy_tab_Linker ;# Widget: Tab "MAIN/C language/Linker"
+ variable tertialy_tab_Custom ;# Widget: Tab "MAIN/C language/Custom"
+ variable sdcc_custom_opts_text ;# Widget: Text widget "Custom options for SDCC"
+ variable asm51_custom_opts_text ;# Widget: Text widget "Custom options for ASEM-51"
+ variable asl_custom_opts_text ;# Widget: Text widget "Custom options for ASL"
+ variable as31_custom_opts_text ;# Widget: Text widget "Custom options for AS31"
+
+ # External assembler configuration
+ variable selected_assembler ;# Int: Preffered assembler (0==MCU8051IDE;1==ASEM-51;2==ASL;3==AS31)
+ variable assembler_ASEM51_config;# Array: ASEM-51 configuration
+ variable assembler_ASEM51_addcfg;# Array: ASEM-51 additional configuration
+ variable assembler_ASL_config ;# Array: ASL configuration
+ variable assembler_ASL_addcfg ;# Array: ASL additional configuration
+ variable assembler_AS31_config ;# Array: AS31 configuration
+ variable assembler_AS31_addcfg ;# Array: AS31 additional configuration
+
+ # SDCC Configuration
+ variable sdcc_bool_opt ;# Array: SDCC configuration
+ variable sdcc_str_opt ;# Array: SDCC configuration
+ variable sdcc_opt_str_opt ;# Array: SDCC configuration
+ variable sdcc_scs_str_opt ;# Array: SDCC configuration
+
+
+ ## Create the dialog
+ # @return void
+ proc mkDialog {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+ variable conf_affected ;# Array of Bool: Affected parts of configuration
+
+ variable primary_tab_asm ;# Widget: Tab "MAIN/Assembly language"
+ variable primary_tab_c ;# Widget: Tab "MAIN/C language"
+ variable assembler_tab_compiler ;# Widget: Tab "Assembly language/Compiler"
+ variable assembler_tab_M8I ;# Widget: Tab "MCU8051IDE"
+ variable assembler_tab_ASEM51 ;# Widget: Tab "ASEM-51"
+ variable assembler_tab_ASL ;# Widget: Tab "ASL"
+ variable assembler_tab_AS31 ;# Widget: Tab "AS31"
+
+ variable sdcc_custom_opts_text ;# Widget: Text widget "Custom options for SDCC"
+ variable asm51_custom_opts_text ;# Widget: Text widget "Custom options for ASEM-51"
+ variable asl_custom_opts_text ;# Widget: Text widget "Custom options for ASL"
+ variable as31_custom_opts_text ;# Widget: Text widget "Custom options for AS31"
+
+ set sdcc_custom_opts_text {}
+ set asm51_custom_opts_text {}
+ set asl_custom_opts_text {}
+ set as31_custom_opts_text {}
+
+
+ # Destroy the dialog if it's alredy opened
+ if {$dialog_opened} {
+ destroy .compiler_config_dialog
+ }
+ set dialog_opened 1
+
+ # Initialize array conf_affected
+ foreach key {
+ MCU8051IDE ASEM51 ASL
+ SDCC_Custom SDCC_Linker SDCC_Optimization
+ SDCC_Code SDCC_General Compiler
+ AS31
+ } {
+ set conf_affected($key) 0
+ }
+
+ # Get settings from Compiler NS
+ getSettings
+
+ # Create toplevel window
+ set win [toplevel .compiler_config_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ label $win.header_label \
+ -compound left \
+ -image ::ICONS::32::exec \
+ -text [mc "Compiler configuration"] \
+ -font [font create \
+ -size -20]
+
+ # Create primary notebook and its tabs
+ set primaryNB [ttk::notebook $win.nb]
+ set ::configDialogs::compiler::create_C_tab__already_done 0
+ bind $primaryNB <<NotebookTabChanged>> {after idle {
+ set tab_index [%W index [%W select]]
+
+ if {!$::MICROSOFT_WINDOWS} {
+ if {!${::configDialogs::compiler::create_C_tab__already_done}} {
+ set ::configDialogs::compiler::create_C_tab__already_done 1
+ ::configDialogs::compiler::create_C_tab
+ }
+ }
+ }}
+
+ set primary_tab_asm [frame $primaryNB.primary_tab_asm]
+ $primaryNB add $primary_tab_asm \
+ -text [mc "Assembly language"] \
+ -image ::ICONS::16::asm \
+ -compound left
+
+ if {!$::MICROSOFT_WINDOWS} {
+ set primary_tab_c [frame $primaryNB.primary_tab_c]
+ $primaryNB add $primary_tab_c \
+ -text [mc "C language -- SDCC"] \
+ -image ::ICONS::16::source_c \
+ -compound left
+ }
+
+
+ # Create notebook "Assembly language" and its pages
+ set secondaryNB [ttk::notebook $primary_tab_asm.secondaryNB]
+ set ::configDialogs::compiler::secondaryNB__tabs_created [list]
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no support for external assembler on Microsoft Windows
+ bind $secondaryNB <<NotebookTabChanged>> {after idle {
+ set tab_index [%W index [%W select]]
+ if {[lsearch ${::configDialogs::compiler::secondaryNB__tabs_created} $tab_index] == -1} {
+ lappend ::configDialogs::compiler::secondaryNB__tabs_created $tab_index
+ switch -- $tab_index {
+ 0 {::configDialogs::compiler::create_compiler_tab}
+ 1 {::configDialogs::compiler::create_asm_tab}
+ 2 {::configDialogs::compiler::create_ASEM51_tab}
+ 3 {::configDialogs::compiler::create_ASL_tab}
+ 4 {::configDialogs::compiler::create_AS31_tab}
+ }
+ }
+ }}
+ }
+
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no support for external assembler on Microsoft Windows
+ set assembler_tab_compiler [frame $secondaryNB.assembler_tab_compiler]
+ $secondaryNB add $assembler_tab_compiler\
+ -text [mc "Compiler"]
+ }
+ set assembler_tab_M8I [frame $secondaryNB.assembler_tab_M8I]
+ $secondaryNB add $assembler_tab_M8I \
+ -text "MCU8051IDE"
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no support for external assembler on Microsoft Windows
+ set assembler_tab_ASEM51 [frame $secondaryNB.assembler_tab_ASEM51]
+ $secondaryNB add $assembler_tab_ASEM51 \
+ -text "ASEM-51"
+ set assembler_tab_ASL [frame $secondaryNB.assembler_tab_ASL]
+ $secondaryNB add $assembler_tab_ASL \
+ -text "ASL"
+ set assembler_tab_AS31 [frame $secondaryNB.assembler_tab_AS31]
+ $secondaryNB add $assembler_tab_AS31 \
+ -text "AS31"
+ }
+ pack $secondaryNB -fill both -expand 1
+
+ # Raise pages in notebooks
+ $primaryNB select $primary_tab_asm
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no support for external assembler on Microsoft Windows
+ $secondaryNB select $assembler_tab_compiler
+ } {
+ ::configDialogs::compiler::create_asm_tab
+ $secondaryNB select $assembler_tab_M8I
+ }
+
+ ## Button frame at the bottom
+ set but_frame [frame $win.button_frame]
+ # Button "Reset"
+ pack [ttk::button $but_frame.but_default \
+ -text [mc "Reset to defaults"] \
+ -command {::configDialogs::compiler::DEFAULTS} \
+
+ ] -side left
+ DynamicHelp::add $but_frame.but_default \
+ -text [mc "Reset all settings to defaults"]
+ # Button "Ok"
+ pack [ttk::button $but_frame.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::compiler::OK} \
+ ] -side right
+ DynamicHelp::add $but_frame.but_ok \
+ -text [mc "Commit new settings"]
+ # Button "Cancel"
+ pack [ttk::button $but_frame.but_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::configDialogs::compiler::CANCEL} \
+ ] -side right
+ DynamicHelp::add $but_frame.but_cancel \
+ -text [mc "Take changes back and close dialog"]
+
+ # Pack frames and notebook
+ pack $but_frame -side bottom -fill x -anchor s -padx 5 -pady 5
+ pack $win.header_label -side top -pady 6
+ pack $primaryNB -side top -fill both -padx 5
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::configure
+ wm transient $win .
+ wm title $win [mc "Configure compiler - %s" ${::APPNAME}]
+ wm geometry $win 450x460
+ wm resizable $win 0 0
+ raise $win
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW {
+ ::configDialogs::compiler::CANCEL
+ }
+ tkwait window $win
+ }
+
+ ## Create tab "C language"
+ # @return void
+ proc create_C_tab {} {
+ variable primary_tab_c ;# Widget: Tab "MAIN/C language"
+ variable tertialy_tab_General ;# Widget: Tab "MAIN/C language/General"
+ variable tertialy_tab_Code ;# Widget: Tab "MAIN/C language/Code generation"
+ variable tertialy_tab_Optim ;# Widget: Tab "MAIN/C language/Optimization"
+ variable tertialy_tab_Linker ;# Widget: Tab "MAIN/C language/Linker"
+ variable tertialy_tab_Custom ;# Widget: Tab "MAIN/C language/Custom"
+
+ # Create notebook
+ set tertialyNB [ttk::notebook $primary_tab_c.nb]
+ set ::configDialogs::compiler::tertialyNB__tabs_created [list]
+ bind $tertialyNB <<NotebookTabChanged>> {after idle {
+ set tab_index [%W index [%W select]]
+
+ if {[lsearch ${::configDialogs::compiler::tertialyNB__tabs_created} $tab_index] == -1} {
+ lappend ::configDialogs::compiler::tertialyNB__tabs_created $tab_index
+
+ configDialogs::compiler::create_T_tab \
+ [lindex [list {General} {Code} {Optimization} {Linker} {Custom}] $tab_index]
+ }
+ }}
+
+ # Create notebook tabs
+ foreach tab {
+ General Code
+ Optimization Linker
+ Custom
+ } var {
+ General Code
+ Optim Linker
+ Custom
+ } text {
+ General {Code generation}
+ Optimization Linker
+ Custom
+ } \
+ {
+ set frame [frame $tertialyNB.frame_${tab}]
+ set tertialy_tab_$var $frame
+ $tertialyNB add $frame -text [mc $text]
+ }
+
+ # Finalize
+ $tertialyNB select $tertialyNB.frame_General
+ pack $tertialyNB -fill both -expand 1
+ }
+
+ ## Create certain tab in notebook "C language"
+ # @parm String tab - Tab name
+ # @return void
+ proc create_T_tab {tab} {
+ variable tertialy_tab_General ;# Widget: Tab "MAIN/C language/General"
+ variable tertialy_tab_Code ;# Widget: Tab "MAIN/C language/Code generation"
+ variable tertialy_tab_Optim ;# Widget: Tab "MAIN/C language/Optimization"
+ variable tertialy_tab_Linker ;# Widget: Tab "MAIN/C language/Linker"
+ variable tertialy_tab_Custom ;# Widget: Tab "MAIN/C language/Custom"
+ variable sdcc_custom_opts_text ;# Widget: Text widget "Custom options for SDCC"
+ variable conf_affected ;# Array of Bool: Affected parts of configuration
+ variable sdcc_str_opt ;# Array: SDCC configuration
+
+ set row 0
+ switch -- $tab {
+ {General} {
+ set conf_affected(SDCC_General) 1
+ set frame $tertialy_tab_General
+ set names {
+ --verbose -V
+ -S --compile-only
+ --preprocessonly --c1mode
+ --print-search-dirs --use-stdout
+ --nostdlib --nostdinc
+ --less-pedantic --debug
+ --cyclomatic --fdollars-in-identifiers
+ --funsigned-char
+ }
+ set helptexts {
+ {Trace calls to the preprocessor, assembler and linker}
+ {Execute verbosely. Show sub commands as they are run}
+ {Compile only; do not assemble or link}
+ {Compile and assemble, but do not link}
+ {Preprocess only, do not compile}
+ {Act in c1 mode. The standard input is preprocessed code, the output is assembly code.}
+ {Display the directories in the compiler's search path}
+ {Send errors to stdout instead of stderr}
+ {Do not include the standard library directory in the search path}
+ {Do not include the standard include directory in the search path}
+ {Disable some of the more pedantic warnings}
+ {Enable debugging symbol output}
+ {Display complexity of compiled functions}
+ {Permit '$' as an identifier character}
+ {Make "char" unsigned by default}
+ }
+
+ set local_frame [frame $frame.local_frame_0]
+ pack $local_frame -side top -anchor w
+ grid columnconfigure $local_frame 0 -minsize 25
+ grid columnconfigure $local_frame 3 -minsize 20
+ grid [label $local_frame.c_standard -text [mc "Standard:"]] \
+ -columnspan 6 -column 0 -row 0 -sticky w
+
+ set local_row 1
+ set col 1
+ foreach name {
+ {--std-c89} {--std-sdcc89}
+ {--std-c99} {--std-sdcc99}
+ } helptext {
+ {Use C89 standard only}
+ {Use C89 standard with SDCC extensions}
+ {Use C99 standard only (incomplete)}
+ {Use C99 standard with SDCC extensions (incomplete)}
+ } \
+ {
+ grid [radiobutton $local_frame.chb_${local_row}_$col \
+ -value $name -text $name \
+ -variable ::configDialogs::compiler::sdcc_str_opt(standard) \
+ ] -column $col -row $local_row -sticky w
+ DynamicHelp::add $local_frame.chb_${local_row}_$col -text [mc $helptext]
+ incr col
+
+ if {$col >= 3} {
+ set col 1
+ incr local_row
+ }
+ }
+
+ pack [ttk::separator $frame.sep_0 -orient horizontal] -fill x -pady 5
+
+ set local_row 0
+ set local_frame [frame $frame.local_frame_1]
+ pack $local_frame -side top -fill x
+
+ grid [Label $local_frame.lbl_$local_row -anchor w \
+ -text {Include path} \
+ -helptext [mc "Add to the include path, as in -Ipath\nPaths are separated by semicolons (`;')"] \
+ ] -column 0 -row $local_row -sticky w
+ grid [ttk::entry $local_frame.chb_$local_row \
+ -width 0 \
+ -textvariable ::configDialogs::compiler::sdcc_scs_str_opt(-I) \
+ ] -column 1 -row $local_row -sticky we
+ DynamicHelp::add $local_frame.chb_$local_row \
+ -text [mc "Add to the include (*.h) path, as in -Ipath\nPaths are separated by semicolons (`;')"]
+ incr local_row
+
+ grid [Label $local_frame.lbl_$local_row -anchor w \
+ -text {Disable warning} \
+ -helptext [mc "Disable specific warning (--disable-warning)\nNumbers are separated by semicolons (`;')"] \
+ ] -column 0 -row $local_row -sticky w
+ grid [ttk::entry $local_frame.chb_$local_row \
+ -width 0 \
+ -textvariable ::configDialogs::compiler::sdcc_scs_str_opt(--disable-warning) \
+ ] -column 1 -row $local_row -sticky we
+ DynamicHelp::add $local_frame.chb_$local_row -text [mc "Disable specific warning (--disable-warning)\nNumbers are separated by semicolons (`;')"] \
+ incr local_row
+
+ grid columnconfigure $local_frame 1 -weight 1
+ pack [ttk::separator $frame.sep_1 -orient horizontal] -fill x -pady 5
+ }
+ {Code} {
+ set conf_affected(SDCC_Code) 1
+ set frame $tertialy_tab_Code
+ set names {
+ --xstack --int-long-reent
+ --float-reent --main-return
+ --xram-movc --profile
+ --fommit-frame-pointer --all-callee-saves
+ --stack-probe --parms-in-bank1
+ --no-xinit-opt --no-c-code-in-asm
+ --no-peep-comments --fverbose-asm
+ --short-is-8bits --stack-auto
+ }
+ set helptexts {
+ {Use external stack}
+ {Use reenterant calls on the int and long support functions}
+ {Use reenterant calls on the float support functions}
+ {Issue a return after main()}
+ {Use movc instead of movx to read xram (xdata)}
+ {On supported ports, generate extra profiling information}
+ {Leave out the frame pointer.}
+ {Callee will always save registers used}
+ {Insert call to function __stack_probe at each function prologue}
+ {Use Bank1 for parameter passing}
+ {Don't memcpy initialized xram from code}
+ {Don't include c-code as comments in the asm file}
+ {Don't include peephole optimizer comments}
+ {Include code generator comments}
+ {Make short 8 bits (for old times sake)}
+ {Stack automatic variables}
+ }
+
+ set local_frame [frame $frame.local_frame_0]
+ pack $local_frame -side top -anchor w
+ grid columnconfigure $local_frame 0 -minsize 25
+ grid columnconfigure $local_frame 3 -minsize 20
+ grid [label $local_frame.c_standard -text [mc "Model:"]] \
+ -columnspan 6 -column 0 -row 0 -sticky w
+
+ set local_row 1
+ set col 1
+ foreach name {
+ {--model-large}
+ {--model-medium}
+ {--model-small}
+ } helptext {
+ {External data space is used}
+ {External paged data space is used}
+ {Internal data space is used}
+ } \
+ {
+ grid [radiobutton $local_frame.chb_${local_row}_$col \
+ -value $name -text $name \
+ -variable ::configDialogs::compiler::sdcc_str_opt(model) \
+ ] -column $col -row $local_row -sticky w
+ DynamicHelp::add $local_frame.chb_${local_row}_$col -text $helptext
+ incr col
+
+ if {$col >= 3} {
+ set col 1
+ incr local_row
+ }
+ }
+
+ pack [ttk::separator $frame.sep_0 -orient horizontal] -fill x -pady 5
+
+ set local_row 0
+ set local_frame [frame $frame.local_frame_1]
+ pack $local_frame -side top -fill x
+
+ grid [Label $local_frame.lbl_$local_row -anchor w \
+ -text {--codeseg} \
+ -helptext [mc "Use this name for the code segment"] \
+ ] -column 0 -row $local_row -sticky w
+ grid [ttk::entry $local_frame.chb_$local_row \
+ -width 0 \
+ -textvariable ::configDialogs::compiler::sdcc_opt_str_opt(--codeseg) \
+ ] -column 1 -row $local_row -sticky we
+ DynamicHelp::add $local_frame.chb_$local_row \
+ -text [mc "Use this name for the code segment"]
+ incr local_row
+
+ grid [Label $local_frame.lbl_$local_row -anchor w \
+ -text {--constseg} \
+ -helptext [mc "Use this name for the const segment"] \
+ ] -column 0 -row $local_row -sticky w
+ grid [ttk::entry $local_frame.chb_$local_row \
+ -width 0 \
+ -textvariable ::configDialogs::compiler::sdcc_opt_str_opt(--constseg) \
+ ] -column 1 -row $local_row -sticky we
+ DynamicHelp::add $local_frame.chb_$local_row -text [mc "Use this name for the const segment"] \
+ incr local_row
+
+ grid columnconfigure $local_frame 1 -weight 1
+ pack [ttk::separator $frame.sep_1 -orient horizontal] -fill x -pady 5
+ }
+ {Optimization} {
+ set conf_affected(SDCC_Optimization) 1
+ set frame $tertialy_tab_Optim
+ set names {
+ --nooverlay --nogcse
+ --nolabelopt --noinvariant
+ --noinduction --nojtbound
+ --noloopreverse --no-peep
+ --no-reg-params --peep-asm
+ --opt-code-speed --opt-code-size
+ }
+ set helptexts {
+ {Disable overlaying leaf function auto variables}
+ {Disable the GCSE optimisation}
+ {Disable label optimisation}
+ {Disable optimisation of invariants}
+ {Disable loop variable induction}
+ {Don't generate boundary check for jump tables}
+ {Disable the loop reverse optimisation}
+ {Disable the peephole assembly file optimisation}
+ {On some ports, disable passing some parameters in registers}
+ {Enable peephole optimization on inline assembly}
+ {Optimize for code speed rather than size}
+ {Optimize for code size rather than speed}
+ }
+ }
+ {Linker} {
+ set conf_affected(SDCC_Linker) 1
+ set frame $tertialy_tab_Linker
+ set names {
+ --out-fmt-ihx --out-fmt-s19
+ }
+ set helptexts {
+ {Output in Intel hex format}
+ {Output in S19 hex format}
+ }
+
+ set local_row 0
+ set local_frame [frame $frame.local_frame_1]
+ pack $local_frame -side top -fill x
+ grid columnconfigure $local_frame 1 -weight 1
+ foreach name {
+ -l -L
+ } helptext {
+ {Include the given library in the link\nPaths are separated by semicolons (`;')}
+ {Add the next field to the library search path\nPaths are separated by semicolons (`;')}
+ } \
+ {
+ grid [Label $local_frame.lbl_$local_row -anchor w \
+ -text $name -helptext [subst $helptext] \
+ ] -column 0 -row $local_row -sticky w
+ grid [ttk::entry $local_frame.chb_$local_row \
+ -width 0 \
+ -textvariable ::configDialogs::compiler::sdcc_scs_str_opt($name) \
+ ] -column 1 -row $local_row -sticky we
+ DynamicHelp::add $local_frame.chb_$local_row \
+ -text [subst $helptext]
+ incr local_row
+ }
+ foreach name {
+ --lib-path --xram-loc
+ --xstack-loc --code-loc
+ --stack-loc --data-loc
+ --stack-size
+ } helptext {
+ {Use this path to search for libraries}
+ {External Ram start location}
+ {External Stack start location}
+ {Code Segment Location}
+ {Stack pointer initial value}
+ {Direct data start location}
+ {Tells the linker to allocate this space for stack}
+ } \
+ {
+ grid [Label $local_frame.lbl_$local_row -anchor w \
+ -text $name -helptext $helptext \
+ ] -column 0 -row $local_row -sticky w
+ grid [ttk::entry $local_frame.chb_$local_row \
+ -width 0 \
+ -textvariable ::configDialogs::compiler::sdcc_opt_str_opt($name) \
+ ] -column 1 -row $local_row -sticky we
+ DynamicHelp::add $local_frame.chb_$local_row -text $helptext
+ incr local_row
+ }
+
+ pack [ttk::separator $frame.sep_0 -orient horizontal] -fill x -pady 5
+ set local_frame [frame $frame.local_frame_0]
+ pack $local_frame -side top -anchor w
+ grid columnconfigure $local_frame 0 -minsize 25
+ pack [ttk::separator $frame.sep_1 -orient horizontal] -fill x -pady 5
+ grid [label $local_frame.c_standard -text [mc "Stack:"]] \
+ -columnspan 3 -column 0 -row 0 -sticky w
+
+ set local_row 1
+ foreach name {
+ --pack-iram --no-pack-iram
+ } helptext {
+ {Tells the linker to pack variables in internal ram}
+ {Tells the linker not to pack variables in internal ram}
+ } \
+ {
+ grid [radiobutton $local_frame.chb_${local_row} \
+ -value $name -text $name \
+ -variable ::configDialogs::compiler::sdcc_str_opt(stack) \
+ ] -column 1 -row $local_row -sticky w
+ DynamicHelp::add $local_frame.chb_${local_row} -text $helptext
+
+ incr local_row
+ }
+ }
+ {Custom} {
+ set conf_affected(SDCC_Custom) 1
+ set frame $tertialy_tab_Custom
+ }
+ }
+
+ set main_frame [frame $frame.frame]
+ if {$tab == {Custom}} {
+ set sdcc_custom_opts_text [text $main_frame.text \
+ -bg white -width 0 -height 0 -wrap word \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ ]
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$main_frame.text yview" \
+ ] -side right -fill y
+ pack $sdcc_custom_opts_text -fill both -expand 1 -side left
+ $sdcc_custom_opts_text insert end $sdcc_str_opt(custom)
+
+ pack $main_frame -side top -fill both -expand 1
+ } {
+ set col 0
+ foreach name $names helptext $helptexts {
+ grid [checkbutton $main_frame.chb_${row}_$col \
+ -text $name -onvalue 1 -offvalue 0 \
+ -variable ::configDialogs::compiler::sdcc_bool_opt($name) \
+ ] -column $col -row $row -sticky w
+ DynamicHelp::add $main_frame.chb_${row}_$col -text [mc $helptext]
+ incr col
+
+ if {$col >= 2} {
+ set col 0
+ incr row
+ }
+ }
+ grid columnconfigure $main_frame 0 -weight 1
+ pack $main_frame -side top -fill x
+ }
+ }
+
+ ## Create tab "Compiler"
+ # @return void
+ proc create_compiler_tab {} {
+ variable assembler_tab_compiler ;# Widget: Tab "Compiler"
+ variable conf_affected ;# Array of Bool: Affected parts of configuration
+
+ set conf_affected(Compiler) 1
+ set main_frame [frame $assembler_tab_compiler.frame]
+ # Preferred editor
+ grid [label $main_frame.editor_lbl \
+ -text [mc "Preferred assemler:"] -anchor w \
+ ] -row 0 -column 0 -sticky w
+ set row 1
+ set i 0
+ foreach text {
+ {MCU 8051 IDE}
+ {ASEM-51}
+ {ASL}
+ {AS31}
+ } helptext {
+ {MCU 8051 IDE native assembler - Sophisticated but slow}
+ {Sophisticated and very fast assembler writen by W.W. Heinz}
+ {Multiplatform assembler written by Alfred Arnold}
+ {Simple 8051 assembler}
+ } {
+ grid [radiobutton $main_frame.rabut_$i \
+ -variable ::configDialogs::compiler::selected_assembler \
+ -value $i -text $text -state disabled \
+ ] -column 0 -padx 25 -row $row -sticky w
+ DynamicHelp::add $main_frame.rabut_$i -text [mc $helptext]
+ incr i
+ incr row
+ }
+ $main_frame.rabut_0 configure -state normal
+ if {${::PROGRAM_AVALIABLE(asem)}} {
+ $main_frame.rabut_1 configure -state normal
+ }
+ if {${::PROGRAM_AVALIABLE(asl)}} {
+ $main_frame.rabut_2 configure -state normal
+ }
+ if {${::PROGRAM_AVALIABLE(as31)}} {
+ $main_frame.rabut_3 configure -state normal
+ }
+
+ grid [ttk::separator $main_frame.sep -orient horizontal] \
+ -row $row -column 0 -sticky we -columnspan 2 -padx 10 -pady 10
+ incr row
+
+ grid [text $main_frame.notes \
+ -bg {#EEEEEE} -bd 0 -highlightthickness 0 -wrap word \
+ -font [font create -family {helvetiva} -size -12] \
+ ] -row $row -column 0 -sticky we -columnspan 2 -padx 10
+
+ $main_frame.notes insert end [mc "Notes to assemblers:\n"]
+ $main_frame.notes insert end [mc " a) MCU 8051 IDE has its own native assembler\n"]
+ $main_frame.notes insert end [mc " b) ASEM-51 is a great assembler written by W.W. Heinz.\n"]
+ $main_frame.notes insert end [mc " You can find it at http://plit.de/asem-51/home.htm\n"]
+ $main_frame.notes insert end [mc " c) ASL: http://linux.maruhn.com/sec/asl.html\n"]
+ $main_frame.notes insert end [mc " d) AS31: http://www.pjrc.com/tech/8051/\n"]
+
+ $main_frame.notes configure -state disabled
+
+ # Configure grid and pack main frame
+ grid columnconfigure $main_frame 0 -minsize 200
+ grid columnconfigure $main_frame 1 -weight 1
+ pack $main_frame -side top -fill x
+ }
+
+ ## Create tab "ASEM51"
+ # @return void
+ proc create_ASEM51_tab {} {
+ variable assembler_tab_ASEM51 ;# Widget: Tab "ASX8051"
+ variable asm51_custom_opts_text ;# Widget: Text widget "Custom options for ASEM-51"
+ variable conf_affected ;# Array of Bool: Affected parts of configuration
+
+ # Set flag "Configuration affected"
+ set conf_affected(ASEM51) 1
+
+ # Create main frame
+ set main_frame [frame $assembler_tab_ASEM51.frame0]
+
+ set i 0
+ foreach name {
+ --omf-51
+ --columns
+ --verbose
+ } helptext {
+ {Generate an object file in absolute OMF-51 format}
+ {Output additional column numbers after the line numbers of program error messages}
+ {Output additional product, version, and error summary information}
+ } \
+ {
+ pack [checkbutton $main_frame.checkbutton_$i \
+ -text $name -onvalue 1 -offvalue 0 \
+ -variable ::configDialogs::compiler::assembler_ASEM51_config($name) \
+ ] -anchor nw
+ DynamicHelp::add $main_frame.checkbutton_$i -text $helptext
+ incr i
+ }
+ pack $main_frame -fill x
+
+ # Additional options
+ set main_frame [frame $assembler_tab_ASEM51.frame_a]
+ set i 0
+ foreach var {
+ adf
+ } text {
+ {Generate MCU 8051 IDE debug file}
+ } helptext {
+ {Generate <file>.adb (MCU 8051 IDE Assembler Debug File) from <file>.lst}
+ } \
+ {
+ set helptext [subst $helptext]
+ pack [checkbutton $main_frame.chb_$i \
+ -text $text -onvalue 1 -offvalue 0 \
+ -variable ::configDialogs::compiler::assembler_ASEM51_addcfg($var) \
+ ] -anchor w
+ DynamicHelp::add $main_frame.chb_$i -text $helptext
+ incr i
+ }
+ pack $main_frame -fill x
+ pack [ttk::separator $assembler_tab_ASEM51.sep_1 -orient horizontal] -fill x -pady 5
+
+ # Create second frame (Include path and custom flags)
+ set main_frame [frame $assembler_tab_ASEM51.frame1]
+ # Include path
+ grid [Label $main_frame.lbl_0 -anchor w \
+ -text [mc "Include paths:"] \
+ -helptext [mc "Option -i\nSeparate directories by colons (`:')"] \
+ ] -column 0 -row 0 -sticky w
+ grid [ttk::entry $main_frame.entry \
+ -textvariable ::configDialogs::compiler::assembler_ASEM51_config(-i) \
+ ] -column 1 -row 0 -sticky we
+ DynamicHelp::add $main_frame.entry \
+ -text [mc "Option -i\nSeparate directories by colons (`:')"]
+ grid [Label $main_frame.lbl_1 \
+ -anchor w \
+ -text [mc "Custom options:"] \
+ ] -column 0 -row 1 -sticky w
+
+ # Configure grid and pack main frame 1
+ grid columnconfigure $main_frame 1 -weight 1
+ pack $main_frame -fill x
+
+ # Text widget "Custom options"
+ set main_frame [frame $assembler_tab_ASEM51.frame2]
+ set asm51_custom_opts_text [text $main_frame.text \
+ -bg white -width 0 -height 0 \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ ]
+ pack $asm51_custom_opts_text -side left -fill both -expand 1
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$asm51_custom_opts_text yview" \
+ ] -side right -fill y
+ $asm51_custom_opts_text insert end \
+ $::configDialogs::compiler::assembler_ASEM51_config(custom)
+ pack $main_frame -fill both -expand 1
+ }
+
+ ## Create tab "AS31"
+ # @return void
+ proc create_AS31_tab {} {
+ variable assembler_tab_AS31 ;# Widget: Tab "AS31"
+ variable as31_custom_opts_text ;# Widget: Text widget "Custom options for AS31"
+ variable conf_affected ;# Array of Bool: Affected parts of configuration
+
+ # Set flag "Configuration affected"
+ set conf_affected(AS31) 1
+
+ # Create main frame
+ set main_frame [frame $assembler_tab_AS31.frame0]
+ set i 0
+ set row 0
+ set col 0
+ foreach name {
+ -l
+ } text {
+ {Generate a listing file, option `-l'}
+ } helptext {
+ {This option tells the assembler to generate a listing file.\n\nTHIS OPTION IS REQUIRED BY THIS IDE TO GENERATE BEBUG FILE !}
+ } \
+ {
+ set helptext [subst $helptext]
+ grid [checkbutton $main_frame.checkbutton_$i \
+ -text [mc $text] -onvalue 1 -offvalue 0 \
+ -variable ::configDialogs::compiler::assembler_AS31_config($name) \
+ ] -sticky w -row $row -column $col
+ DynamicHelp::add $main_frame.checkbutton_$i -text [mc $helptext]
+
+ incr i
+ incr col
+ if {$col > 3} {
+ set col 0
+ incr row
+ }
+ }
+ for {set i 0} {$i < 4} {incr i} {
+ grid columnconfigure $main_frame $i -weight 1
+ }
+ pack $main_frame -fill x
+
+ # Additional options
+ set main_frame [frame $assembler_tab_AS31.frame_a]
+ set i 0
+ foreach var {
+ adf
+ } text {
+ {Generate MCU 8051 IDE debug file}
+ } helptext {
+ {Generate <file>.adb (MCU 8051 IDE Assembler Debug File)\nfrom <file>.lst}
+ } \
+ {
+ set helptext [subst $helptext]
+ pack [checkbutton $main_frame.chb_$i \
+ -text [mc $text] -onvalue 1 -offvalue 0 \
+ -variable ::configDialogs::compiler::assembler_AS31_addcfg($var) \
+ ] -anchor w
+ DynamicHelp::add $main_frame.chb_$i -text [mc $helptext]
+ incr i
+ }
+ pack $main_frame -fill x
+ pack [ttk::separator $assembler_tab_AS31.sep_1 -orient horizontal] -fill x
+
+ # Create second frame (EntryBoxes and ComboBoxes)
+ set main_frame [frame $assembler_tab_AS31.frame1]
+ set row 0
+ foreach name {
+ -F
+ } helptext {
+ {This options specifies the output format that is to be used.\n\nSee AS31 manual page for more datails ...}
+ } values {
+ {hex tdr byte od srec2 srec3 srec4}
+ } \
+ {
+ set helptext [subst $helptext]
+ grid [Label $main_frame.lbl_$row -anchor w \
+ -text $name -helptext [mc $helptext] \
+ ] -column 0 -row $row -sticky w
+ grid [ttk::combobox $main_frame.entry_$row \
+ -state readonly \
+ -values $values \
+ -textvariable ::configDialogs::compiler::assembler_AS31_config($name) \
+ ] -column 1 -row $row -sticky we
+ DynamicHelp::add $main_frame.entry_$row -text [mc $helptext]
+ incr row
+ }
+ foreach name {
+ -A
+ } helptext {
+ {This option specifies a format specific string which is\npassed to the format generator. Both format "tdr" and the\nsrecord formats use this option.}
+ } \
+ {
+ set helptext [subst $helptext]
+ grid [Label $main_frame.lbl_$row -anchor w \
+ -text $name -helptext [mc $helptext] \
+ ] -column 0 -row $row -sticky w
+ grid [ttk::entry $main_frame.entry_$row \
+ -textvariable ::configDialogs::compiler::assembler_AS31_config($name) \
+ ] -column 1 -row $row -sticky we
+ DynamicHelp::add $main_frame.entry_$row \
+ -text [mc $helptext]
+ incr row
+ }
+
+ # Custom flags
+ grid [Label $main_frame.lbl_$row -anchor w \
+ -text [mc "Custom options:"] \
+ ] -column 0 -row $row -sticky w
+
+ # Configure grid and pack main frame 1
+ grid columnconfigure $main_frame 1 -weight 1
+ pack $main_frame -fill x
+
+ # Text widget "Custom options"
+ set main_frame [frame $assembler_tab_AS31.frame2]
+ set as31_custom_opts_text [text $main_frame.text \
+ -bg white -width 0 -height 0 \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ ]
+ pack $as31_custom_opts_text -side left -fill both -expand 1
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$as31_custom_opts_text yview" \
+ ] -side right -fill y
+ $as31_custom_opts_text insert end \
+ $::configDialogs::compiler::assembler_AS31_config(custom)
+ pack $main_frame -fill both -expand 1
+ }
+
+ ## Create tab "ASL"
+ # @return void
+ proc create_ASL_tab {} {
+ variable assembler_tab_ASL ;# Widget: Tab "ASL"
+ variable asl_custom_opts_text ;# Widget: Text widget "Custom options for ASL"
+ variable conf_affected ;# Array of Bool: Affected parts of configuration
+
+ # Set flag "Configuration affected"
+ set conf_affected(ASL) 1
+
+ # Create main frame
+ set main_frame [frame $assembler_tab_ASL.frame0]
+ set i 0
+ set row 0
+ set col 0
+ foreach name {
+ -A -a -C -c -h -I -L -M -P -n -quiet -s -u -U -w -x
+ } helptext {
+ {Change the data structure that is internally used to store\nthe symbol table. By default, AS uses binary trees to store\nmacro and symbol definitions. Turning this option on will\nchange this to AVL-balanced trees. Depending on the ratio\nof symbol entries and lookups, this might speed up assembly.\nUsing AVL-balanced trees helps also reducing the stack usage,\nwhich is however irrelevant for the C version of AS.}
+ {Instruct AS to write out the shared symbol definitions in\na format suitable for including into an AS assembler program.\nThe file's name is constructed by replacing the source file's\nextension with '.inc'. See the user manual for more\ninformation about symbol sharing.}
+ {Add a cross reference table to the assembler listing. A cross\nreference table lists all symbols that have been referenced\nat least once during assembly, including the source line\nnumber(s) and count of every reference. This option only makes\nsense when the generation of an assembly listing has been\nturned on via the -L or -l parameters. }
+ {Instruct AS to write out the shared symbol definitions in a\nformat suitable for including into a C program. The file's\nname is constructed by replacing the source file's extension\nwith '.h'. See the user manual for more information about\nsymbol sharing.}
+ {Force AS to print all hexadecimal constants with lowercase\nletters, rather than with uppercase letters A..F which is\nthe default.}
+ {Add an include file list to the assembly listing. An include\nfile list contains all files that have been included while\nassembling the source files, including multiple and nested\ninclusion. Nesting of inclusion is identified by different\nindention. This option only makes sense when the generation of\nan assembly listing has been turned on via the -L or -l parameters.}
+ {Turn on generation of an assembly listing and send it to a\nfile whose name is constructed by replacing the source\nfile's extension with '.lst'.}
+ {Turn on generation of a macro definition file. A macro\ndefinition file is a file that contains all macro definitions\nthat have been detected during assembly, in a format suitable\nfor an inclusion into another file. The macro definition file's\nname is constructed by replacing the source file's extension\nwith '.mac'.}
+ {Turn on generation of a macro output file. A macro output\nfile contains the intermediate source code that remains after\nmacro expansion and conditional assembly. The macro output\nfile's name is constructed by replacing the source file's\nextension with '.i'.}
+ {Force AS to extend all error and warning messages with their\ninternal error resp. warning number.}
+ {Turn on silent assembly mode. In silent compilation mode, AS\nwill not do any console output except for warning and\nerror messages.}
+ {Add a section list to the assembly listing. A section list\ncontains all sections that have been defined in the source\nfiles, marking their nesting level by different levels of\nindentation. This option only makes sense when the generation\nof an assembly listing has been turned on via the\n-L or -l parameters.}
+ {Tell AS to do additional bookkeeping about which address\nranges have been used by the assembled program. This option\nenables the detection of overlapping memory usage. If an\nassembly listing has been turned on via the -L or -l parameters,\nit will also contain a list of all used memory areas.}
+ {Force AS to operate in case-sensitive mode. By default,\nnames of symbols, macros, user-defined functions and sections\nare treated in a case-insensitive manner.}
+ {Suppress output of warnings.}
+ {Turn on extended error reporting. With extended error\nreporting, several error and warning messages will also\nprint the item that created the message, e.g. the name of\nan unknown instruction. When this option is given twice,\nthe erroneous source line is additinally printed.}
+ } \
+ {
+ set helptext [subst $helptext]
+ grid [checkbutton $main_frame.checkbutton_$i \
+ -text $name -onvalue 1 -offvalue 0 \
+ -variable ::configDialogs::compiler::assembler_ASL_config($name) \
+ ] -sticky w -row $row -column $col
+ DynamicHelp::add $main_frame.checkbutton_$i -text [mc $helptext]
+
+ incr i
+ incr col
+ if {$col > 3} {
+ set col 0
+ incr row
+ }
+ }
+ for {set i 0} {$i < 4} {incr i} {
+ grid columnconfigure $main_frame $i -weight 1
+ }
+ pack $main_frame -fill x
+ pack [ttk::separator $assembler_tab_ASL.sep_0 -orient horizontal] -fill x
+
+ # Additional options
+ set main_frame [frame $assembler_tab_ASL.frame_a]
+ set i 0
+ foreach var {
+ ihex adf
+ } text {
+ {Generate IHEX file}
+ {Generate MCU 8051 IDE debug file}
+ } helptext {
+ {Use program p2hex to convert <file>.p to <file>.hex}
+ {Generate <file>.adb (MCU 8051 IDE Assembler Debug File)\nfrom <file>.hex and <file>.map}
+ } \
+ {
+ set helptext [subst $helptext]
+ pack [checkbutton $main_frame.chb_$i \
+ -text [mc $text] -onvalue 1 -offvalue 0 \
+ -variable ::configDialogs::compiler::assembler_ASL_addcfg($var) \
+ ] -anchor w
+ DynamicHelp::add $main_frame.chb_$i -text [mc $helptext]
+ incr i
+ }
+ pack $main_frame -fill x
+ pack [ttk::separator $assembler_tab_ASL.sep_1 -orient horizontal] -fill x
+
+ # Create second frame (EntryBoxes and ComboBoxes)
+ set main_frame [frame $assembler_tab_ASL.frame1]
+ set row 0
+ foreach name {
+ -cpu -g
+ } helptext {
+ {Set the target processor to <name>.\nUse this option if the source file does\nnot contain a CPU statement.}
+ {-g \[MAP|Atmel|NoICE\]\n\tInstruct AS to write an additional file containing\n\tdebug information. This information covers the symbol\n\ttable and the relation between source line numbers\n\tand machine addresses. The argument specifies whether\n\tdebug info shall be written in AS's own MAP format,\n\tthe object format for Atmel's AVR tools, or a command\n\tfile suitable for John Hartman's NoICE. If no argument\n\tis given, MAP will be chosen. The file's name is\n\tconstructed by replacing the source file's extension\n\twith '.map', '.obj', or '.noi' respectively.\n\nMCU 8051 IDE requires MAP to be selected\nhere to generate debug file}
+ } values {
+ {
+ 8021 8022 8039 80C39 8048 80C48 8041 8042
+ 87C750 8051 8052 80C320 80C501 80C502 80C504 80515
+ 80517 80C251
+ } {
+ {} MAP Atmel NoICE
+ }
+ } \
+ {
+ set helptext [subst $helptext]
+ grid [Label $main_frame.lbl_$row -anchor w \
+ -text $name -helptext [mc $helptext] \
+ ] -column 0 -row $row -sticky w
+ grid [ttk::combobox $main_frame.entry_$row \
+ -state readonly \
+ -values $values \
+ -textvariable ::configDialogs::compiler::assembler_ASL_config($name) \
+ ] -column 1 -row $row -sticky we
+ DynamicHelp::add $main_frame.entry_$row -text [mc $helptext]
+ incr row
+ }
+ foreach name {
+ -r -i
+ } helptext {
+ {-r \[pass number\]\n\tTell AS to output warnings when a situation appears\n\tin a source file that forces another pass of assembly.\n\tSuch situations either take place when a symbol is\n\tundefined in the first pass or a symbol's value has\n\tchanged compared to the previous pass. This option\n\tis useful to track down sources of excessive\n\tmulti-passing, but be aware that it might yield a\n\tfairly large number of warnings, especially in the\n\tfirst pass. Optionally, a pass number may be added\n\tto this option to inhibit output until a certain\n\tpass is reached.}
+ {-i <path\[:path...\]>\tAdd new entries to the list of paths that are\n\tsearched for include files. New entries are\n\tprepended to the current include path list,\n\tso if multiple paths are given with one\n\tcommand-line parameter, they will be entered\n\tinto the path list in reverse order.}
+ } \
+ {
+ set helptext [subst $helptext]
+ grid [Label $main_frame.lbl_$row -anchor w \
+ -text $name -helptext [mc $helptext] \
+ ] -column 0 -row $row -sticky w
+ grid [ttk::entry $main_frame.entry_$row \
+ -textvariable ::configDialogs::compiler::assembler_ASL_config($name) \
+ ] -column 1 -row $row -sticky we
+ DynamicHelp::add $main_frame.entry_$row -text [mc $helptext]
+ incr row
+ }
+
+ # Custom flags
+ grid [Label $main_frame.lbl_$row -anchor w \
+ -text [mc "Custom options:"] \
+ ] -column 0 -row $row -sticky w
+
+ # Configure grid and pack main frame 1
+ grid columnconfigure $main_frame 1 -weight 1
+ pack $main_frame -fill x
+
+ # Text widget "Custom options"
+ set main_frame [frame $assembler_tab_ASL.frame2]
+ set asl_custom_opts_text [text $main_frame.text \
+ -bg white -width 0 -height 0 \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ ]
+ pack $asl_custom_opts_text -side left -fill both -expand 1
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$asl_custom_opts_text yview" \
+ ] -side right -fill y
+ $asl_custom_opts_text insert end \
+ $::configDialogs::compiler::assembler_ASL_config(custom)
+ pack $main_frame -fill both -expand 1
+ }
+
+ ## Create tab "MCU8051IDE"
+ # @return void
+ proc create_asm_tab {} {
+ variable conf_affected ;# Array of Bool: Affected parts of configuration
+ variable assembler_tab_M8I ;# Widget: Tab "MCU8051IDE"
+
+ # Set flag "Configuration affected"
+ set conf_affected(MCU8051IDE) 1
+
+ ## Create notebook
+ set nb0 [ttk::notebook $assembler_tab_M8I.nb]
+
+ # Tab "Output"
+ set ouput_tab [frame $nb0.ouput_tab]
+ $nb0 add $ouput_tab -text [mc "Output"]
+ # Tab "Directives"
+ set directives_tab [frame $nb0.directives_tab]
+ $nb0 add $directives_tab -text [mc "Directives"]
+
+ #
+ ## Tab "Output"
+ #
+
+ # Header
+ grid [Label $ouput_tab.source_label \
+ -text [mc "Source"] -anchor c \
+ -helptext [mc "Use value defined in source code"] \
+ ] -column 2 -row 0 -sticky we
+ grid [Label $ouput_tab.always_label \
+ -text [mc "Always"] -anchor c \
+ -helptext [mc "Generate always"] \
+ ] -column 3 -row 0 -sticky we
+ grid [Label $ouput_tab.never_label \
+ -text [mc "Never"] -anchor c \
+ -helptext [mc "Never generate"] \
+ ] -column 4 -row 0 -sticky we
+
+ # Code listing
+ grid [Label $ouput_tab.lst_label -anchor w \
+ -text [mc "Generate code listing"] \
+ -helptext [mc "Should compiler generate *.lst files"] \
+ ] -column 1 -row 1 -sticky we
+ grid [radiobutton $ouput_tab.lst_radio0 -value 0 \
+ -variable ::configDialogs::compiler::option__print \
+ ] -column 2 -row 1
+ grid [radiobutton $ouput_tab.lst_radio1 -value 1 \
+ -variable ::configDialogs::compiler::option__print \
+ ] -column 3 -row 1
+ grid [radiobutton $ouput_tab.lst_radio2 -value 2 \
+ -variable ::configDialogs::compiler::option__print \
+ ] -column 4 -row 1
+
+ # Table of symbols
+ grid [Label $ouput_tab.sym_label -anchor w \
+ -text [mc "Table of symbols (in *.lst)"] \
+ -helptext [mc "Include table of used symbolic names to code listing"] \
+ ] -column 1 -row 2 -sticky we
+ grid [radiobutton $ouput_tab.sym_radio0 -value 0 \
+ -variable ::configDialogs::compiler::option__symbols \
+ ] -column 2 -row 2
+ grid [radiobutton $ouput_tab.sym_radio1 -value 1 \
+ -variable ::configDialogs::compiler::option__symbols \
+ ] -column 3 -row 2
+ grid [radiobutton $ouput_tab.sym_radio2 -value 2 \
+ -variable ::configDialogs::compiler::option__symbols \
+ ] -column 4 -row 2
+
+ # Hex object code
+ grid [Label $ouput_tab.hex_label -anchor w \
+ -text [mc "Generate object code (ihex8)"] \
+ -helptext [mc "Generate object code in format Intel Hex 8 (*.hex)"] \
+ ] -column 1 -row 3 -sticky we
+ grid [radiobutton $ouput_tab.hex_radio0 -value 0 \
+ -variable ::configDialogs::compiler::option__object \
+ ] -column 2 -row 3
+ grid [radiobutton $ouput_tab.hex_radio1 -value 1 \
+ -variable ::configDialogs::compiler::option__object \
+ ] -column 3 -row 3
+ grid [radiobutton $ouput_tab.hex_radio2 -value 2 \
+ -variable ::configDialogs::compiler::option__object \
+ ] -column 4 -row 3
+
+ grid [ttk::separator $ouput_tab.sep0 \
+ -orient horizontal \
+ ] -column 0 -row 4 -columnspan 5 -sticky we -pady 5
+
+ # Sim object code
+ grid [Label $ouput_tab.sim_label -anchor w \
+ -text [mc "Generate code for simulator"] \
+ -helptext [mc "Generate *.sim file for simulator"] \
+ ] -column 1 -row 5 -sticky we
+ grid [checkbutton $ouput_tab.sim_check \
+ -variable ::configDialogs::compiler::option_CREATE_SIM_FILE \
+ ] -column 2 -row 5 -sticky w -columnspan 3
+
+ # Bin object code
+ grid [Label $ouput_tab.bin_label -anchor w \
+ -text [mc "Generate binary object code"] \
+ -helptext [mc "Generate binary object code (*.bin)"] \
+ ] -column 1 -row 6 -sticky we
+ grid [checkbutton $ouput_tab.bin_check \
+ -variable ::configDialogs::compiler::option_CREATE_BIN_FILE \
+ ] -column 2 -row 6 -sticky w -columnspan 3
+
+ grid [ttk::separator $ouput_tab.sep1 \
+ -orient horizontal \
+ ] -column 0 -row 7 -columnspan 5 -sticky we -pady 5
+
+ # Compier warning level
+ grid [Label $ouput_tab.warning_label -anchor w \
+ -text [mc "Warning level"] \
+ -helptext [mc "What kind of messages should be included in compiler log output"] \
+ ] -column 1 -row 8 -sticky we
+ grid [ttk::combobox $ouput_tab.warning_combo \
+ -textvariable ::configDialogs::compiler::opt_WARNING_LEVEL \
+ -values {
+ {All}
+ {Errors + Warnings}
+ {Errros only}
+ {Nothing}
+ } \
+ -state readonly -width 17 \
+ ] -column 2 -row 8 -sticky w -columnspan 3
+ DynamicHelp::add $ouput_tab.warning_combo \
+ -text [mc "What kind of messages should be included in compiler log output"]
+
+ # Verbose
+ grid [Label $ouput_tab.verbose_label -anchor w \
+ -text [mc "Verbose"] \
+ -helptext [mc "Should compiler inoform user about what it is doing"] \
+ ] -column 1 -row 9 -sticky we
+ grid [checkbutton $ouput_tab.verbose_check \
+ -onvalue 0 -offvalue 1 \
+ -variable ::configDialogs::compiler::option_QUIET \
+ ] -column 2 -row 9 -sticky w -columnspan 3
+
+ grid [ttk::separator $ouput_tab.sep2 \
+ -orient horizontal \
+ ] -column 0 -row 10 -columnspan 5 -sticky we -pady 5
+
+ # Enable optimalizations
+ grid [Label $ouput_tab.optim_label -anchor w \
+ -text [mc "Enable optimalizations"] \
+ -helptext [mc "Enable peephole optimalizations"]\
+ ] -column 1 -row 11 -sticky we
+ grid [checkbutton $ouput_tab.optim_check \
+ -onvalue 1 -offvalue 0 \
+ -variable ::configDialogs::compiler::option_optim_ena \
+ ] -column 2 -row 11 -sticky w -columnspan 3
+
+ # Maximum length of IHEX-8 record
+ grid [Label $ouput_tab.ih8_max_len_lbl -anchor w \
+ -text [mc "Maximum HEX record data length"] \
+ -helptext [mc "Maximum length of Intel HEX 8 record data field.\n\nGeneraly it doesn't matter what is set here. But some (badly written)\nprogrammes may refuse to load files containing records which exceeds\ncertain length.\n\nHigher value also results in smaller .hex files\n\nValue equal to 0 will be treated as 1"] \
+ ] -column 1 -row 12 -sticky we
+ grid [spinbox $ouput_tab.ih8_max_len_spbox \
+ -from 0 -to 255 -bg white -validate all -width 4 \
+ -textvariable ::configDialogs::compiler::max_ihex_rec_length \
+ -vcmd "::configDialogs::compiler::ih8_max_len_spbox_val %P"
+ ] -column 2 -row 12 -sticky w -columnspan 3
+
+ #
+ ## Tab "Directives"
+ #
+
+ # Header
+ grid [label $directives_tab.header \
+ -anchor w -text [mc "Ignore directives"] \
+ -font [font create -family {helvetica} -size -17 -weight bold] \
+ ] -column 0 -row 0 -columnspan 3 -sticky we -pady 10 -padx 10
+ grid [label $directives_tab.accept_label \
+ -text [mc "Accept"] -anchor w \
+ ] -column 1 -row 1
+ grid [label $directives_tab.ignore_label \
+ -text [mc "Ignore"] -anchor w \
+ ] -column 2 -row 1
+
+ # Create matrix of radio buttons
+ set row 2
+ foreach var {
+ nomod paging pagelength
+ pagewidth title date
+ list
+ } txt {
+ $nomod {$nopaging, $paging} $pagelength
+ $pagewidth $title $date
+ {$list, $nolist, list, nolist}
+ } helptext {
+ {}
+ {}
+ {}
+ {}
+ {}
+ {}
+ {}
+ } {
+
+ # Label
+ grid [Label $directives_tab.${var}_label \
+ -text $txt -anchor w -highlightthickness 0 -bd 0 \
+ -helptext $helptext \
+ ] -column 0 -row $row -sticky we
+ # Accept
+ grid [radiobutton $directives_tab.${var}_radio0 -value 0 \
+ -variable ::configDialogs::compiler::option__${var} \
+ ] -column 1 -row $row
+ # Ignore
+ grid [radiobutton $directives_tab.${var}_radio1 -value 1 \
+ -variable ::configDialogs::compiler::option__${var} \
+ ] -column 2 -row $row
+
+ incr row
+ }
+
+ pack $nb0 -side top -fill both -expand 1
+ }
+
+ ## Validate content of spinbox "Max length of IHEX-8 record"
+ # @parm String string - String to validate
+ # @return Bool - Validation result
+ proc ih8_max_len_spbox_val {string} {
+ if {![string length $string]} {
+ return 1
+ }
+ if {![string is digit -strict $string]} {
+ return 0
+ }
+ if {$string > 255 || $string < 0} {
+ return 0
+ }
+ return 1
+ }
+
+ ## Retrieve settings from Compiler NS and X NS
+ # @return void
+ proc getSettings {} {
+ variable defaults ;# List of default settings
+ variable opt_WARNING_LEVEL ;# Warning level
+ variable max_ihex_rec_length ;# Int: Maximum length of IHEX-8 record
+
+ variable selected_assembler ;# Int: Preffered assembler (0==MCU8051IDE;1==ASEM-51;2==ASL)
+ variable assembler_ASEM51_config;# Array: ASEM-51 configuration
+ variable assembler_ASEM51_addcfg;# Array: ASEM-51 additional configuration
+ variable assembler_ASL_config ;# Array: ASL configuration
+ variable assembler_ASL_addcfg ;# Array: ASL additional configuration
+ variable assembler_AS31_config ;# Array: AS31 configuration
+ variable assembler_AS31_addcfg ;# Array: AS31 additional configuration
+
+ variable sdcc_bool_opt ;# Array: SDCC configuration
+ variable sdcc_str_opt ;# Array: SDCC configuration
+ variable sdcc_opt_str_opt ;# Array: SDCC configuration
+ variable sdcc_scs_str_opt ;# Array: SDCC configuration
+
+
+ ## Assembler: MCU8051IDE
+ # Set local option variables
+ foreach var $defaults {
+ set var [lindex $var 0]
+ set ::configDialogs::compiler::option_${var} [subst "\$::Compiler::Settings::$var"]
+ }
+ set max_ihex_rec_length ${Compiler::Settings::max_ihex_rec_length}
+
+ # Set warning level
+ set tmp {All}
+ switch -- ${::Compiler::Settings::WARNING_LEVEL} {
+ 0 {set tmp {All}}
+ 1 {set tmp {Errors + Warnings}}
+ 2 {set tmp {Errros only}}
+ 3 {set tmp {Nothing}}
+ default {puts stderr "Invalid WARNING_LEVEL value"}
+ }
+ set opt_WARNING_LEVEL $tmp
+
+ ## Preferred assembler
+ set selected_assembler $::ExternalCompiler::selected_assembler
+ ## ASEM-51
+ array set assembler_ASEM51_config [array get ::ExternalCompiler::assembler_ASEM51_config]
+ array set assembler_ASEM51_addcfg [array get ::ExternalCompiler::assembler_ASEM51_addcfg]
+ ## ASL
+ array set assembler_ASL_config [array get ::ExternalCompiler::assembler_ASL_config]
+ array set assembler_ASL_addcfg [array get ::ExternalCompiler::assembler_ASL_addcfg]
+ ## AS31
+ array set assembler_AS31_config [array get ::ExternalCompiler::assembler_AS31_config]
+ array set assembler_AS31_addcfg [array get ::ExternalCompiler::assembler_AS31_addcfg]
+
+ ## SDCC
+ # Copy boolean options
+ array set sdcc_bool_opt [array get ::ExternalCompiler::sdcc_bool_options]
+ # Copy string options
+ array set sdcc_str_opt [array get ::ExternalCompiler::sdcc_string_options]
+ # Copy optional strings
+ array set sdcc_opt_str_opt [array get ::ExternalCompiler::sdcc_optional_string_options]
+ # Copy semicolon separated optional string options
+ array set sdcc_scs_str_opt [array get ::ExternalCompiler::sdcc_scs_string_options]
+ }
+
+ ## Set compiler acording to local settings
+ # @return void
+ proc use_settings {} {
+ variable defaults ;# List of default settings
+ variable opt_WARNING_LEVEL ;# Warning level
+ variable conf_affected ;# Array of Bool: Affected parts of configuration
+
+ variable max_ihex_rec_length ;# Int: Maximum length of IHEX-8 record
+ variable selected_assembler ;# Int: Preffered assembler (0==MCU8051IDE;1==ASEM-51;2==ASL)
+ variable assembler_ASEM51_config;# Array: ASEM-51 configuration
+ variable assembler_ASEM51_addcfg;# Array: ASEM-51 additional configuration
+ variable assembler_ASL_config ;# Array: ASL configuration
+ variable assembler_ASL_addcfg ;# Array: ASL additional configuration
+ variable assembler_AS31_config ;# Array: AS31 configuration
+ variable assembler_AS31_addcfg ;# Array: AS31 additional configuration
+
+ variable asm51_custom_opts_text ;# Widget: Text widget "Custom options for ASEM-51"
+ variable asl_custom_opts_text ;# Widget: Text widget "Custom options for ASL"
+ variable as31_custom_opts_text ;# Widget: Text widget "Custom options for AS31"
+ variable sdcc_custom_opts_text ;# Widget: Text widget "Custom options for SDCC"
+
+ variable sdcc_bool_opt ;# Array: SDCC configuration
+ variable sdcc_str_opt ;# Array: SDCC configuration
+ variable sdcc_opt_str_opt ;# Array: SDCC configuration
+ variable sdcc_scs_str_opt ;# Array: SDCC configuration
+
+ ## Assembler: MCU8051IDE
+ if {$conf_affected(MCU8051IDE)} {
+ # Set option variables
+ foreach var $defaults {
+ set var [lindex $var 0]
+ set ::Compiler::Settings::$var [subst "\$::configDialogs::compiler::option_${var}"]
+ }
+ if {![string length $max_ihex_rec_length]} {
+ set max_ihex_rec_length 0
+ }
+ set Compiler::Settings::max_ihex_rec_length $max_ihex_rec_length
+
+ # Set warning level
+ set tmp ${::Compiler::Settings::WARNING_LEVEL}
+ switch -- $opt_WARNING_LEVEL {
+ {All} {
+ set tmp 0
+ }
+ {Errors + Warnings} {
+ set tmp 1
+ }
+ {Errros only} {
+ set tmp 2
+ }
+ {Nothing} {
+ set tmp 3
+ }
+ default {
+ puts stderr "Invalid WARNING_LEVEL value"
+ }
+ }
+ set ::Compiler::Settings::WARNING_LEVEL $tmp
+ }
+
+ ## Preferred assembler
+ if {$conf_affected(Compiler)} {
+ set ::ExternalCompiler::selected_assembler $selected_assembler
+ }
+
+ ## Assembler: ASEM51
+ if {$conf_affected(ASEM51)} {
+ array set ::ExternalCompiler::assembler_ASEM51_addcfg \
+ [array get assembler_ASEM51_addcfg]
+ array set ::ExternalCompiler::assembler_ASEM51_config \
+ [array get assembler_ASEM51_config]
+ set ::ExternalCompiler::assembler_ASEM51_config(custom) \
+ [regsub {\n$} [$asm51_custom_opts_text get 1.0 end] {}]
+ }
+
+ ## Assembler: ASL
+ if {$conf_affected(ASL)} {
+ array set ::ExternalCompiler::assembler_ASL_addcfg \
+ [array get assembler_ASL_addcfg]
+ array set ::ExternalCompiler::assembler_ASL_config \
+ [array get assembler_ASL_config]
+ set ::ExternalCompiler::assembler_ASL_config(custom) \
+ [regsub {\n$} [$asl_custom_opts_text get 1.0 end] {}]
+ }
+
+ ## Assembler: AS31
+ if {$conf_affected(AS31)} {
+ array set ::ExternalCompiler::assembler_AS31_addcfg \
+ [array get assembler_AS31_addcfg]
+ array set ::ExternalCompiler::assembler_AS31_config \
+ [array get assembler_AS31_config]
+ set ::ExternalCompiler::assembler_AS31_config(custom) \
+ [regsub {\n$} [$as31_custom_opts_text get 1.0 end] {}]
+ }
+
+ ## SDCC Custom options
+ if {$conf_affected(SDCC_Custom)} {
+ set sdcc_str_opt(custom) [regsub {\n$} [$sdcc_custom_opts_text get 1.0 end] {}]
+ set ::ExternalCompiler::sdcc_string_options(custom) $sdcc_str_opt(custom)
+ }
+
+ ## SDCC Configuration
+ if {
+ $conf_affected(SDCC_Linker) || $conf_affected(SDCC_Optimization) ||
+ $conf_affected(SDCC_Code) || $conf_affected(SDCC_General)
+ } {
+ # Copy boolean options
+ array set ::ExternalCompiler::sdcc_bool_options [array get sdcc_bool_opt]
+ # Copy string options
+ array set ::ExternalCompiler::sdcc_string_options [array get sdcc_str_opt]
+ # Copy optional strings
+ array set ::ExternalCompiler::sdcc_optional_string_options [array get sdcc_opt_str_opt]
+ # Copy semicolon separated optional string options
+ array set ::ExternalCompiler::sdcc_scs_string_options [array get sdcc_scs_str_opt]
+ }
+
+ ${::X::actualProject} retrieve_compiler_settings
+ }
+
+ ## Save settings to config file
+ # @return void
+ proc save_config {} {
+ variable max_ihex_rec_length ;# Int: Maximum length of IHEX-8 record
+ variable defaults ;# List of default settings
+
+ ## Assembler: MCU8051IDE
+ # Save option variables
+ foreach var $defaults {
+ set var [lindex $var 0]
+ ::settings setValue \
+ "Compiler/$var" \
+ [subst "\$::Compiler::Settings::${var}"]
+ }
+ ::settings setValue "Compiler/max_ihex_rec_length" \
+ ${::Compiler::Settings::max_ihex_rec_length}
+ # Save warning level
+ ::settings setValue "Compiler/WARNING_LEVEL" \
+ ${::Compiler::Settings::WARNING_LEVEL}
+
+ ## Preferred assembler
+ ::settings setValue "Compiler/selected_assembler" \
+ $::ExternalCompiler::selected_assembler
+
+ ## Assembler: ASEM-51
+ ::settings setValue "Compiler/assembler_ASEM51_addcfg" \
+ [array get ::ExternalCompiler::assembler_ASEM51_addcfg]
+ ::settings setValue "Compiler/assembler_ASEM51_config" \
+ [array get ::ExternalCompiler::assembler_ASEM51_config]
+
+ ## Assembler: ASL
+ ::settings setValue "Compiler/assembler_ASL_addcfg" \
+ [array get ::ExternalCompiler::assembler_ASL_addcfg]
+ ::settings setValue "Compiler/assembler_ASL_config" \
+ [array get ::ExternalCompiler::assembler_ASL_config]
+
+ ## Assembler: AS31
+ ::settings setValue "Compiler/assembler_AS31_addcfg" \
+ [array get ::ExternalCompiler::assembler_AS31_addcfg]
+ ::settings setValue "Compiler/assembler_AS31_config" \
+ [array get ::ExternalCompiler::assembler_AS31_config]
+
+ ## SDCC
+ foreach array {
+ sdcc_bool_options sdcc_string_options
+ sdcc_optional_string_options sdcc_scs_string_options
+ } {
+ ::settings setValue "Compiler/$array" \
+ [array get ::ExternalCompiler::$array]
+ }
+
+ # Synchronize
+ ::settings saveConfig
+ }
+
+ ## Load settings from config file
+ # @return void
+ proc load_config {} {
+ variable defaults ;# List of default settings
+ variable max_ihex_rec_length ;# Int: Maximum length of IHEX-8 record
+
+ ## Assembler: MCU8051IDE
+ # Load normal options
+ foreach item $defaults {
+ set var [lindex $item 0]
+ set val [lindex $item 1]
+ set ::Compiler::Settings::${var} \
+ [::settings getValue "Compiler/$var" $val]
+ }
+ set ::Compiler::Settings::max_ihex_rec_length \
+ [ ::settings getValue \
+ "Compiler/max_ihex_rec_length" \
+ ${::Compiler::Settings::max_ihex_rec_length} \
+ ]
+ if {
+ ![string is digit -strict ${::Compiler::Settings::max_ihex_rec_length}] ||
+ ${::Compiler::Settings::max_ihex_rec_length} < 0 ||
+ ${::Compiler::Settings::max_ihex_rec_length} > 255
+ } {
+ set ::Compiler::Settings::max_ihex_rec_length 255
+ }
+ # Load warning level
+ set ::Compiler::Settings::WARNING_LEVEL \
+ [ ::settings getValue \
+ "Compiler/WARNING_LEVEL" \
+ ${::Compiler::Settings::WARNING_LEVEL} \
+ ]
+
+ ## Preferred assembler
+ set ::ExternalCompiler::selected_assembler [::settings getValue \
+ "Compiler/selected_assembler" \
+ $::ExternalCompiler::selected_assembler_def \
+ ]
+
+ ## Assembler: ASEM51
+ # Base config
+ set conf [::settings getValue "Compiler/assembler_ASEM51_config" \
+ $::ExternalCompiler::assembler_ASEM51_config_def \
+ ]
+ set len [llength $conf]
+ for {set i 0} {$i < $len} {incr i} {
+ set key [lindex $conf $i]
+ incr i
+ set val [lindex $conf $i]
+
+ if {[llength [array names ::ExternalCompiler::assembler_ASEM51_config -exact $key]]} {
+ set ::ExternalCompiler::assembler_ASEM51_config($key) $val
+ }
+ }
+ # Additional config
+ set conf [::settings getValue "Compiler/assembler_ASEM51_addcfg" \
+ $::ExternalCompiler::assembler_ASEM51_addcfg_def \
+ ]
+ set len [llength $conf]
+ for {set i 0} {$i < $len} {incr i} {
+ set key [lindex $conf $i]
+ incr i
+ set val [lindex $conf $i]
+
+ if {[llength [array names ::ExternalCompiler::assembler_ASEM51_addcfg -exact $key]]} {
+ set ::ExternalCompiler::assembler_ASEM51_addcfg($key) $val
+ }
+ }
+
+ ## Assembler: ASL
+ # Base config
+ set conf [::settings getValue "Compiler/ASL" \
+ $::ExternalCompiler::assembler_ASL_config_def \
+ ]
+ set len [llength $conf]
+ for {set i 0} {$i < $len} {incr i} {
+ set key [lindex $conf $i]
+ incr i
+ set val [lindex $conf $i]
+
+ if {[llength [array names ::ExternalCompiler::assembler_ASL_config -exact $key]]} {
+ set ::ExternalCompiler::assembler_ASL_config($key) $val
+ }
+ }
+ # Additional config
+ set conf [::settings getValue "Compiler/ASL" \
+ $::ExternalCompiler::assembler_ASL_addcfg_def \
+ ]
+ set len [llength $conf]
+ for {set i 0} {$i < $len} {incr i} {
+ set key [lindex $conf $i]
+ incr i
+ set val [lindex $conf $i]
+
+ if {[llength [array names ::ExternalCompiler::assembler_ASL_addcfg -exact $key]]} {
+ set ::ExternalCompiler::assembler_ASL_addcfg($key) $val
+ }
+ }
+
+ ## Assembler: AS31
+ # Base config
+ set conf [::settings getValue "Compiler/AS31" \
+ $::ExternalCompiler::assembler_AS31_config_def \
+ ]
+ set len [llength $conf]
+ for {set i 0} {$i < $len} {incr i} {
+ set key [lindex $conf $i]
+ incr i
+ set val [lindex $conf $i]
+
+ if {[llength [array names ::ExternalCompiler::assembler_AS31_config -exact $key]]} {
+ set ::ExternalCompiler::assembler_AS31_config($key) $val
+ }
+ }
+ # Additional config
+ set conf [::settings getValue "Compiler/AS31" \
+ $::ExternalCompiler::assembler_AS31_addcfg_def \
+ ]
+ set len [llength $conf]
+ for {set i 0} {$i < $len} {incr i} {
+ set key [lindex $conf $i]
+ incr i
+ set val [lindex $conf $i]
+
+ if {[llength [array names ::ExternalCompiler::assembler_AS31_addcfg -exact $key]]} {
+ set ::ExternalCompiler::assembler_AS31_addcfg($key) $val
+ }
+ }
+
+ ## SDCC
+ foreach array {
+ sdcc_bool_options sdcc_string_options
+ sdcc_optional_string_options sdcc_scs_string_options
+ } {
+ set conf [::settings getValue \
+ "Compiler/$array" [subst "\$::ExternalCompiler::${array}_def"] \
+ ]
+ set len [llength $conf]
+ for {set i 0} {$i < $len} {incr i} {
+ set key [lindex $conf $i]
+ incr i
+ set val [lindex $conf $i]
+
+ if {[llength [array names ::ExternalCompiler::$array -exact $key]]} {
+ set ::ExternalCompiler::${array}($key) $val
+ }
+ }
+ }
+ }
+
+ ## Destroy the dialog
+ # @return void
+ proc CANCEL {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Destroy dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Use settings and destroy the dialog
+ # @return void
+ proc OK {} {
+ variable win ;# ID of toplevel dialog window
+
+ # Use and save settings
+ use_settings
+ save_config
+
+ # Destroy dialog window
+ CANCEL
+ }
+
+ ## Restrore defaults
+ # @return void
+ proc DEFAULTS {} {
+ variable win ;# ID of toplevel dialog window
+ variable defaults ;# List of default settings
+ variable opt_WARNING_LEVEL ;# Warning level
+ variable max_ihex_rec_length ;# Int: Maximum length of IHEX-8 record
+
+ # Text widgets
+ variable sdcc_custom_opts_text ;# Widget: Text widget "Custom options for SDCC"
+ variable asm51_custom_opts_text ;# Widget: Text widget "Custom options for ASEM-51"
+ variable asl_custom_opts_text ;# Widget: Text widget "Custom options for ASL"
+ variable as31_custom_opts_text ;# Widget: Text widget "Custom options for AS31"
+
+ # External assembler configuration
+ variable selected_assembler ;# Int: Preffered assembler (0==MCU8051IDE;1==ASEM-51;2==ASL)
+ variable assembler_ASEM51_config;# Array: ASEM-51 configuration
+ variable assembler_ASEM51_addcfg;# Array: ASEM-51 additional configuration
+ variable assembler_ASL_config ;# Array: ASL configuration
+ variable assembler_ASL_addcfg ;# Array: ASL additional configuration
+ variable assembler_AS31_config ;# Array: AS31 configuration
+ variable assembler_AS31_addcfg ;# Array: AS31 additional configuration
+
+ # SDCC Configuration
+ variable sdcc_bool_opt ;# Array: SDCC configuration
+ variable sdcc_str_opt ;# Array: SDCC configuration
+ variable sdcc_opt_str_opt ;# Array: SDCC configuration
+ variable sdcc_scs_str_opt ;# Array: SDCC configuration
+
+ # Confirmation dialog
+ if {
+ [tk_messageBox \
+ -parent $win \
+ -type yesno \
+ -icon question \
+ -title [mc "Restore defaults"] \
+ -message [mc "Are you sure that you want restore default settings ?"] \
+ ] != {yes}
+ } {
+ return
+ }
+
+ ## Preferred assembler
+ set selected_assembler $::ExternalCompiler::selected_assembler_def
+ ## Assembler MCU8051IDE
+ # Restore normal options
+ foreach item $defaults {
+ set var [lindex $item 0]
+ set val [lindex $item 1]
+ set ::configDialogs::compiler::option_${var} $val
+ }
+ set max_ihex_rec_length 16
+ # Warning level
+ set opt_WARNING_LEVEL {All}
+ ## ASEM-51
+ array set assembler_ASEM51_addcfg $::ExternalCompiler::assembler_ASEM51_addcfg_def
+ array set assembler_ASEM51_config $::ExternalCompiler::assembler_ASEM51_config_def
+ # Custom options
+ if {[winfo exists $asm51_custom_opts_text]} {
+ $asm51_custom_opts_text delete 1.0 end
+ $asm51_custom_opts_text insert end $assembler_ASEM51_config(custom)
+ }
+ ## ASL
+ array set assembler_ASL_addcfg $::ExternalCompiler::assembler_ASL_addcfg_def
+ array set assembler_ASL_config $::ExternalCompiler::assembler_ASL_config_def
+ # Custom options
+ if {[winfo exists $asl_custom_opts_text]} {
+ $asl_custom_opts_text delete 1.0 end
+ $asl_custom_opts_text insert end $assembler_ASL_config(custom)
+ }
+ ## AS31
+ array set assembler_AS31_addcfg $::ExternalCompiler::assembler_AS31_addcfg_def
+ array set assembler_AS31_config $::ExternalCompiler::assembler_AS31_config_def
+ # Custom options
+ if {[winfo exists $as31_custom_opts_text]} {
+ $as31_custom_opts_text delete 1.0 end
+ $as31_custom_opts_text insert end $assembler_AS31_config(custom)
+ }
+
+ ## SDCC
+ # Copy boolean options
+ array set sdcc_bool_opt ${::ExternalCompiler::sdcc_bool_options_def}
+ # Copy string options
+ array set sdcc_str_opt ${::ExternalCompiler::sdcc_string_options_def}
+ # Copy optional strings
+ array set sdcc_opt_str_opt ${::ExternalCompiler::sdcc_optional_string_options_def}
+ # Copy semicolon separated optional string options
+ array set sdcc_scs_str_opt ${::ExternalCompiler::sdcc_scs_string_options_def}
+ # Custom options
+ if {[winfo exists $sdcc_custom_opts_text]} {
+ $sdcc_custom_opts_text delete 1.0 end
+ $sdcc_custom_opts_text insert end $sdcc_str_opt(custom)
+ }
+ }
+}
diff --git a/lib/configdialogs/configdialogs.tcl b/lib/configdialogs/configdialogs.tcl
new file mode 100755
index 0000000..cbffd16
--- /dev/null
+++ b/lib/configdialogs/configdialogs.tcl
@@ -0,0 +1,51 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements various configuration dialogs
+#
+# Currently implemented:
+# - Editor configuration
+# - Compiler configuration
+# - Right panel configuration
+# - Main toolbar configuration
+# - Custom commands configuration
+# - Shortcuts configuration
+# - Global configuration
+# - Simulator configuration
+# - Terminal configuration
+# --------------------------------------------------------------------------
+
+namespace eval configDialogs {
+ # Load all available configuration dialogs into one common namespace
+ source "${::LIB_DIRNAME}/configdialogs/editor_config.tcl" ;# Editor configuration dialog
+ source "${::LIB_DIRNAME}/configdialogs/compiler_config.tcl" ;# Compiler configuration dialog
+ source "${::LIB_DIRNAME}/configdialogs/rightpanel_config.tcl" ;# Right panel configuration dialog
+ source "${::LIB_DIRNAME}/configdialogs/toolbar_config.tcl" ;# Main toolbar configuration dialog
+ source "${::LIB_DIRNAME}/configdialogs/custom_commands_config.tcl" ;# Custom commands configuration dialog
+ source "${::LIB_DIRNAME}/configdialogs/shortcuts_config.tcl" ;# Shortcuts configuration dialog
+ source "${::LIB_DIRNAME}/configdialogs/global_config.tcl" ;# Global configuration dialog
+ source "${::LIB_DIRNAME}/configdialogs/simulator_config.tcl" ;# Simulator configuration dialog
+ source "${::LIB_DIRNAME}/configdialogs/terminal_config.tcl" ;# Terminal configuration dialog
+}
diff --git a/lib/configdialogs/custom_commands_config.tcl b/lib/configdialogs/custom_commands_config.tcl
new file mode 100755
index 0000000..e04ae1d
--- /dev/null
+++ b/lib/configdialogs/custom_commands_config.tcl
@@ -0,0 +1,418 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements custom commands configuration dialog
+# --------------------------------------------------------------------------
+
+namespace eval custom_commands {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened 0 ;# Bool: True if this dialog is already opened
+
+ # Font for text widgets
+ variable cmd_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ ]
+
+ variable text_0 ;# ID of text widget for command 0
+ variable text_1 ;# ID of text widget for command 1
+ variable text_2 ;# ID of text widget for command 2
+
+ variable description ;# Array: Command description (-textvariable) (idx: 0..2)
+ variable cmfr_dialog ;# Array of Bool: Variable for checkbutton "Confirmation dialog"
+ variable results_dialog ;# Array of Bool: Variable for checkbutton "Show results"
+ variable ignore_errors ;# Array of Bool: Variable for checkbutton "Ignore errors"
+
+ ## Create the dialog
+ # @parm Int = 0 - number of tab to raise
+ # @return void
+ proc mkDialog args {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+ variable cmd_font ;# Font for text widgets
+
+ variable text_0 ;# ID of text widget for command 0
+ variable text_1 ;# ID of text widget for command 1
+ variable text_2 ;# ID of text widget for command 2
+
+ variable description ;# Array: Command description (-textvariable) (idx: 0..2)
+ variable cmfr_dialog ;# Array of Bool: Variable for checkbutton "Confirmation dialog"
+ variable results_dialog ;# Array of Bool: Variable for checkbutton "Show results"
+ variable ignore_errors ;# Array of Bool: Variable for checkbutton "Ignore errors"
+
+ # Destroy the dialog if it's alredy opened
+ if {$dialog_opened} {
+ destroy .custom_commands_config_dialog
+ }
+ set dialog_opened 1
+
+ # Create toplevel window
+ set win [toplevel .custom_commands_config_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ label $win.header_label \
+ -compound left \
+ -image ::ICONS::22::gear \
+ -text [mc "Edit custom commands"] \
+ -font [font create -size -20]
+
+ # Create notebook
+ set nb [ttk::notebook $win.nb]
+
+ # Create notebook tabs
+ for {set idx 0} {$idx < 3} {incr idx} {
+ # Create tab
+ set tab [frame $nb.frame_${idx}]
+ $nb add $tab -image ::ICONS::22::gear$idx
+
+ # Create "Short description" (entry and label)
+ pack [Label $tab.desc_label \
+ -text [mc "Short description"] \
+ -helptext [mc "This string will be used as status bar tip (max. 50 chars)"]
+ ] -anchor w
+ pack [ttk::entry $tab.desc_entry \
+ -validate key \
+ -textvariable ::configDialogs::custom_commands::description($idx) \
+ -validatecommand {::configDialogs::custom_commands::desc_validate %P} \
+ ] -fill x
+
+ ## Create options labelframe
+ label $tab.labelframe_label -compound left -image ::ICONS::16::configure -text [mc "Options"]
+ set frame [ttk::labelframe $tab.labelframe -labelwidget $tab.labelframe_label]
+ # Create checkbutton "Confirmation dialog"
+ set button [checkbutton $frame.cmfr_cbutton -anchor w \
+ -text [mc "Confirmation dialog"] \
+ -variable ::configDialogs::custom_commands::cmfr_dialog($idx) \
+ ]
+ pack $button -anchor w
+ DynamicHelp::add $button -text [mc "Invkoke dialog to confirm command execution"]
+ # Create checkbutton "Show results"
+ set button [checkbutton $frame.results_cbutton \
+ -text [mc "Show results"] -anchor w \
+ -variable ::configDialogs::custom_commands::results_dialog($idx) \
+ ]
+ pack $button -anchor w
+ DynamicHelp::add $button -text [mc "After finish show dialog with results"]
+ # Create checkbutton "Ignore errors"
+ set button [checkbutton $frame.ignore_cbutton \
+ -text [mc "Ignore errors"] -anchor w \
+ -variable ::configDialogs::custom_commands::ignore_errors($idx) \
+ ]
+ pack $button -anchor w
+ DynamicHelp::add $button -text [mc "Do not invoke error dialog if the process fail"]
+ pack $frame -fill x -pady 10 -padx 5
+
+ # Create label "Commands to execute" and help button
+ set frame [frame $tab.cmd_label_frame]
+ pack [label $frame.label \
+ -text [mc "Shell script to execute"] \
+ ] -side left
+ pack [ttk::button $frame.button \
+ -image ::ICONS::16::help \
+ -style Flat.TButton \
+ -command {::configDialogs::custom_commands::show_help} \
+ ] -side right
+ DynamicHelp::add $frame.button \
+ -text [mc "Show help"]
+ pack $frame -fill x
+
+ # Create text for entering commands
+ set frame [frame $tab.text_frame]
+ set text [text $frame.text \
+ -background {#FFFFFF} \
+ -width 1 -height 1 \
+ -font $cmd_font -undo 1 \
+ -yscrollcommand "$frame.scrollbar set" \
+ ]
+ pack $text -side left -fill both -expand 1
+ pack [ttk::scrollbar $frame.scrollbar \
+ -orient vertical \
+ -command "$text yview" \
+ ] -side right -fill y
+ pack $frame -fill both -expand 1
+
+ # Set NS variable -- text widget reference
+ set text_$idx $text
+
+ # Get settins from the program
+ if {[regexp {\s*[01]\s+[01]\s+[01]\s*} $::X::custom_command_options($idx)]} {
+ set cmfr_dialog($idx) [lindex $::X::custom_command_options($idx) 0]
+ set results_dialog($idx) [lindex $::X::custom_command_options($idx) 1]
+ set ignore_errors($idx) [lindex $::X::custom_command_options($idx) 2]
+ }
+
+ set description($idx) $::X::custom_command_desc($idx)
+ $text insert end $::X::custom_command_cmd($idx)
+ }
+
+ # Raise tab
+ if {$args == {}} {
+ set args 0
+ }
+ $nb select [lindex [$nb tabs] $args]
+
+ # Create button frame at the bottom
+ set but_frame [frame $win.button_frame]
+ # Button "Ok"
+ pack [ttk::button $but_frame.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::custom_commands::OK} \
+ ] -side right
+ # Button "Cancel"
+ pack [ttk::button $but_frame.but_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::configDialogs::custom_commands::CANCEL} \
+ ] -side right
+
+ # Pack frames and notebook
+ pack $but_frame -side bottom -fill x -expand 0 -anchor s -padx 10 -pady 5
+ pack $win.header_label -side top -pady 6
+ pack $nb -side top -fill both -expand 1 -padx 10
+
+ # Finalize dialog creation
+ wm iconphoto $win ::ICONS::16::configure
+ wm transient $win .
+ wm title $win [mc "Edit custom commands - %s" ${::APPNAME}]
+ wm minsize $win 460 400
+ raise $win
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW {
+ ::configDialogs::custom_commands::CANCEL
+ }
+ tkwait window $win
+ }
+
+ ## Show help window
+ # @return void
+ proc show_help {} {
+ # Destroy prevoius help window
+ if {[winfo exists .custom_commands_help]} {
+ destroy .custom_commands_help
+ return
+ }
+ set x [expr {[winfo pointerx .] - 400}]
+ set y [winfo pointery .]
+
+ # Create new help window
+ set win [toplevel .custom_commands_help -class {Help} -bg {#EEEEEE}]
+ set frame [frame $win.f -bg {#555555} -bd 0 -padx 1 -pady 1]
+ wm overrideredirect $win 1
+
+ # Click to close
+ bind $win <Button-1> "grab release $win; destroy $win"
+
+ # Create header "-- click to close --"
+ pack [label $frame.lbl_header \
+ -text [mc "-- click to close --"] \
+ -bg {#FFFF55} -font $::smallfont \
+ -fg {#000000} -anchor c \
+ ] -side top -anchor c -fill x
+
+ # Create text widget
+ set text [text $frame.text \
+ -bg {#FFFFCC} \
+ -exportselection 0 \
+ -takefocus 0 \
+ -cursor left_ptr \
+ -bd 0 -relief flat \
+ ]
+
+ pack $frame -fill both -expand 1
+
+ # Create text tags
+ $text tag configure tag_bold_small \
+ -font [font create -weight bold -size -12 -family $::DEFAULT_FIXED_FONT]
+ $text tag configure tag_bold_big \
+ -foreground {#0000DD} -underline 1 \
+ -font [font create -weight bold -size -14 -family $::DEFAULT_FIXED_FONT]
+
+ # Fill in the text widget
+ $text insert end [mc "VARIABLES:"]
+ $text tag add tag_bold_big {insert linestart} {insert lineend}
+ $text insert end "\n %URL"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tThe full URL of the current file\n"]
+ $text insert end " %URLS"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tList of the URLs of all open documents\n"]
+ $text insert end " %directory"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tProject directory\n"]
+ $text insert end " %filename"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tThe filename of the current document\n"]
+ $text insert end " %basename"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tSame as %filename, but without extension\n"]
+ $text insert end " %mainfile"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tName of project main file\n"]
+ $text insert end " %line"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tNumber of the current line\n"]
+ $text insert end " %column"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tNumber of the current column\n"]
+ $text insert end " %selection"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tThe selected text in the current file\n"]
+ $text insert end " %text"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tThe full text of the current file\n"]
+ $text insert end " %%"
+ $text tag add tag_bold_small {insert linestart} {insert lineend}
+ $text insert end [mc "\t\tPercent sign\n\n"]
+ $text insert end [mc "Variables %line, %column, %selection and %text"]
+ foreach start {10 17 26 41} end {15 24 36 46} {
+ $text tag add tag_bold_small \
+ [list insert linestart+${start}c] \
+ [list insert linestart+${end}c]
+ }
+ $text insert end [mc "\nare not avaliable if external editor is used"]
+
+ # Show the text widget
+ $text configure -state disabled
+ pack $text -side bottom -fill both -expand 1
+
+ # Set window attributes
+ wm geometry $win "=400x270+$x+$y"
+ wm protocol $win WM_DELETE_WINDOW "
+ grab release $win
+ destroy $win
+ grab .custom_commands_config_dialog"
+ wm transient $win .custom_commands_config_dialog
+ raise $win
+ update
+ catch {
+ grab -global $win
+ }
+ tkwait window $win
+ }
+
+ ## Validate content of entry "Description"
+ # @parm String content - String to validate
+ # @return Bool - result
+ proc desc_validate {content} {
+ if {[string length $content] > 50} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Change content of configuration variables
+ # @return void
+ proc use_settings {} {
+ variable description ;# Array: Command description (-textvariable) (idx: 0..2)
+ variable cmfr_dialog ;# Array of Bool: Variable for checkbutton "Confirmation dialog"
+ variable results_dialog ;# Array of Bool: Variable for checkbutton "Show results"
+ variable ignore_errors ;# Array of Bool: Variable for checkbutton "Ignore errors"
+
+ variable text_0 ;# ID of text widget for command 0
+ variable text_1 ;# ID of text widget for command 1
+ variable text_2 ;# ID of text widget for command 2
+
+ for {set i 0} {$i < 3} {incr i} {
+ # Change content of configuration variables
+ set ::X::custom_command_options($i) \
+ "$cmfr_dialog($i) $results_dialog($i) $ignore_errors($i)"
+ set ::X::custom_command_desc($i) $description($i)
+ set ::X::custom_command_cmd($i) [regsub {\n$} [[subst "\$text_${i}"] get 1.0 end] {}]
+
+ # Change status tips
+ if {[winfo exists .mainIconBar.custom$i]} {
+ setStatusTip \
+ -widget .mainIconBar.custom$i \
+ -text [mc "Custom command %s: %s" $i $description($i)]
+ }
+ }
+ }
+
+ ## Save configuration to config file
+ # @return void
+ proc save_config {} {
+ # Save settings
+ for {set i 0} {$i < 3} {incr i} {
+ ::settings setValue "Custom command $i/options" \
+ $::X::custom_command_options($i)
+ ::settings setValue "Custom command $i/description" \
+ $::X::custom_command_desc($i)
+ ::settings setValue "Custom command $i/command" \
+ $::X::custom_command_cmd($i)
+ }
+
+ # Commit
+ ::settings saveConfig
+ }
+
+ ## Load configuratin from config file
+ # @return void
+ proc load_config {} {
+ for {set i 0} {$i < 3} {incr i} {
+ # Options
+ set ::X::custom_command_options($i) [::settings \
+ getValue "Custom command $i/options" \
+ $::X::custom_command_options($i)]
+ # Description
+ set ::X::custom_command_desc($i) [::settings \
+ getValue "Custom command $i/description" \
+ $::X::custom_command_desc($i)]
+ # Command
+ set ::X::custom_command_cmd($i) [::settings \
+ getValue "Custom command $i/command" \
+ $::X::custom_command_cmd($i)]
+ }
+ }
+
+ ## Take back changes and destroy dialog window
+ # @return void
+ proc CANCEL {} {
+ variable win ;# ID of dialog toplevel window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Get rid of dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Apply changes and destroy dialog window
+ # @return void
+ proc OK {} {
+ variable win ;# ID of dialog toplevel window
+
+ # Apply new settings
+ use_settings ;# Adjust NS variables
+ save_config ;# Save new config
+
+ # Get rid of the dialog window
+ CANCEL
+ }
+}
diff --git a/lib/configdialogs/editor_config.tcl b/lib/configdialogs/editor_config.tcl
new file mode 100755
index 0000000..bd51a55
--- /dev/null
+++ b/lib/configdialogs/editor_config.tcl
@@ -0,0 +1,2148 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements editor configuration dialog
+# --------------------------------------------------------------------------
+
+namespace eval editor {
+
+ variable dialog_opened 0 ;# Bool: True if this dialog is already opened
+ variable row 0 ;# General purpose variable (some row somewhere)
+ variable win ;# ID of dialog toplevel window
+ variable button_index 0 ;# Button index (for creating many buttons)
+
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable changed ;# Bool: Settings changed
+ variable apply_button ;# ID of button "Apply"
+
+ variable autocompletion_turned_on 0
+
+ # Notebook related
+ variable nb ;# Widget: Notebook itself
+ variable editor_tab ;# Widget: Tab "Editor"
+ variable general_tab ;# Widget: Tab "General"
+ variable colors_tab ;# Widget: Tab "Colors"
+ variable fonts_tab ;# Widget: Tab "Fonts"
+ variable highlight_tab ;# Widget: Tab "Syntax highlight"
+ variable highlight_tab_asm ;# Widget: Tab "Syntax highlight"/"Assembler"
+ variable highlight_tab_C ;# Widget: Tab "Syntax highlight"/"C language"
+ variable highlight_tab_lst ;# Widget: Tab "Syntax highlight"/"Code listing"
+
+ ## Tab "Editor"
+ ## Int: Editor to use
+ # 0 - Native editor
+ # 1 - Vim
+ # 2 - Emacs
+ # 3 - Nano
+ # 4 - dav
+ # 5 - le
+ variable editor_to_use
+
+ # Tab "General"
+ variable default_encoding ;# Default encoding for opening files
+ variable default_eol ;# Default EOL character
+ variable intentation_mode ;# Editor indentation mode
+ variable spaces_no_tabs ;# Bool: Use spaces instead of tabs
+ variable number_of_spaces ;# Int: Number of spaces to use instead of tab
+ variable autosave ;# Int: Autosave interval in minutes (0 == disabled)
+ variable auto_brackets ;# Automaticaly insert oposite brackets, quotes, etc.
+ variable hg_trailing_sp ;# Bool: Highlight trailing space
+ variable auto_completion ;# Bool: Enable popup-based completion
+ variable cline_completion ;# Bool: Enable popup-based completion for command line
+ variable avaliable_encodings {
+ utf-8 iso8859-1 iso8859-2
+ iso8859-3 iso8859-4 iso8859-5
+ iso8859-6 iso8859-7 iso8859-8
+ iso8859-9 iso8859-10 iso8859-13
+ iso8859-14 iso8859-15 iso8859-16
+ cp1250 cp1251 cp1252
+ cp1253 cp1254 cp1255
+ cp1256 cp1257 cp1258
+ }
+
+ # Tab "Colors"
+ variable color_normal_text ;# RGB: Editor backgound color
+ variable color_selected_text ;# RGB: Backgound color for selected text
+ variable color_current_line ;# RGB: Backgound color for current line
+ variable color_bookmark ;# RGB: Backgound color for bookmarks
+ variable color_breakpoint ;# RGB: Backgound color for breakpoints
+ variable color_simulator_line ;# RGB: Backgound color for simulator line
+ variable color_error_line ;# RGB: Backgound color for line containing an error
+ variable color_trailing_space ;# RGB: Backgound color for trailing space
+ variable color_iconBorder_bg ;# RGB: Backgound color for icon border
+ variable color_lineNumbers_bg ;# RGB: Backgound color for line numbers
+ variable color_lineNumbers_fg ;# RGB: Foregound color for line numbers
+
+ # Tab "Fonts"
+ variable sample_text ;# ID of text widget for sample text
+ variable sample_text_size ;# Font size
+ variable sample_text_family ;# Font family
+
+ ## Tab "Assembler syntax highlight"
+ variable hightlight_tags_asm ;# List: Definition of colors and styles for assembler syntax highlighting
+ variable list_of_tags_asm ;# List: Highlighting tags
+ variable highlight_tab_scr_text_asm ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_asm ;# ID of text widget for sample text
+ # List of checkbuttons affected by changing cursor position in sample text
+ variable highlight_tab_checkbuttons_asm
+
+ ## Tab "C" syntax highlight"
+ variable hightlight_tags_C ;# List: Definition of colors and styles for C syntax highlighting
+ variable list_of_tags_C ;# List: Highlighting tags
+ variable highlight_tab_scr_text_C ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_C ;# ID of text widget for sample text
+ # List of checkbuttons affected by changing cursor position in sample text
+ variable highlight_tab_checkbuttons_C
+
+ ## Tab "LST" syntax highlight"
+ variable hightlight_tags_lst ;# List: Definition of colors and styles for LST syntax highlighting
+ variable list_of_tags_lst ;# List: Highlighting tags
+ variable highlight_tab_scr_text_lst ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_lst ;# ID of text widget for sample text
+ # List of checkbuttons affected by changing cursor position in sample text
+ variable highlight_tab_checkbuttons_lst
+
+
+ ## Create the dialog
+ # @parm String = {} - Tab to raise on start up
+ # @return void
+ proc mkDialog args {
+ variable nb ;# Widget: Notebook itself
+ variable editor_tab ;# Widget: Tab "Editor"
+ variable general_tab ;# Widget: Tab "General"
+ variable colors_tab ;# Widget: Tab "Colors"
+ variable fonts_tab ;# Widget: Tab "Fonts"
+ variable highlight_tab ;# Widget: Tab "Syntax highlight"
+ variable highlight_tab_asm ;# Widget: Tab "Syntax highlight"/"Assembler"
+ variable highlight_tab_C ;# Widget: Tab "Syntax highlight"/"C language"
+ variable highlight_tab_lst ;# Widget: Tab "Syntax highlight"/"Code listing"
+
+ variable apply_button ;# ID of button "Apply"
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable changed ;# Bool: Settings changed
+ variable editor_to_use ;# Int: Prefred editor
+ variable sample_text ;# ID of text widget for sample text
+ variable sample_text_size ;# Font size
+ variable sample_text_family ;# Font family
+ variable row ;# General purpose variable (some row somewhere)
+ variable win ;# ID of dialog toplevel window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+ variable button_index ;# Button index (for creating many buttons)
+ variable hightlight_tags_asm ;# List: Definition of colors and styles for assembler syntax highlighting
+ variable hightlight_tags_C ;# List: Definition of colors and styles for C syntax highlighting
+ variable hightlight_tags_lst ;# List: Definition of colors and styles for LST syntax highlighting
+
+
+ set button_index 0
+
+ # Destroy dialog windows if it is already opened
+ if {$dialog_opened} {
+ destroy .editor_config_dialog
+ }
+ set dialog_opened 1
+ set changed 0
+ set anything_modified 0
+ # Get settings from the program
+ getSettings
+ # Create toplevel window
+ set win [toplevel .editor_config_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ label $win.header_label \
+ -compound left \
+ -image ::ICONS::32::configure \
+ -text [mc "Editor configuration"] \
+ -font [font create -size -20]
+
+ # Create notebook
+ set nb [ttk::notebook $win.nb]
+ bind $nb <<NotebookTabChanged>> {after idle {
+ set tab_index [%W index [%W select]]
+
+ if {[lsearch ${::configDialogs::editor::tab_created_so_far} $tab_index] == -1} {
+ lappend ::configDialogs::editor::tab_created_so_far $tab_index
+
+ if {!$::MICROSOFT_WINDOWS} {
+ ::configDialogs::editor::create_tab \
+ [lindex \
+ [list editor general colors fonts highlight] \
+ $tab_index \
+ ]
+ } else { ;# External editors are not available on Microsoft Windows
+ ::configDialogs::editor::create_tab \
+ [lindex \
+ [list general colors fonts highlight] \
+ $tab_index \
+ ]
+ }
+ }
+ }}
+ set ::configDialogs::editor::tab_created_so_far [list]
+ # Create Tab "Editor"
+ if {!$::MICROSOFT_WINDOWS} { ;# External editors are not available on Microsoft Windows
+ set editor_tab [frame $nb.editor_tab]
+ $nb add $editor_tab -text [mc "Editor"]
+ }
+ # Create Tab "General"
+ set general_tab [frame $nb.general_tab]
+ $nb add $general_tab -text [mc "General"]
+ # Create Tab "Colors"
+ set colors_tab [frame $nb.colors_tab]
+ $nb add $colors_tab -text [mc "Colors"]
+ # Create Tab "Fonts"
+ set fonts_tab [frame $nb.fonts_tab]
+ $nb add $fonts_tab -text [mc "Fonts"]
+ # Create Tab "Highlight"
+ set highlight_tab [frame $nb.highlight_tab]
+ $nb add $highlight_tab -text [mc "Syntax highlight"]
+
+ #
+ ## Finalize
+ #
+
+ if {[string length $args]} {
+ if {!$::MICROSOFT_WINDOWS} { ;# External editors are not available on Microsoft Windows
+ $nb select [lindex [$nb tabs] \
+ [lsearch [list {Editor} {General} {Colors} {Fonts} {Highlight}] $args]]
+ } {
+ $nb select [lindex [$nb tabs] \
+ [lsearch [list {General} {Colors} {Fonts} {Highlight}] $args]]
+ }
+ } {
+ if {!$::MICROSOFT_WINDOWS} { ;# External editors are not available on Microsoft Windows
+ if {$editor_to_use} {
+ foreach tab [list $highlight_tab $general_tab] {
+ $nb tab $tab -state disabled
+ }
+ $nb select $editor_tab
+ } {
+ $nb select $general_tab
+ }
+ } {
+ $nb select $general_tab
+ }
+ }
+
+ # Create button frame at the bottom
+ set but_frame [frame $win.button_frame]
+ # Button "Apply"
+ set apply_button [ttk::button $but_frame.but_apply \
+ -text [mc "Apply"] \
+ -state disabled \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::editor::APPLY} \
+ ]
+ pack $apply_button -side left
+ # Button "Ok"
+ pack [ttk::button $but_frame.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::editor::OK} \
+ ] -side right
+ # Button "Cancel"
+ pack [ttk::button $but_frame.but_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::configDialogs::editor::CANCEL} \
+ ] -side right
+
+ # Pack frames and notebook
+ pack $but_frame -side bottom -fill x -expand 0 -anchor s -padx 10 -pady 5
+ pack $win.header_label -side top -pady 6
+ pack $nb -side top -fill both -expand 1 -padx 10
+
+ # Finalize creation of the dialog
+ wm transient $win .
+ wm iconphoto $win ::ICONS::16::configure
+ wm title $win [mc "Editor configuration - %s" ${::APPNAME}]
+ wm geometry $win =380x440
+ wm resizable $win 0 0
+ raise $win
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW {
+ ::configDialogs::editor::CANCEL
+ }
+ tkwait window $win
+ }
+
+ ## Create tab in notebook
+ # @parm String tab_name - Name of tab to create
+ # @return void
+ proc create_tab {tab_name} {
+ variable nb ;# Widget: Notebook itself
+ variable editor_tab ;# Widget: Tab "Editor"
+ variable general_tab ;# Widget: Tab "General"
+ variable colors_tab ;# Widget: Tab "Colors"
+ variable fonts_tab ;# Widget: Tab "Fonts"
+ variable avaliable_encodings ;# Avaliable encodings
+ variable highlight_tab ;# Widget: Tab "Syntax highlight"
+ variable highlight_tab_asm ;# Widget: Tab "Syntax highlight"/"Assembler"
+ variable highlight_tab_C ;# Widget: Tab "Syntax highlight"/"C language"
+ variable highlight_tab_lst ;# Widget: Tab "Syntax highlight"/"Code listing"
+
+ variable editor_to_use ;# Int: Prefred editor
+ variable sample_text ;# ID of text widget for sample text
+ variable sample_text_size ;# Font size
+ variable sample_text_family ;# Font family
+ variable row ;# General purpose variable (some row somewhere)
+ variable win ;# ID of dialog toplevel window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+ variable button_index ;# Button index (for creating many buttons)
+
+ switch -- $tab_name {
+ {editor} { ;# Tab "Editor selection"
+ set editor_top_frame [frame $editor_tab.top_frame]
+ # Preferred editor
+ grid [label $editor_top_frame.editor_lbl \
+ -text [mc "Preferred editor:"] -anchor w \
+ ] -row 0 -column 0 -sticky w
+ set row 1
+ set i 0
+ foreach text {
+ {Native editor} Vim Emacs Nano dav le
+ } {
+ grid [radiobutton $editor_top_frame.rabut_$i \
+ -variable ::configDialogs::editor::editor_to_use \
+ -value $i -text $text -state disabled \
+ -command ::configDialogs::editor::editor_to_use_changed \
+ ] -column 0 -padx 25 -row $row -sticky w
+ incr i
+ incr row
+ }
+ $editor_top_frame.rabut_0 configure -state normal
+ if {${::PROGRAM_AVALIABLE(urxvt)}} {
+ if {${::PROGRAM_AVALIABLE(vim)}} {
+ $editor_top_frame.rabut_1 configure -state normal
+ }
+ if {${::PROGRAM_AVALIABLE(emacs)}} {
+ $editor_top_frame.rabut_2 configure -state normal
+ }
+ if {${::PROGRAM_AVALIABLE(nano)}} {
+ $editor_top_frame.rabut_3 configure -state normal
+ }
+ if {${::PROGRAM_AVALIABLE(dav)}} {
+ $editor_top_frame.rabut_4 configure -state normal
+ }
+ if {${::PROGRAM_AVALIABLE(le)}} {
+ $editor_top_frame.rabut_5 configure -state normal
+ }
+ }
+ grid [label $editor_top_frame.editor_note \
+ -fg {#555555} -font [font create \
+ -family {helvetica} \
+ -size -14 -slant italic \
+ ] \
+ -text [mc "(This change will take effect upon next start.)"] \
+ ] -row 20 -column 0 -columnspan 2 -sticky w
+
+ # Finalize
+ grid columnconfigure $editor_top_frame 0 -minsize 200
+ grid columnconfigure $editor_top_frame 1 -weight 1
+ pack $editor_top_frame -side top -anchor nw -padx 5 -fill x
+ }
+ {general} { ;# Tab "General"
+ # Create label frames
+ set editing_labelframe [ttk::labelframe $general_tab.labelframe_edit \
+ -text [mc "Editing"] \
+ ]
+ set open_labelframe [ttk::labelframe $general_tab.labelframe_open \
+ -text [mc "File opening, saving, etc."] \
+ ]
+ set cmd_labelframe [ttk::labelframe $general_tab.labelframe_cmd \
+ -text [mc "Command line"] \
+ ]
+
+ ## Labelframe "Editing"
+ # Item: "Auto brackets"
+ grid [Label $editing_labelframe.autob_lbl \
+ -text [mc "Auto brackets"] \
+ -helptext [mc "If you type a left bracket, editor\nwill automaticaly insert right bracket"] \
+ ] -row 1 -column 0 -sticky w -padx 5
+ grid [checkbutton $editing_labelframe.autob_chbutton \
+ -variable ::configDialogs::editor::auto_brackets \
+ -command ::configDialogs::editor::settings_changed \
+ ] -row 1 -column 1 -sticky w -padx 5
+ DynamicHelp::add $editing_labelframe.autob_chbutton \
+ -text [mc "When you type a left bracket editor\nwill automaticaly insert right bracket"]
+ # Item: "Indentation mode"
+ grid [Label $editing_labelframe.imode_lbl \
+ -text [mc "Indentation mode"] \
+ -helptext [mc "What to do when you press enter\n\tnone\t- start on the begining of the next line\n\tnormal\t- keep indention of the previous line"] \
+ ] -row 2 -column 0 -sticky w -padx 5
+ grid [ttk::combobox $editing_labelframe.imode_cb \
+ -values [list [mc "none"] [mc "normal"]] \
+ -state readonly \
+ -width 0 \
+ -textvariable ::configDialogs::editor::intentation_mode \
+ ] -row 2 -column 1 -sticky we -padx 5
+ bind $editing_labelframe.imode_cb <<ComboboxSelected>> \
+ {::configDialogs::editor::settings_changed}
+ DynamicHelp::add $editing_labelframe.imode_cb \
+ -text [mc "What to do when you press enter\n\tnone\t- start on the begining of the next line\n\tnormal\t- keep indention of the previous line"]
+ # Item: "Insert ' ' instead of '\t'"
+ grid [Label $editing_labelframe.tabis_lbl \
+ -text [mc "Insert ' ' instead of '\\t'"] \
+ -helptext [mc "Use spaces instead of tabs"] \
+ ] -row 3 -column 0 -sticky w -padx 5
+ grid [checkbutton $editing_labelframe.tabis_chbutton \
+ -variable ::configDialogs::editor::spaces_no_tabs \
+ -command ::configDialogs::editor::settings_changed \
+ ] -row 3 -column 1 -sticky w -padx 5
+ DynamicHelp::add $editing_labelframe.tabis_chbutton \
+ -text [mc "Use spaces instead of tabs"]
+ # Item: "Number of spaces"
+ grid [Label $editing_labelframe.nofs_lbl \
+ -text [mc "Number of spaces"] \
+ -helptext [mc "Number of spaces to use instead of tabs"] \
+ ] -row 4 -column 0 -sticky w -padx 5
+ grid [spinbox $editing_labelframe.nofs_spinbox \
+ -from 1 -to 16 -bg white -validate all \
+ -vcmd "::configDialogs::editor::nofs_spinbox_val %P" \
+ -textvariable ::configDialogs::editor::number_of_spaces \
+ -command ::configDialogs::editor::settings_changed \
+ ] -row 4 -column 1 -sticky we -padx 5
+ DynamicHelp::add $editing_labelframe.nofs_spinbox \
+ -text [mc "Number of spaces to use instead of tabs"]
+ # Item: "Enable autocompletion"
+ grid [Label $editing_labelframe.completion_lbl \
+ -text [mc "Enable autocompletion"] \
+ -helptext [mc "Enable popup-based autocompletion"] \
+ ] -row 5 -column 0 -sticky w -padx 5
+ grid [checkbutton $editing_labelframe.completion_chbutton \
+ -variable ::configDialogs::editor::auto_completion \
+ -command ::configDialogs::editor::settings_changed \
+ ] -row 5 -column 1 -sticky w -padx 5
+ DynamicHelp::add $editing_labelframe.completion_chbutton \
+ -text [mc "Enable popup-based autocompletion"]
+ # Item: "Highlight trailing space"
+ grid [Label $editing_labelframe.trail_sp_lbl \
+ -text [mc "Highlight trailing space"] \
+ ] -row 6 -column 0 -sticky w -padx 5
+ grid [checkbutton $editing_labelframe.trail_sp_chbutton \
+ -variable ::configDialogs::editor::hg_trailing_sp \
+ -command ::configDialogs::editor::settings_changed \
+ ] -row 6 -column 1 -sticky w -padx 5
+ # Finalize
+ grid columnconfigure $editing_labelframe 0 -minsize 200
+ grid columnconfigure $editing_labelframe 1 -weight 1
+
+ ## Labelframe "File opening & saving"
+ # Item: "Show tab bar"
+ grid [Label $open_labelframe.show_editor_tab_bar_lbl \
+ -text [mc "Show tab bar"] \
+ ] -row 0 -column 0 -sticky w -padx 5
+ grid [checkbutton $open_labelframe.show_editor_tab_bar_chb \
+ -onvalue 1 -offvalue 0 \
+ -variable ::CONFIG(SHOW_EDITOR_TAB_BAR) \
+ -command ::configDialogs::editor::settings_changed \
+ ] -row 0 -column 1 -sticky w -padx 5
+
+ # Item: "Default charset"
+ grid [Label $open_labelframe.charset_lbl \
+ -text [mc "Default encoding"] \
+ -helptext [mc "When you open file with unknown encoding\nthis encoding will be used"] \
+ ] -row 1 -column 0 -sticky w -padx 5
+ grid [ttk::combobox $open_labelframe.charset_cb \
+ -width 0 \
+ -state readonly \
+ -values $avaliable_encodings \
+ -textvariable ::configDialogs::editor::default_encoding \
+ ] -row 1 -column 1 -sticky we -padx 5
+ bind $open_labelframe.charset_cb <<ComboboxSelected>> \
+ {::configDialogs::editor::settings_changed}
+ DynamicHelp::add $open_labelframe.charset_cb \
+ -text [mc "When you open file with unknown encoding\nthis encoding will be used"]
+ # Item: "Default EOL"
+ grid [Label $open_labelframe.eol_lbl \
+ -text [mc "Default EOL"] \
+ -helptext [mc "When you open file with unknown\nEOL (End Of Line) this EOL will be used"] \
+ ] -row 2 -column 0 -sticky w -padx 5
+ grid [ttk::combobox $open_labelframe.eol_cb \
+ -textvariable ::configDialogs::editor::default_eol \
+ -width 0 \
+ -state readonly \
+ -values {{lf} {cr} {crlf}} \
+ ] -row 2 -column 1 -sticky we -padx 5
+ bind $open_labelframe.eol_cb <<ComboboxSelected>> \
+ {::configDialogs::editor::settings_changed}
+ DynamicHelp::add $open_labelframe.eol_cb \
+ -text [mc "When you open file with unknown\nEOL (End Of Line) this EOL will be used"]
+ # Item: "Autosave"
+ grid [Label $open_labelframe.autosave_lbl \
+ -text [mc "Autosave interval"] \
+ -helptext [mc "Autosave interval in minutes (0 means disabled)"] \
+ ] -row 3 -column 0 -sticky w -padx 5
+ grid [ttk::combobox $open_labelframe.autosave_cb \
+ -width 0 \
+ -state readonly \
+ -values {0 1 2 5 10 15 20 30 45 60} \
+ -textvariable ::configDialogs::editor::autosave \
+ ] -row 3 -column 1 -sticky we -padx 5
+ bind $open_labelframe.autosave_cb <<ComboboxSelected>> \
+ {::configDialogs::editor::settings_changed}
+ DynamicHelp::add $open_labelframe.autosave_cb \
+ -text [mc "Autosave interval in minutes (0 means disabled)"]
+ # Finalize
+ grid columnconfigure $open_labelframe 0 -minsize 200
+ grid columnconfigure $open_labelframe 1 -weight 1
+
+ ## Labelframe "Command line"
+ # Item: "Enable autocompletion"
+ grid [Label $cmd_labelframe.completion_lbl \
+ -text [mc "Enable autocompletion"] \
+ -helptext [mc "Enable popup-based autocompletion"] \
+ ] -row 0 -column 0 -sticky w -padx 5
+ grid [checkbutton $cmd_labelframe.completion_chbutton \
+ -variable ::configDialogs::editor::cline_completion \
+ -command ::configDialogs::editor::settings_changed \
+ ] -row 0 -column 1 -sticky w -padx 5
+ # Finalize
+ grid columnconfigure $cmd_labelframe 0 -minsize 200
+ grid columnconfigure $cmd_labelframe 1 -weight 1
+
+ # Pack label frames of tab "General"
+ pack $editing_labelframe -fill both -expand 1 -padx 5
+ pack $open_labelframe -fill both -expand 1 -padx 5 -pady 10
+ pack $cmd_labelframe -fill both -expand 1 -padx 5
+ }
+ {colors} {;# Tab "Colors"
+ # Create label frames
+ set frm_textAreaBackfround [ttk::labelframe \
+ $colors_tab.textAreaBackfround \
+ -text [mc "Text area background"] \
+ -padding 5 \
+ ]
+ set frm_additionalElements [ttk::labelframe \
+ $colors_tab.additionalElements \
+ -text [mc "Additional elements"] \
+ -padding 5 \
+ ]
+
+ # Create buttons in label frame "Text area background"
+ set row 0
+ foreach name {
+ normal_text selected_text current_line
+ bookmark simulator_line breakpoint
+ error_line trailing_space
+ } text {
+ {Normal text} {Selected text} {Current line}
+ {Bookmark} {Simulator line} {Breakpoint}
+ {Line with an error} {Trailing space}
+ } {
+
+ mk_button_select_menu \
+ $frm_textAreaBackfround \
+ "::configDialogs::editor::color_$name" \
+ $name \
+ $text
+ }
+
+ grid columnconfigure $frm_textAreaBackfround 1 -minsize 200
+
+ # Create buttons in label frame "Text area background"
+ set row 0
+ foreach name {
+ iconBorder_bg lineNumbers_bg
+ lineNumbers_fg
+ } text {
+ {Icon border background} {Line numbers background}
+ {Line numbers foreground}
+ } {
+
+ mk_button_select_menu \
+ $frm_additionalElements \
+ "::configDialogs::editor::color_$name" \
+ $name \
+ $text
+
+ grid columnconfigure $frm_additionalElements 1 -minsize 200
+ }
+
+ # Pack label frames
+ pack $frm_textAreaBackfround -fill both -expand 1 -pady 5
+ pack $frm_additionalElements -fill both -expand 1 -pady 5
+ }
+ {fonts} { ;# Tab "Fonts"
+ # Create frames
+ set top_frame [frame $fonts_tab.frm_top_frame]
+ set bottom_frame [frame $fonts_tab.frm_bottom_frame]
+ set top_left_frame [frame $top_frame.frm_left]
+ set top_right_frame [frame $top_frame.frm_right]
+
+ # Create fonts listbox
+ set scrollbar [ttk::scrollbar $top_left_frame.scrollbar \
+ -orient vertical \
+ -command "$top_left_frame.list_box yview" \
+ ]
+ set listBox [ListBox $top_left_frame.list_box \
+ -bg white \
+ -yscrollcommand "$scrollbar set" \
+ -selectfill 1 \
+ -selectbackground #8888FF \
+ -highlightthickness 0 \
+ -height 15 \
+ -width 25 \
+ ]
+ pack $scrollbar -side right -fill y
+ pack $listBox -side left -fill both -expand 1
+ $listBox bindText <1> {::configDialogs::editor::select_font_family %W}
+ if {[winfo exists $listBox.c]} {
+ bind $listBox.c <Button-5> {%W yview scroll +5 units; break}
+ bind $listBox.c <Button-4> {%W yview scroll -5 units; break}
+ }
+
+ # Create size listbox
+ set scrollbar [ttk::scrollbar $top_right_frame.scrollbar \
+ -orient vertical \
+ -command "$top_right_frame.list_box yview" \
+ ]
+ set listBox [ListBox $top_right_frame.list_box \
+ -bg white \
+ -yscrollcommand "$scrollbar set" \
+ -selectfill 1 \
+ -selectbackground #8888FF \
+ -width 7 \
+ -height 15 \
+ -highlightthickness 0 \
+ ]
+ pack $scrollbar -side right -fill y
+ pack $listBox -side left -fill y
+ $listBox bindText <1> {::configDialogs::editor::select_font_size %W}
+ if {[winfo exists $listBox.c]} {
+ bind $listBox.c <Button-5> {%W yview scroll +5 units; break}
+ bind $listBox.c <Button-4> {%W yview scroll -5 units; break}
+ }
+
+ # Create sample text entry
+ set sample_text [entry $bottom_frame.entry \
+ -bg #EEEEEE \
+ -bd 0 \
+ -width 30 \
+ -font [font create \
+ -family $sample_text_family \
+ -size -$sample_text_size \
+ ] \
+ ]
+ pack $sample_text -pady 25
+ $sample_text insert end [mc "The Quick Brown Fox Jumps Over The Lazy Dog"]
+
+ # Pack frames
+ pack $top_left_frame -side left -padx 5 -fill x
+ pack $top_right_frame -side right -padx 5
+ pack $top_frame -side top -pady 10
+ pack $bottom_frame -side bottom -fill both -expand 1
+
+ # Fill up sizes listbox
+ for {set i 4} {$i < 22} {incr i} {
+ $top_right_frame.list_box insert end $i -text $i
+ if {$i == $sample_text_size} {
+ $top_right_frame.list_box selection set $i
+ }
+ }
+
+ pack [label $bottom_frame.progress \
+ -text [mc "Searching for available fonts ..."] \
+ ]
+
+ # Fill up fonts listbox
+ after idle [subst {
+ set i 0
+ foreach font \[font families\] {
+ set font_ref \[font create -family \$font\]
+ if {!\[font metrics \$font_ref -fixed\]} {
+ font delete \$font_ref
+ continue
+ }
+ font delete \$font_ref
+
+ $top_left_frame.list_box insert end \$i -text \$font
+ if {\$font == {$sample_text_family}} {
+ $top_left_frame.list_box selection set \$i
+ }
+ incr i
+ update
+ }
+ destroy $bottom_frame.progress
+ }]
+ }
+ {highlight} { ;# Tab "Syntax highlight"
+ set highlight_notebook [ttk::notebook $highlight_tab.nb]
+ bind $highlight_notebook <<NotebookTabChanged>> {after idle {
+ set tab_index [%W index [%W select]]
+
+ if {[lsearch ${::configDialogs::editor::hn_tab_created_so_far} $tab_index] == -1} {
+ lappend ::configDialogs::editor::hn_tab_created_so_far $tab_index
+ ::configDialogs::editor::create_highlight_tab $tab_index
+ }
+ }}
+ set ::configDialogs::editor::hn_tab_created_so_far [list]
+
+ set highlight_tab_asm [frame $highlight_notebook.highlight_tab_asm]
+ $highlight_notebook add $highlight_tab_asm -text [mc "Assembler"]
+ set highlight_tab_C [frame $highlight_notebook.highlight_tab_C]
+ $highlight_notebook add $highlight_tab_C -text [mc "C language"]
+ set highlight_tab_lst [frame $highlight_notebook.highlight_tab_lst]
+ $highlight_notebook add $highlight_tab_lst -text [mc "Code listing"]
+
+ $highlight_notebook select $highlight_tab_asm
+ pack $highlight_notebook -fill both -expand 1
+ }
+ }
+ }
+
+ ## Create tab synatx highlight in notebook "Syntax highlight"
+ # @parm Int language - Highlighting pattern
+ # 0 - Assembler
+ # 1 - C language
+ # 2 - Code listing
+ # @retuer void
+ proc create_highlight_tab {language} {
+ ## General
+ variable hightlight_tags_asm ;# List: Definition of colors and styles for assembler syntax highlighting
+ variable hightlight_tags_C ;# List: Definition of colors and styles for C syntax highlighting
+ variable hightlight_tags_lst ;# List: Definition of colors and styles for LST syntax highlighting
+ variable highlight_tab_asm ;# Widget: Tab "Syntax highlight"/"Assembler"
+ variable highlight_tab_C ;# Widget: Tab "Syntax highlight"/"C language"
+ variable highlight_tab_lst ;# Widget: Tab "Syntax highlight"/"Code listing"
+
+ ## Assembler
+ variable highlight_tab_scr_text_asm ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_asm ;# ID of text widget for sample text
+ variable highlight_tab_checkbuttons_asm ;# List of checkbuttons affected by changing cursor
+ variable list_of_tags_asm ;# List: Highlighting tags
+
+ # C language
+ variable highlight_tab_scr_text_C ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_C ;# ID of text widget for sample text
+ variable highlight_tab_checkbuttons_C ;# List of checkbuttons affected by changing cursor
+ variable list_of_tags_C ;# List: Highlighting tags
+
+ # Code listing
+ variable highlight_tab_scr_text_lst ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_lst ;# ID of text widget for sample text
+ variable highlight_tab_checkbuttons_lst ;# List of checkbuttons affected by changing cursor
+ variable list_of_tags_lst ;# List: Highlighting tags
+
+ # Determinate set of highlighting tags
+ switch -- $language {
+ 0 {
+ set tab_frame $highlight_tab_asm
+ set hightlight_tags $hightlight_tags_asm
+ }
+ 1 {
+ set tab_frame $highlight_tab_C
+ set hightlight_tags $hightlight_tags_C
+ }
+ 2 {
+ set tab_frame $highlight_tab_lst
+ set hightlight_tags $hightlight_tags_lst
+ }
+ }
+
+ ## Create widgets
+ # Top frame - Contains: SCR frame (SRC header, list of tags), scrollbar
+ set highlight_tab_top_frame [frame $tab_frame.top_frame]
+ # SCR frame - Contains: SRC header, list of tags
+ set highlight_tab_scr_frm [frame $highlight_tab_top_frame.src_frm -bd 1 -relief sunken]
+ # Scrollbar (in Top frame)
+ set highlight_tab_scrollbar [ttk::scrollbar \
+ $highlight_tab_top_frame.scrollbar \
+ -orient vertical \
+ -command "$highlight_tab_scr_frm.scr_text_c yview" \
+ ]
+ # SRC header (in SCR frame)
+ set highlight_tab_scr_header [text $highlight_tab_scr_frm.scr_text_h \
+ -bd 0 -height 2 -bg {#DFDFDF} -height 1 -width 0 \
+ -cursor left_ptr -font [font create -family any -size -16] \
+ ]
+ bind $highlight_tab_scr_header <<Selection>> {false_selection %W}
+ bind $highlight_tab_scr_header <ButtonRelease-3> {break}
+ bind $highlight_tab_scr_header <Key-Menu> {break}
+ # list of tags (in SCR frame)
+ set highlight_tab_scr_text [text $highlight_tab_scr_frm.scr_text_c \
+ -bd 0 \
+ -bg {#FFFFFF} \
+ -cursor left_ptr \
+ -font ${::Editor::defaultFont_bold} \
+ -yscrollcommand "$highlight_tab_scrollbar set" \
+ -width 1 \
+ ]
+ $highlight_tab_scr_text tag configure sel_user \
+ -borderwidth 1 -background {#CCCCFF} -relief raised
+ switch -- $language {
+ 0 {set sh_ns ASMsyntaxHighlight}
+ 1 {set sh_ns CsyntaxHighlight}
+ 2 {set sh_ns LSTsyntaxHighlight}
+ }
+ ${sh_ns}::create_tags $highlight_tab_scr_text ${::Editor::fontSize} ${::Editor::fontFamily} $hightlight_tags
+ bind $highlight_tab_scr_text <<Selection>> {false_selection %W}
+ bind $highlight_tab_scr_text <ButtonRelease-3> {break}
+ bind $highlight_tab_scr_text <Key-Menu> {break}
+ bind $highlight_tab_scr_text <Button-4> "$highlight_tab_scr_text yview scroll -1 units"
+ bind $highlight_tab_scr_text <Button-5> "$highlight_tab_scr_text yview scroll +1 units"
+ # Sample text
+ set highlight_tab_scr_sample_text [text $tab_frame.scr_text_sample \
+ -bd 1 -bg {#FFFFFF} -width 0 -height 3 -maxundo 0 \
+ -wrap none -selectborderwidth 1 -highlightcolor gray \
+ ]
+ ${sh_ns}::create_tags $highlight_tab_scr_sample_text 12 $::DEFAULT_FIXED_FONT $hightlight_tags
+ bind $highlight_tab_scr_sample_text <KeyRelease> "::configDialogs::editor::parse %K $language"
+ bind $highlight_tab_scr_sample_text <ButtonPress-1> \
+ "::configDialogs::editor::syntax_sample_text_click %x %y $language"
+ switch -- $language {
+ 0 {
+ $highlight_tab_scr_sample_text insert end [join [list \
+ "FOX0 equ (100 % Xer)\n" \
+ "main: inc FOX0 ; [mc {increment some register}]\n" \
+ " sjmp main ; [mc {close main loop}]" \
+ ] {}]
+ }
+ 1 {
+ $highlight_tab_scr_sample_text insert end [join [list \
+ "/** @sa DOXYGEN <b> **/ // [mc {Comment}]\n" \
+ "unsigned int func() {\n" \
+ "\treturn 0xFA+044-58+'d'\n" \
+ "}\n" \
+ "printf(\"[mc {String}] %f\", 7.2);\n" \
+ "#define [mc {macro Some value}]\n" \
+ "#include <some_lib.h>" \
+ ] {}]
+ }
+ 2 {
+ $highlight_tab_scr_sample_text insert end [join {
+ { 0055 18 X data 55h} \
+ { =1 32 sub_0:} \
+ {0014 1122 =1 33 +1 inc A} \
+ } "\n"]
+ }
+ }
+
+ # Pack widgets
+ pack $highlight_tab_scr_header -in $highlight_tab_scr_frm -fill x -expand 1 -anchor n
+ pack $highlight_tab_scr_text -in $highlight_tab_scr_frm -fill both -expand 1
+ pack $highlight_tab_scrollbar -side right -fill y
+ pack $highlight_tab_scr_frm -side left -expand 1 -fill both
+ pack $highlight_tab_scr_sample_text -side bottom -fill x -expand 0
+ pack $highlight_tab_top_frame -side top -fill both -expand 1
+
+ # Create content of "SCR header"
+ $highlight_tab_scr_header tag configure tag_normal \
+ -font [$highlight_tab_scr_text cget -font]
+ $highlight_tab_scr_header insert end " [mc {Content}] "
+ $highlight_tab_scr_header image create end -image ::ICONS::16::text_italic -pady 0
+ $highlight_tab_scr_header insert end " "
+ $highlight_tab_scr_header image create end -image ::ICONS::16::text_strike -pady 0
+ $highlight_tab_scr_header insert end " "
+ $highlight_tab_scr_header image create end -image ::ICONS::16::text_bold -pady 0
+ $highlight_tab_scr_header insert end " [mc {Color}]"
+ $highlight_tab_scr_header configure -state disabled
+ $highlight_tab_scr_header tag add tag_normal 1.0 end
+
+ # Create content of "list of tags"
+ set row 0 ;# Number of current row
+ set list_of_tags {} ;# List of highlighting tags
+ set highlight_tab_checkbuttons {} ;# List of check buttons
+ foreach key $hightlight_tags {
+ incr row
+
+ # Local variables
+ set tag [lindex $key 0] ;# ID of the text tag
+ set content { } ;# Name of the text tag
+ set color [lindex $key 1] ;# RGB: Foreground color
+ set overstrike [lindex $key 2] ;# Bool: Overstrike
+ set italic [lindex $key 3] ;# Bool: Italic
+ set bold [lindex $key 4] ;# Bool: Bold
+
+ # Modify some variables
+ append content [mc [key2name $tag]]
+ set localButtons {}
+ lappend list_of_tags $tag
+
+ # Determinate font weight
+ if {$bold} {
+ set weight bold
+ } {
+ set weight normal
+ }
+
+ # Determinate font slant
+ if {$italic} {
+ set slant italic
+ } {
+ set slant roman
+ }
+
+ # Initialize some NS variables
+ set ::configDialogs::editor::__${language}_${row}_italic $italic
+ set ::configDialogs::editor::__${language}_${row}_overstrike $overstrike
+ set ::configDialogs::editor::__${language}_${row}_bold $bold
+
+ # Insert tag name and some '\t'
+ $highlight_tab_scr_text insert end $content
+ set len [string length $content]
+ $highlight_tab_scr_text tag add $tag \
+ [$highlight_tab_scr_text index {insert linestart}] \
+ [$highlight_tab_scr_text index insert]
+ $highlight_tab_scr_text insert end [string repeat { } [expr {24 - $len}]]
+
+ # Insert checkbutton "Italic"
+ set button [checkbutton $highlight_tab_scr_frm.italic_${row} \
+ -command "::configDialogs::editor::change_style italic $row $language" \
+ -variable ::configDialogs::editor::__${language}_${row}_italic \
+ -relief flat -pady 0 -highlightthickness 0 -bg {#FFFFFF} \
+ -activebackground {#FFFFFF} \
+ ]
+ lappend localButtons $button
+ $highlight_tab_scr_text window create end -window $button
+ $highlight_tab_scr_text insert end " "
+
+ # Insert checkbutton "Overstike"
+ set button [checkbutton $highlight_tab_scr_frm.overstrike_${row} \
+ -command "::configDialogs::editor::change_style overstrike $row $language" \
+ -variable ::configDialogs::editor::__${language}_${row}_overstrike \
+ -relief flat -pady 0 -highlightthickness 0 -bg {#FFFFFF} \
+ -activebackground {#FFFFFF} \
+ ]
+ lappend localButtons $button
+ $highlight_tab_scr_text window create end -window $button
+ $highlight_tab_scr_text insert end " "
+
+ # Insert checkbutton "Bold"
+ set button [checkbutton $highlight_tab_scr_frm.bold_${row} \
+ -command "::configDialogs::editor::change_style bold $row $language" \
+ -variable ::configDialogs::editor::__${language}_${row}_bold \
+ -relief flat -pady 0 -highlightthickness 0 -bg {#FFFFFF} \
+ -activebackground {#FFFFFF} \
+ ]
+ lappend localButtons $button
+ $highlight_tab_scr_text window create end -window $button
+ $highlight_tab_scr_text insert end " "
+
+ # Insert button "Color"
+ set button [button $highlight_tab_scr_frm.color_${row} \
+ -bd 1 -relief raised -pady 0 -highlightthickness 0 \
+ -bg $color -activebackground $color -width 3 \
+ -command "::configDialogs::editor::select_bg_color $highlight_tab_scr_frm.color_${row} $row $language" \
+ ]
+ $highlight_tab_scr_text window create end -window $button
+
+ # Insert LF
+ $highlight_tab_scr_text insert end "\n"
+
+ # Append local buttons to list of checkbuttons
+ lappend highlight_tab_checkbuttons $localButtons
+ }
+
+ # Disable text widget "List of tags" and remove last line (empty line)
+ $highlight_tab_scr_text delete end-1l end
+ $highlight_tab_scr_text configure -state disabled
+
+ # Set NS variables
+ switch -- $language {
+ 0 {
+ set highlight_tab_scr_text_asm $highlight_tab_scr_text
+ set highlight_tab_scr_sample_text_asm $highlight_tab_scr_sample_text
+ set highlight_tab_checkbuttons_asm $highlight_tab_checkbuttons
+ set list_of_tags_asm $list_of_tags
+ }
+ 1 {
+ set highlight_tab_scr_text_C $highlight_tab_scr_text
+ set highlight_tab_scr_sample_text_C $highlight_tab_scr_sample_text
+ set highlight_tab_checkbuttons_C $highlight_tab_checkbuttons
+ set list_of_tags_C $list_of_tags
+ }
+ 2 {
+ set highlight_tab_scr_text_lst $highlight_tab_scr_text
+ set highlight_tab_scr_sample_text_lst $highlight_tab_scr_sample_text
+ set highlight_tab_checkbuttons_lst $highlight_tab_checkbuttons
+ set list_of_tags_lst $list_of_tags
+ }
+ }
+
+ # Initialize syntax highlight
+ if {$language != 1} {
+ for {set i 1} {$i < int([$highlight_tab_scr_sample_text index end])} {incr i} {
+ set lineEnd [$highlight_tab_scr_sample_text index "$i.0 lineend"]
+ set lineStart $i.0
+
+ ${sh_ns}::highlight $highlight_tab_scr_sample_text $i
+ }
+ } {
+ parse {} 1
+ }
+ }
+
+ ## This function should be called always after change of $editor_to_use
+ # @return void
+ proc editor_to_use_changed {} {
+ variable nb ;# Widget: Notebook itself
+ variable editor_to_use ;# Int: Prefred editor
+ variable general_tab ;# Widget: Tab "General"
+ variable highlight_tab ;# Widget: Tab "Syntax highlight"
+
+ settings_changed
+
+ if {$editor_to_use} {
+ set state disabled
+ } {
+ set state normal
+ }
+ foreach tab [list $general_tab $highlight_tab] {
+ $nb tab $tab -state $state
+ }
+ }
+
+ ## Create some text tag in the given text widget
+ # @parm Widget text_widget - target text widget
+ # @parm Int item - index of the tag (in variable hightlight_tags)
+ # @parm Int language - Highlighting pattern
+ # 0 - Assembler
+ # 1 - C language
+ # 2 - Code listing
+ # @return void
+ proc create_tags {text_widget item language} {
+ variable hightlight_tags_asm ;# List: Definition of colors and styles for assembler syntax highlighting
+ variable hightlight_tags_C ;# List: Definition of colors and styles for C syntax highlighting
+ variable hightlight_tags_lst ;# List: Definition of colors and styles for LST syntax highlighting
+
+ # Determinate set of highlighting tags
+ switch -- $language {
+ 0 {
+ set hightlight_tags $hightlight_tags_asm
+ }
+ 1 {
+ set hightlight_tags $hightlight_tags_C
+ }
+ 2 {
+ set hightlight_tags $hightlight_tags_lst
+ }
+ }
+
+ # Gain tag definition
+ set item [lindex $hightlight_tags $item]
+ # Create array of tag attributes
+ for {set i 0} {$i < 5} {incr i} {
+ set tag($i) [lindex $item $i]
+ }
+
+ # Foreground color
+ if {$tag(1) == {}} {
+ set tag(1) black
+ }
+ # Font weight
+ if {$tag(3) == 1} {
+ set tag(3) italic
+ } {
+ set tag(3) roman
+ }
+ # Font slant
+ if {$tag(4) == 1} {
+ set tag(4) bold
+ } {
+ set tag(4) normal
+ }
+
+ # Create the tag
+ $text_widget tag configure $tag(0) \
+ -foreground $tag(1) \
+ -font [ font create \
+ -overstrike $tag(2) \
+ -slant $tag(3) \
+ -weight $tag(4) \
+ -size -12 \
+ -family $::DEFAULT_FIXED_FONT]
+ }
+
+ ## Call procedure syntax_find
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative Y coordinate
+ # @parm Int language - Highlighting pattern
+ # 0 - Assembler
+ # 1 - C language
+ # 2 - Code listing
+ # @return void
+ proc syntax_sample_text_click {x y language} {
+ variable highlight_tab_scr_sample_text_asm ;# ID of text widget for sample text
+ variable highlight_tab_scr_sample_text_C ;# ID of text widget for sample text
+ variable highlight_tab_scr_sample_text_lst ;# ID of text widget for sample text
+
+ switch -- $language {
+ 0 {set text $highlight_tab_scr_sample_text_asm}
+ 1 {set text $highlight_tab_scr_sample_text_C}
+ 2 {set text $highlight_tab_scr_sample_text_lst}
+ }
+ syntax_find [$text index @$x,$y] $language
+ }
+
+ ## Find tag used at the giuven index
+ # @parm TextIndex text_index - text index
+ # @parm Int language - Highlighting pattern
+ # 0 - Assembler
+ # 1 - C language
+ # 2 - Code listing
+ # @return void
+ proc syntax_find {text_index language} {
+ variable list_of_tags_asm ;# List: Highlighting tags
+ variable highlight_tab_checkbuttons_asm ;# List of checkbuttons affected by changing curosr
+ variable highlight_tab_scr_text_asm ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_asm ;# ID of text widget for sample text
+
+ ## Assembler
+ variable highlight_tab_scr_text_asm ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_asm ;# ID of text widget for sample text
+ variable highlight_tab_checkbuttons_asm ;# List of checkbuttons affected by changing cursor
+ variable list_of_tags_asm ;# List: Highlighting tags
+
+ # C language
+ variable highlight_tab_scr_text_C ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_C ;# ID of text widget for sample text
+ variable highlight_tab_checkbuttons_C ;# List of checkbuttons affected by changing cursor
+ variable list_of_tags_C ;# List: Highlighting tags
+
+ # Code listing
+ variable highlight_tab_scr_text_lst ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_lst ;# ID of text widget for sample text
+ variable highlight_tab_checkbuttons_lst ;# List of checkbuttons affected by changing cursor
+ variable list_of_tags_lst ;# List: Highlighting tags
+
+
+ # Determinate set of highlighting tags
+ switch -- $language {
+ 0 {
+ set list_of_tags $list_of_tags_asm
+ set highlight_tab_checkbuttons $highlight_tab_checkbuttons_asm
+ set highlight_tab_scr_text $highlight_tab_scr_text_asm
+ set highlight_tab_scr_sample_text $highlight_tab_scr_sample_text_asm
+ }
+ 1 {
+ set list_of_tags $list_of_tags_C
+ set highlight_tab_checkbuttons $highlight_tab_checkbuttons_C
+ set highlight_tab_scr_text $highlight_tab_scr_text_C
+ set highlight_tab_scr_sample_text $highlight_tab_scr_sample_text_C
+ }
+ 2 {
+ set list_of_tags $list_of_tags_lst
+ set highlight_tab_checkbuttons $highlight_tab_checkbuttons_lst
+ set highlight_tab_scr_text $highlight_tab_scr_text_lst
+ set highlight_tab_scr_sample_text $highlight_tab_scr_sample_text_lst
+ }
+ }
+
+ # Remove previous selection
+ if {[$highlight_tab_scr_text tag ranges {sel_user}] != {}} {
+ set index [$highlight_tab_scr_text index sel_user.first]
+ set buttons [lindex $highlight_tab_checkbuttons [expr {int($index) - 1}]]
+ foreach button $buttons {
+ $button configure -bg {#FFFFFF} -activebackground {#FFFFFF}
+ }
+ $highlight_tab_scr_text tag remove sel_user 1.0 end
+ }
+
+ # Determinate tag name
+ set index [$highlight_tab_scr_sample_text index $text_index]
+ set index [$highlight_tab_scr_sample_text tag names $index]
+
+ # If the tag could not be determinated -> abort
+ set index [lindex $index 0]
+ if {$index == {}} {return}
+
+ # Determinate tag number
+ set index [lsearch $list_of_tags $index]
+ if {$index == -1} {return}
+
+ # Change background color for checkbuttons related to the tag
+ set buttons [lindex $highlight_tab_checkbuttons $index]
+ foreach button $buttons {
+ $button configure -bg {#CCCCFF} -activebackground {#CCCCFF}
+ }
+
+ # Select row related to the tag
+ incr index
+ $highlight_tab_scr_text tag add sel_user $index.0 [expr {$index + 1}].0
+ $highlight_tab_scr_text see $index.0
+ }
+
+ ## Manages syntax highlighting in sample text
+ # @parm String key - ID of the released key
+ # @parm Int language - Highlighting pattern
+ # 0 - Assembler
+ # 1 - C language
+ # 2 - Code listing
+ # @return void
+ proc parse {key language} {
+ variable highlight_tab_scr_sample_text_asm ;# ID of text widget for sample text
+ variable highlight_tab_scr_sample_text_C ;# ID of text widget for sample text
+ variable highlight_tab_scr_sample_text_lst ;# ID of text widget for sample text
+
+ switch -- $language {
+ 0 {
+ set widget $highlight_tab_scr_sample_text_asm
+ }
+ 1 {
+ set widget $highlight_tab_scr_sample_text_C
+ }
+ 2 {
+ set widget $highlight_tab_scr_sample_text_lst
+ }
+ }
+
+ # Keep indentication level after line break
+ if {$key == "KP_Enter" || $key == "Return"} {
+ # Get content of previous line
+ set prev_line [$widget get \
+ [$widget index {insert - 1 line linestart}] \
+ [$widget index {insert - 1 line lineend}] \
+ ]
+
+ # Determinate indentication characters
+ set indent_chars {}
+ regexp {^\s+} $prev_line indent_chars
+
+ # Insert indentication characters
+ if {$indent_chars != {}} {
+ $widget insert $lineNumber.0 $indent_chars
+ }
+ }
+
+ # Syntax highlight for assembler or code listing
+ if {$language == 0 && $language == 2} {
+ # Highlight current line
+ if {[lsearch {
+ Left Right Down Up Insert Home Prior
+ End Next Shift_R Control_R Alt_L Alt_R
+ Control_L Shift_L Escape
+ } $key] == -1} {
+ if {$language == 0} {
+ ASMsyntaxHighlight::highlight $widget $lineNumber
+ } {
+ LSTsyntaxHighlight::highlight $widget $lineNumber
+ }
+ }
+
+ # Syntax highlight for C language
+ } {
+ # Highlight all lines
+ if {[lsearch {
+ Left Right Down Up Insert Home Prior
+ End Next Shift_R Control_R Alt_L Alt_R
+ Control_L Shift_L Escape
+ } $key] == -1} {
+ set status 1
+ set end_line [expr {int([$widget index end])}]
+ for {set line 0} {$line < $end_line} {incr line} {
+ set status [CsyntaxHighlight::highlight \
+ $widget $line $status \
+ ]
+ }
+ }
+ }
+
+ # Change selection in "Tag List"
+ syntax_find [$widget index insert] $language
+ }
+
+ ## Change font family for sample text entry in tab "Fonts"
+ # @parm Widget widget - source listbox
+ # @parm String item - ID of current item in source listbox
+ # @return void
+ proc select_font_family {widget item} {
+ variable sample_text ;# ID of text widget for sample text
+ variable sample_text_size ;# Font size
+ variable sample_text_family ;# Font family
+
+ # Select item in the lisbox
+ set sample_text_family [$widget itemcget $item -text]
+ $widget selection set $item
+
+ # Change font in sample text
+ $sample_text configure -font [font create \
+ -family $sample_text_family \
+ -size -$sample_text_size]
+
+ # Adjust status changed
+ settings_changed
+ }
+
+ ## Change font size for sample text entry in tab "Fonts"
+ # @parm Widget widget - source listbox
+ # @parm String item - ID of current item in source listbox
+ # @return void
+ proc select_font_size {widget item} {
+ variable sample_text ;# ID of text widget for sample text
+ variable sample_text_size ;# Font size
+ variable sample_text_family ;# Font family
+
+ # Select item in the lisbox
+ set sample_text_size $item
+ $widget selection set $item
+
+ # Change font in sample text
+ $sample_text configure -font [font create \
+ -family $sample_text_family \
+ -size -$sample_text_size \
+ ]
+
+ # Adjust status changed
+ settings_changed
+ }
+
+ ## Change font style in sample text and list of tags in tab "Syntax highlight"
+ # @parm String what - ID of style
+ # @parm Int row - number of row in "List of tags"
+ # @parm Int language - Highlighting pattern
+ # 0 - Assembler
+ # 1 - C language
+ # 2 - Code listing
+ # @return void
+ proc change_style {what row language} {
+ variable hightlight_tags_asm ;# List: Definition of colors and styles for assembler syntax highlighting
+ variable hightlight_tags_C ;# List: Definition of colors and styles for C syntax highlighting
+ variable hightlight_tags_lst ;# List: Definition of colors and styles for LST syntax highlighting
+
+ variable highlight_tab_scr_text_C ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_C ;# ID of text widget for sample text
+ variable highlight_tab_scr_text_asm ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_asm ;# ID of text widget for sample text
+ variable highlight_tab_scr_text_lst ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_lst ;# ID of text widget for sample text
+
+
+ incr row -1
+
+ # Determinate set of highlighting tags and text widget
+ switch -- $language {
+ 0 {
+ set highlight_tab_scr_sample_text $highlight_tab_scr_sample_text_asm
+ set highlight_tab_scr_text $highlight_tab_scr_text_asm
+ set hightlight_tags hightlight_tags_asm
+ }
+ 1 {
+ set highlight_tab_scr_sample_text $highlight_tab_scr_sample_text_C
+ set highlight_tab_scr_text $highlight_tab_scr_text_C
+ set hightlight_tags hightlight_tags_C
+ }
+ 2 {
+ set highlight_tab_scr_sample_text $highlight_tab_scr_sample_text_lst
+ set highlight_tab_scr_text $highlight_tab_scr_text_lst
+ set hightlight_tags hightlight_tags_lst
+ }
+ }
+
+ # Decide what to change
+ switch -- $what {
+ overstrike {
+ lset $hightlight_tags "$row 2" \
+ [subst "\${::configDialogs::editor::__${language}_[expr {$row + 1}]_overstrike}"]
+ }
+ italic {
+ lset $hightlight_tags "$row 3" \
+ [subst "\${::configDialogs::editor::__${language}_[expr {$row + 1}]_italic}"]
+ }
+ bold {
+ lset $hightlight_tags "$row 4" \
+ [subst "\${::configDialogs::editor::__${language}_[expr {$row + 1}]_bold}"]
+ }
+ default {return}
+ }
+
+ # Change tags
+ create_tags $highlight_tab_scr_sample_text $row $language
+ create_tags $highlight_tab_scr_text $row $language
+
+ # Adjust status changed
+ settings_changed
+ }
+
+ ## Validate content of nofs_spinbox
+ # @parm String content - content to validate
+ # @return Bool - success
+ proc nofs_spinbox_val {content} {
+ if {![string is digit $content]} {
+ return 0
+ }
+ if {$content > 16 || $content < 1} {
+ return 0
+ }
+ return 1
+ }
+
+ ## Change font color in sample text and list of tags in tab "Syntax highlight"
+ # @parm Widget button - ID of the button used to change the color
+ # @parm Int row - number of row in "List of tags"
+ # @parm Int language - Highlighting pattern
+ # 0 - Assembler
+ # 1 - C language
+ # 2 - Code listing
+ # @return void
+ proc select_bg_color {button row language} {
+ variable win ;# ID of dialog toplevel window
+ variable hightlight_tags_asm ;# List: Definition of colors and styles for assembler syntax highlighting
+ variable hightlight_tags_C ;# List: Definition of colors and styles for C syntax highlighting
+ variable hightlight_tags_lst ;# List: Definition of colors and styles for LST syntax highlighting
+
+ variable highlight_tab_scr_text_asm ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_asm ;# ID of text widget for sample text
+ variable highlight_tab_scr_text_C ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_C ;# ID of text widget for sample text
+ variable highlight_tab_scr_text_lst ;# ID of text widget for configuring syntax
+ variable highlight_tab_scr_sample_text_lst ;# ID of text widget for sample text
+
+ # Determinate set of highlighting tags
+ switch -- $language {
+ 0 {
+ set highlight_tab_scr_sample_text $highlight_tab_scr_sample_text_asm
+ set highlight_tab_scr_text $highlight_tab_scr_text_asm
+ set hightlight_tags_var hightlight_tags_asm
+ set hightlight_tags $hightlight_tags_asm
+ }
+ 1 {
+ set highlight_tab_scr_sample_text $highlight_tab_scr_sample_text_C
+ set highlight_tab_scr_text $highlight_tab_scr_text_C
+ set hightlight_tags_var hightlight_tags_C
+ set hightlight_tags $hightlight_tags_C
+ }
+ 2 {
+ set highlight_tab_scr_sample_text $highlight_tab_scr_sample_text_lst
+ set highlight_tab_scr_text $highlight_tab_scr_text_lst
+ set hightlight_tags_var hightlight_tags_lst
+ set hightlight_tags $hightlight_tags_lst
+ }
+ }
+
+ incr row -1
+
+ # Destroy prevoisly opened color selection dialog
+ if {[winfo exists .select_color]} {
+ destroy .select_color
+ }
+
+ # Invoke new color selection dialog
+ set color [lindex $hightlight_tags "$row 1"]
+ set color [SelectColor .select_color \
+ -parent $win \
+ -color $color \
+ -title [mc "Select color - %s" ${::APPNAME}] \
+ ]
+
+ # Change button background color
+ if {$color != {}} {
+ lset $hightlight_tags_var "$row 1" $color
+ $button configure -bg $color -activebackground $color
+ }
+
+ # Change tags
+ create_tags $highlight_tab_scr_sample_text $row $language
+ create_tags $highlight_tab_scr_text $row $language
+
+ # Adjust status changed
+ settings_changed
+ }
+
+ ## Translate Tk tag name to human readable string
+ # @parm String key - tag name
+ # @return String - result
+ proc key2name {key} {
+ switch -- $key {
+ tag_char {return {Char}}
+ tag_hex {return {Hexadecimal number}}
+ tag_oct {return {Octal number}}
+ tag_dec {return {Decimal number}}
+ tag_bin {return {Binary number}}
+ tag_constant {return {Constant}}
+ tag_unknown_base {return {Generic number}}
+ tag_string {return {String}}
+ tag_comment {return {Comment}}
+ tag_control {return {Control sequence}}
+ tag_symbol {return {Symbol}}
+ tag_oper_sep {return {Operand separator}}
+ tag_directive {return {Directive}}
+ tag_label {return {Label}}
+ tag_instruction {return {Instruction}}
+ tag_sfr {return {SFR register}}
+ tag_indirect {return {Indirect adress}}
+ tag_imm_char {return {Immediate char}}
+ tag_imm_hex {return {Immediate hex}}
+ tag_imm_oct {return {Immediate oct}}
+ tag_imm_dec {return {Immediate dec}}
+ tag_imm_bin {return {Immediate bin}}
+ tag_imm_constant {return {Immediate const}}
+ tag_imm_unknown {return {Immediate generic}}
+ tag_macro {return {Macro instruction}}
+
+ tag_c_keyword {return {Keyword}}
+ tag_c_data_type {return {Data type}}
+ tag_c_dec {return {Decimal}}
+ tag_c_hex {return {Hexadecimal}}
+ tag_c_oct {return {Octal}}
+ tag_c_char {return {Char}}
+ tag_c_float {return {Float}}
+ tag_c_string {return {String}}
+ tag_c_string_char {return {String char}}
+ tag_c_comment {return {Comment}}
+ tag_c_symbol {return {Symbol}}
+ tag_c_bracket {return {Bracket}}
+ tag_c_preprocessor {return {Preprocessor}}
+ tag_c_directive {return {Directive}}
+ tag_c_prep_lib {return {Preprocessor lib.}}
+ tag_normal {return {Normal text}}
+ tag_c_dox_comment {return {Doxygen: Comment}}
+ tag_c_dox_tag {return {Doxygen: Tag}}
+ tag_c_dox_word {return {Doxygen: Word}}
+ tag_c_dox_name {return {Doxygen: Name}}
+ tag_c_dox_html {return {Doxygen: HTML}}
+ tag_c_dox_harg {return {Doxygen: HTML arg.}}
+ tag_c_dox_hargval {return {Doxygen: HTML val.}}
+
+ tag_lst_number {return {Value}}
+ tag_lst_code {return {Processor code}}
+ tag_lst_address {return {Address}}
+ tag_lst_line {return {Line number}}
+ tag_lst_macro {return {Macro level}}
+ tag_lst_include {return {Inclusion level}}
+ tag_lst_error {return {Error / Warning}}
+ tag_lst_msg {return {Message}}
+ }
+ }
+
+
+ ## Create button for selecting some color (used in tab "Colors")
+ # @parm Widget parent - parent frame
+ # @parm Variable variable - variable containg button background color (RGB format)
+ # @parm String name - button name (used in GUI path)
+ # @parm String text - text showed beside the button
+ # @return void
+ proc mk_button_select_menu {parent variable name text} {
+ variable row ;# General purpose variable (some row somewhere)
+ variable win ;# ID of dialog toplevel window
+ variable button_index ;# Button index (for creating many buttons)
+
+ # Get color from the given variable
+ set color [subst "\${$variable}"]
+
+ # Create button label
+ grid [label $parent.${name}${button_index} \
+ -text $text \
+ -anchor w -bd 0 -relief raised \
+ -pady 0 -highlightthickness 0 \
+ ] -column 1 -row $row -sticky we
+ # Create button
+ set button [button $parent.but_normal_text$button_index \
+ -bd 1 -relief raised -pady 0 -highlightthickness 0 \
+ -bg $color -width 10 -activebackground $color \
+ -command "::configDialogs::editor::select_color $variable $parent.but_normal_text$button_index"
+ ]
+
+ # Show button
+ grid $button -column 2 -row $row -sticky ns -padx 10
+
+ # Adjust button index and current row
+ incr button_index
+ incr row
+ }
+
+ ## Select some color (command for buttons in tab "Colors")
+ # @parm Variable variable - variable containing current color (format RGB)
+ # @parm Widget button - ID of button which invoked this procedure
+ # @return void
+ proc select_color {variable button} {
+ variable win ;# ID of dialog toplevel window
+
+ # Destroy previously opened color selection dialog
+ if {[winfo exists .select_color]} {
+ destroy .select_color
+ }
+
+ # Invoke new color selection dialog
+ set color [subst "\$$variable"]
+ set color [SelectColor .select_color \
+ -parent $win \
+ -color $color \
+ -title [mc "Select color - %s" ${::APPNAME}] \
+ ]
+
+ # Set new content of the given variable and button background color
+ if {$color != {}} {
+ set $variable $color
+ $button configure -bg $color -activebackground $color
+
+ # Adjust status changed
+ settings_changed
+ }
+ }
+
+ ## Retrieve settings related to this dialog from the program
+ # @return void
+ proc getSettings {} {
+ variable editor_to_use ;# Int: Prefred editor
+ variable default_encoding ;# Default encoding for opening files
+ variable default_eol ;# Default EOL character
+ variable intentation_mode ;# Editor indentation mode
+ variable spaces_no_tabs ;# Bool: Use spaces instead of tabs
+ variable number_of_spaces ;# Number of spaces to use instead of tab
+ variable autosave ;# Int: Autosave interval in minutes (0 == disabled)
+ variable auto_completion ;# Bool: Enable popup-base completion
+ variable cline_completion ;# Bool: Enable popup-based completion for command line
+ variable auto_brackets ;# Automaticaly insert oposite brackets, quotes, etc.
+ variable hg_trailing_sp ;# Bool: Highlight trailing space
+
+ variable color_normal_text ;# RGB: Editor backgound color
+ variable color_selected_text ;# RGB: Backgound color for selected text
+ variable color_current_line ;# RGB: Backgound color for current line
+ variable color_bookmark ;# RGB: Backgound color for bookmarks
+ variable color_breakpoint ;# RGB: Backgound color for breakpoints
+ variable color_simulator_line ;# RGB: Backgound color for simulator line
+ variable color_error_line ;# RGB: Backgound color for line containing an error
+ variable color_trailing_space ;# RGB: Backgound color for trailing space
+
+ variable color_iconBorder_bg ;# RGB: Backgound color for icon border
+ variable color_lineNumbers_bg ;# RGB: Backgound color for line numbers
+ variable color_lineNumbers_fg ;# RGB: Foregound color for line numbers
+
+ variable sample_text_size ;# Font size
+ variable sample_text_family ;# Font family
+ variable hightlight_tags_asm ;# List: Definition of colors and styles for assembler syntax highlighting
+ variable hightlight_tags_C ;# List: Definition of colors and styles for C syntax highlighting
+ variable hightlight_tags_lst ;# List: Definition of colors and styles for LST syntax highlighting
+
+
+ # Get highlighting tags
+ set hightlight_tags_asm ${::ASMsyntaxHighlight::hightlight_tags}
+ set hightlight_tags_C ${::CsyntaxHighlight::hightlight_tags}
+ set hightlight_tags_lst ${::LSTsyntaxHighlight::hightlight_tags}
+
+ # Get data from editor NS
+ set intentation_mode [mc ${Editor::intentation_mode}]
+ set spaces_no_tabs ${Editor::spaces_no_tabs}
+ set number_of_spaces ${Editor::number_of_spaces}
+ set auto_completion ${Editor::auto_completion}
+ set cline_completion ${Editor::cline_completion}
+ set autosave ${Editor::autosave}
+ set auto_brackets ${Editor::auto_brackets}
+ set hg_trailing_sp ${Editor::hg_trailing_sp}
+ set sample_text_size ${Editor::fontSize}
+ set sample_text_family ${Editor::fontFamily}
+ set color_normal_text ${Editor::normal_text_bg}
+ set color_iconBorder_bg ${Editor::iconBorder_bg}
+ set color_lineNumbers_bg ${Editor::lineNumbers_bg}
+ set color_lineNumbers_fg ${Editor::lineNumbers_fg}
+ set editor_to_use [::settings getValue \
+ "Editor config/editor_to_use" ${Editor::editor_to_use} \
+ ]
+
+ # Get data from filelist NS
+ set default_encoding ${FileList::default_encoding}
+ set default_eol ${FileList::default_eol}
+
+ foreach record ${::Editor::line_markers} {
+ set key [lindex $record 0]
+ set val [lindex $record 1]
+
+ switch -- $key {
+ {sel} {
+ set color_selected_text $val
+ }
+ {tag_current_line} {
+ set color_current_line $val
+ }
+ {tag_bookmark} {
+ set color_bookmark $val
+ }
+ {tag_breakpoint} {
+ set color_breakpoint $val
+ }
+ {tag_simulator_curr} {
+ set color_simulator_line $val
+ }
+ {tag_error_line} {
+ set color_error_line $val
+ }
+ {tag_trailing_space} {
+ set color_trailing_space $val
+ }
+ }
+ }
+ }
+
+ ## Change content of configuration variables in Editor NS, Filelist NS and SyntaxHighlight NS
+ # @return void
+ proc use_settings {} {
+ variable autocompletion_turned_on
+
+ variable default_encoding ;# Default encoding for opening files
+ variable default_eol ;# Default EOL character
+ variable intentation_mode ;# Editor indentation mode
+ variable spaces_no_tabs ;# Bool: Use spaces instead of tabs
+ variable number_of_spaces ;# Number of spaces to use instead of tab
+ variable autosave ;# Int: Autosave interval in minutes (0 == disabled)
+ variable auto_completion ;# Bool: Enable popup-base completion
+ variable cline_completion ;# Bool: Enable popup-based completion for command line
+ variable auto_brackets ;# Automaticaly insert oposite brackets, quotes, etc.
+ variable hg_trailing_sp ;# Bool: Highlight trailing space
+
+ variable editor_to_use ;# Int: Prefred editor
+ variable color_normal_text ;# RGB: Editor backgound color
+ variable color_selected_text ;# RGB: Backgound color for selected text
+ variable color_current_line ;# RGB: Backgound color for current line
+ variable color_bookmark ;# RGB: Backgound color for bookmarks
+ variable color_breakpoint ;# RGB: Backgound color for breakpoints
+ variable color_simulator_line ;# RGB: Backgound color for simulator line
+ variable color_error_line ;# RGB: Backgound color for line containing an error
+ variable color_trailing_space ;# RGB: Backgound color for trailing space
+
+ variable color_iconBorder_bg ;# RGB: Backgound color for icon border
+ variable color_lineNumbers_bg ;# RGB: Backgound color for line numbers
+ variable color_lineNumbers_fg ;# RGB: Foregound color for line numbers
+
+ variable sample_text_size ;# Font size
+ variable sample_text_family ;# Font family
+ variable hightlight_tags_asm ;# List: Definition of colors and styles for assembler syntax highlighting
+ variable hightlight_tags_C ;# List: Definition of colors and styles for C syntax highlighting
+ variable hightlight_tags_lst ;# List: Definition of colors and styles for LST syntax highlighting
+
+ if {!$Editor::auto_completion && $auto_completion} {
+ set autocompletion_turned_on 1
+ } {
+ set autocompletion_turned_on 0
+ }
+
+ ## Filelist
+ set FileList::default_encoding $default_encoding
+ set FileList::default_eol $default_eol
+
+ ## Editor
+ set Editor::intentation_mode [mc $intentation_mode]
+ set Editor::spaces_no_tabs $spaces_no_tabs
+ set Editor::auto_brackets $auto_brackets
+ set Editor::hg_trailing_sp $hg_trailing_sp
+ set Editor::auto_completion $auto_completion
+ set Editor::cline_completion $cline_completion
+ set Editor::autosave $autosave
+ set Editor::normal_text_bg $color_normal_text
+ set Editor::iconBorder_bg $color_iconBorder_bg
+ set Editor::lineNumbers_bg $color_lineNumbers_bg
+ set Editor::lineNumbers_fg $color_lineNumbers_fg
+ set Editor::fontSize $sample_text_size
+ set Editor::fontFamily $sample_text_family
+
+ if {$number_of_spaces != {}} {
+ set Editor::number_of_spaces $number_of_spaces
+ } {
+ set Editor::number_of_spaces 8
+ }
+
+ set Editor::line_markers [list \
+ "sel $color_selected_text" \
+ "tag_current_line $color_current_line" \
+ "tag_bookmark $color_bookmark" \
+ "tag_breakpoint $color_breakpoint" \
+ "tag_simulator_curr $color_simulator_line" \
+ "tag_error_line $color_error_line" \
+ "tag_trailing_space $color_trailing_space"]
+
+ set Editor::defaultFont [font create \
+ -size -$sample_text_size \
+ -family $sample_text_family \
+ ]
+ set Editor::defaultFont_bold [font create \
+ -size -$sample_text_size \
+ -family $sample_text_family \
+ -weight {bold} \
+ ]
+
+ ## Syntax highlight
+ set ::ASMsyntaxHighlight::hightlight_tags $hightlight_tags_asm
+ set ::CsyntaxHighlight::hightlight_tags $hightlight_tags_C
+ set ::LSTsyntaxHighlight::hightlight_tags $hightlight_tags_lst
+ }
+
+ ## Adjust all editors to fit new settings
+ # @return Bool - result
+ proc apply_settings {} {
+ variable autocompletion_turned_on
+
+ # Check if there is at least 1 opened editor
+ if {[llength ${X::openedProjects}] == 0} {
+ return 0
+ }
+
+ # Iterate over projects
+ foreach project ${::X::openedProjects} {
+
+ # Refresh font settings in right panel
+ $project rightPanel_refresh_font_settings 1
+
+ # Adjust tab bar
+ $project show_hide_tab_bar
+
+ # Refresh font settings in all editors
+ foreach editor [$project cget -editors] {
+ $editor change_colors
+ $editor refresh_font_settings
+ $editor define_line_markers
+ if {$autocompletion_turned_on} {
+ $editor autocompletion_turned_on
+ }
+ ASMsyntaxHighlight::create_tags \
+ [$editor cget -editor] \
+ ${Editor::fontSize} \
+ ${Editor::fontFamily}
+ CsyntaxHighlight::create_tags \
+ [$editor cget -editor] \
+ ${Editor::fontSize} \
+ ${Editor::fontFamily}
+ }
+ }
+
+ # done ...
+ return 1
+ }
+
+ ## Set status changed to True
+ # @return true
+ proc settings_changed {} {
+ variable changed ;# Bool: Settings changed
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable apply_button ;# ID of button "Apply"
+
+ if {$changed} {return}
+
+ set changed 1
+ set anything_modified 1
+ $apply_button configure -state normal
+ }
+
+ ## Take back changes and destroy dialog window
+ # @return void
+ proc CANCEL {} {
+ variable win ;# ID of dialog toplevel window
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Restore previous configuration
+ if {$anything_modified} {
+ load_config
+ apply_settings
+ set anything_modified 0
+ }
+
+ # Get rid of dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Apply changes and destroy dialog window
+ # @return void
+ proc OK {} {
+ variable win ;# ID of dialog toplevel window
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Apply new settings
+ if {$anything_modified} {
+ use_settings ;# Adjust NS variables
+ apply_settings ;# Adjust GUI
+ save_config ;# Save new config
+ }
+
+ # Get rid of dialog window
+ grab release $win
+ set dialog_opened 0
+ destroy $win
+ }
+
+ ## Apply changes in GUI
+ # @return Bool - result
+ proc APPLY {} {
+ variable apply_button ;# ID of button "Apply"
+ variable changed ;# Bool: Settings changed
+
+ # Check if there is at least 1 opened editor
+ if {[llength ${X::openedProjects}] == 0} {
+ return 0
+ }
+
+ # Reset status changed
+ set changed 0
+ $apply_button configure -state disabled
+
+ # Adjust NS variables
+ use_settings
+
+ ## Apply settings in current editor
+ set actualEditor [${X::actualProject} cget -actualEditor]
+ set actualEditor2 [${X::actualProject} cget -actualEditor2]
+ ${X::actualProject} show_hide_tab_bar
+ ${X::actualProject} rightPanel_refresh_font_settings 0
+ ${X::actualProject} editor_procedure $actualEditor change_colors {}
+ ${X::actualProject} editor_procedure $actualEditor refresh_font_settings {}
+ ${X::actualProject} editor_procedure $actualEditor define_line_markers {}
+ if {$actualEditor2 >= 0} {
+ ${X::actualProject} editor_procedure $actualEditor2 change_colors {}
+ ${X::actualProject} editor_procedure $actualEditor2 refresh_font_settings {}
+ ${X::actualProject} editor_procedure $actualEditor2 define_line_markers {}
+ }
+ set editors [${X::actualProject} cget -editors]
+ ASMsyntaxHighlight::create_tags [[lindex $editors $actualEditor] cget -editor] \
+ ${Editor::fontSize} ${Editor::fontFamily}
+ CsyntaxHighlight::create_tags [[lindex $editors $actualEditor] cget -editor] \
+ ${Editor::fontSize} ${Editor::fontFamily}
+ LSTsyntaxHighlight::create_tags [[lindex $editors $actualEditor] cget -editor] \
+ ${Editor::fontSize} ${Editor::fontFamily}
+ if {$actualEditor2 >= 0} {
+ ASMsyntaxHighlight::create_tags [[lindex $editors $actualEditor2] cget -editor] \
+ ${Editor::fontSize} ${Editor::fontFamily}
+ CsyntaxHighlight::create_tags [[lindex $editors $actualEditor2] cget -editor] \
+ ${Editor::fontSize} ${Editor::fontFamily}
+ LSTsyntaxHighlight::create_tags [[lindex $editors $actualEditor2] cget -editor] \
+ ${Editor::fontSize} ${Editor::fontFamily}
+ }
+
+ # done ...
+ return 1
+ }
+
+ ## Save configuration to config file
+ # @return void
+ proc save_config {} {
+ variable editor_to_use ;# Int: Prefred editor
+
+ # Section "Syntax highlight"
+ foreach item [concat \
+ ${::ASMsyntaxHighlight::hightlight_tags} \
+ ${::CsyntaxHighlight::hightlight_tags} \
+ ${::LSTsyntaxHighlight::hightlight_tags} \
+ ] {
+ set key [lindex $item 0]
+ set value [lrange $item 1 end]
+ ::settings setValue "Syntax highlight/$key" $value
+ }
+
+ # Section "Editor colors"
+ foreach key {
+ normal_text_bg iconBorder_bg lineNumbers_bg lineNumbers_fg
+ fontSize fontFamily line_markers
+ } {
+ ::settings setValue "Editor colors/$key" [subst "\$::Editor::$key"]
+ }
+
+ # Section "Editor config"
+ foreach key {
+ intentation_mode spaces_no_tabs
+ number_of_spaces auto_brackets
+ auto_completion autosave
+ cline_completion hg_trailing_sp
+ } {
+ ::settings setValue "Editor config/$key" [subst "\$::Editor::$key"]
+ }
+ ::settings setValue "Editor config/default_encoding" ${::FileList::default_encoding}
+ ::settings setValue "Editor config/default_eol" ${::FileList::default_eol}
+ ::settings setValue "Editor config/editor_to_use" $editor_to_use
+
+ # Commit
+ ::settings saveConfig
+ }
+
+ ## Load configuration from config file
+ # @return void
+ proc load_config {} {
+ variable avaliable_encodings ;# Encodings supported by editor
+
+ ## Section "Syntax highlight"
+ # Assembler
+ set hightlight_tags {}
+ foreach item ${::ASMsyntaxHighlight::hightlight_tags} {
+ set key [lindex $item 0]
+ set value [lrange $item 1 end]
+ set value [::settings getValue "Syntax highlight/$key" $value]
+ lappend hightlight_tags "$key $value"
+ }
+ set ::ASMsyntaxHighlight::hightlight_tags $hightlight_tags
+ # C language
+ set hightlight_tags {}
+ foreach item ${::CsyntaxHighlight::hightlight_tags} {
+ set key [lindex $item 0]
+ set value [lrange $item 1 end]
+ set value [::settings getValue "Syntax highlight/$key" $value]
+ lappend hightlight_tags "$key $value"
+ }
+ set ::CsyntaxHighlight::hightlight_tags $hightlight_tags
+ unset hightlight_tags
+ # Code listing
+ set hightlight_tags {}
+ foreach item ${::LSTsyntaxHighlight::hightlight_tags} {
+ set key [lindex $item 0]
+ set value [lrange $item 1 end]
+ set value [::settings getValue "Syntax highlight/$key" $value]
+ lappend hightlight_tags "$key $value"
+ }
+ set ::LSTsyntaxHighlight::hightlight_tags $hightlight_tags
+ unset hightlight_tags
+
+ # Section "Editor config"
+ foreach key {
+ intentation_mode spaces_no_tabs
+ number_of_spaces auto_brackets
+ auto_completion autosave
+ cline_completion editor_to_use
+ hg_trailing_sp
+ } {
+ set value [subst "\$::Editor::$key"]
+ set value [::settings getValue "Editor config/$key" $value]
+ set ::Editor::$key $value
+ }
+ if {
+ ![string is integer ${::Editor::editor_to_use}]
+ ||
+ ${::Editor::editor_to_use} < 0
+ ||
+ ${::Editor::editor_to_use} > 5
+ } {
+ set ::Editor::editor_to_use 0
+ puts stderr [mc "Invalid key: '%s'" {editor_to_use}]
+ } elseif {${::Editor::editor_to_use}} {
+ if {!${::PROGRAM_AVALIABLE(urxvt)}} {
+ puts stderr [mc "Unable to use external embedded editor because rxvt-unicode is not avaliable"]
+ set ::Editor::editor_to_use 0
+ } {
+ switch -- ${::Editor::editor_to_use} {
+ 1 {set program {vim} }
+ 2 {set program {emacs} }
+ 3 {set program {nano} }
+ 4 {set program {dav} }
+ 5 {set program {le} }
+ }
+ if {!$::PROGRAM_AVALIABLE($program)} {
+ puts stderr [mc "Program %s is not avaliable. Using native editor." $program]
+ set ::Editor::editor_to_use 0
+ }
+ }
+ }
+ if {![string is boolean -strict ${::Editor::spaces_no_tabs}]} {
+ set FileList::spaces_no_tabs 0
+ puts stderr [mc "Invalid key: '%s'" {spaces_no_tabs}]
+ }
+ if {![string is boolean -strict ${::Editor::auto_brackets}]} {
+ set FileList::auto_brackets 1
+ puts stderr [mc "Invalid key: '%s'" {auto_brackets}]
+ }
+ if {![string is boolean -strict ${::Editor::hg_trailing_sp}]} {
+ set FileList::hg_trailing_sp 1
+ puts stderr [mc "Invalid key: '%s'" {hg_trailing_sp}]
+ }
+ if {![string is digit -strict ${::Editor::autosave}]} {
+ set Editor::autosave 0
+ puts stderr [mc "Invalid key: '%s'" {autosave}]
+ } {
+ if {${::Editor::autosave} > 60 || ${::Editor::autosave} < 0} {
+ set Editor::number_of_spaces 0
+ puts stderr [mc "Invalid key: '%s'" {autosave}]
+ }
+ }
+ if {![string is digit -strict ${::Editor::number_of_spaces}]} {
+ set FileList::number_of_spaces 8
+ puts stderr [mc "Invalid key: '%s'" {number_of_spaces}]
+ } {
+ if {${::Editor::number_of_spaces} > 16 || ${::Editor::number_of_spaces} < 1} {
+ set FileList::number_of_spaces 8
+ puts stderr [mc "Invalid key: '%s'" {number_of_spaces}]
+ }
+ }
+ if {![string is boolean -strict ${::Editor::auto_completion}]} {
+ set FileList::auto_completion 1
+ puts stderr [mc "Invalid key: '%s'" {auto_completion}]
+ }
+ if {![string is boolean -strict ${::Editor::cline_completion}]} {
+ set FileList::cline_completion 1
+ puts stderr [mc "Invalid key: '%s'" {cline_completion}]
+ }
+ if {
+ ${::Editor::intentation_mode} != {none}
+ &&
+ ${::Editor::intentation_mode} != {normal}
+ } {
+ set FileList::intentation_mode {normal}
+ puts stderr [mc "Invalid key: '%s'" {intentation_mode}]
+ }
+
+ set FileList::default_encoding [::settings getValue \
+ "Editor config/default_encoding" {utf-8}]
+ if {[lsearch $avaliable_encodings ${FileList::default_encoding}] == -1} {
+ set FileList::default_encoding {utf-8}
+ puts stderr [mc "Invalid key: '%s'" {default_encoding}]
+ }
+
+ set FileList::default_eol [::settings getValue \
+ "Editor config/default_eol" {lf}]
+ if {
+ ${FileList::default_eol} != {lf} &&
+ ${FileList::default_eol} != {cr} &&
+ ${FileList::default_eol} != {crlf}
+ } {
+ set FileList::default_eol {lf}
+ puts stderr [mc "Invalid key: '%s'" {default_eol}]
+ }
+
+ # Section "Editor colors" and "Fonts"
+ foreach key {
+ normal_text_bg iconBorder_bg lineNumbers_bg lineNumbers_fg
+ fontSize fontFamily line_markers
+ } {
+ set value [subst "\$::Editor::$key"]
+ set value [::settings getValue "Editor colors/$key" $value]
+
+ set valid 1
+
+ # Validate line_markers
+ if {$key == {line_markers}} {
+ foreach def ${::Editor::line_markers} new $value {
+ if {![string equal [lindex $def 0] [lindex $new 0]]} {
+ puts stderr [mc "Invalid key: '%s'" [lindex $new 0]]
+ set valid 0
+ break
+ }
+ }
+ }
+
+ if {$valid} {
+ set ::Editor::$key $value
+ }
+ }
+
+ # Set editor default font
+ set ::Editor::defaultFont [font create \
+ -size -${::Editor::fontSize} \
+ -family ${::Editor::fontFamily} \
+ ]
+ set ::Editor::defaultFont_bold [font create \
+ -size -${::Editor::fontSize} \
+ -family ${::Editor::fontFamily} \
+ -weight {bold} \
+ ]
+ }
+}
diff --git a/lib/configdialogs/global_config.tcl b/lib/configdialogs/global_config.tcl
new file mode 100755
index 0000000..a5a422b
--- /dev/null
+++ b/lib/configdialogs/global_config.tcl
@@ -0,0 +1,318 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements global configuration dialog
+# --------------------------------------------------------------------------
+
+
+## Global configuration dialog
+ # see Array OPTION in root NS
+namespace eval global {
+
+ variable dialog_opened 0 ;# Bool: True if this dialog is already opened
+ variable win ;# ID of dialog toplevel window
+
+ variable avaliable_languages ;# List of avaliable languages
+
+ ## Configuration variables
+ variable show_splash ;# Bool: Show splash creen on startup
+ variable show_tips ;# Bool: Show tips on startup
+ variable language ;# String: Language
+
+ ## Create the dialog
+ # @return void
+ proc mkDialog {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+ variable avaliable_languages ;# List of avaliable languages
+
+ # Destroy the dialog if it's alredy opened
+ if {$dialog_opened} {
+ destroy .global_config_dialog
+ }
+ set dialog_opened 1
+
+ # Get settings from main NS
+ getSettings
+
+ # Determinate avaliable languages
+ get_languages
+
+ # Create toplevel window
+ set win [toplevel .global_config_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ label $win.header_label \
+ -compound left \
+ -image ::ICONS::32::kcmmemory \
+ -text [mc "MCU 8051 IDE configuration"] \
+ -font [font create -size -20]
+
+ # Create horizontal separator
+ Separator $win.sep -orient horizontal
+
+ ## Create middle frame
+ set middle_frame [frame $win.middle_frame]
+ # Checkbutton "Display splash screen"
+ grid [Label $middle_frame.lbl_splash \
+ -text [mc "Display splash screen"] \
+ -helptext [mc "Show splash screen on startup"] \
+ ] -row 0 -column 0 -sticky w
+ grid [checkbutton $middle_frame.chb_splash \
+ -variable ::configDialogs::global::show_splash \
+ ] -row 0 -column 1 -sticky w
+ DynamicHelp::add $middle_frame.chb_splash \
+ -text [mc "Show splash screen on startup"]
+ # Checkbutton "Show tips on startup"
+ grid [Label $middle_frame.lbl_tips \
+ -text [mc "Show tips on startup"] \
+ -helptext [mc "Invoke dialog with tip of the day on startup"] \
+ ] -row 1 -column 0 -sticky w
+ grid [checkbutton $middle_frame.chb_tips \
+ -variable ::configDialogs::global::show_tips \
+ ] -row 1 -column 1 -sticky w
+ DynamicHelp::add $middle_frame.chb_tips \
+ -text [mc "Invoke dialog with tip of the day on startup"]
+ # Combo "Language"
+ grid [Label $middle_frame.lbl_lang \
+ -text [mc "Language"] \
+ -helptext [mc "Your preferred language"] \
+ ] -row 2 -column 0 -sticky w
+ grid [ttk::combobox $middle_frame.cb_lang \
+ -values $avaliable_languages \
+ -state readonly \
+ -textvariable ::configDialogs::global::language \
+ ] -row 2 -column 1 -sticky w
+ bind $middle_frame.cb_lang <<ComboboxSelected>> \
+ {::configDialogs::global::language_changed}
+ DynamicHelp::add $middle_frame.cb_lang \
+ -text [mc "Your preferred language"]
+ # Separator
+ grid [ttk::separator $middle_frame.sep -orient horizontal] -columnspan 2 -sticky we -row 3 -column 0 -pady 5
+ # Checkbutton "Do not ask whether ..."
+ grid [text $middle_frame.lbl_ask \
+ -wrap word -height 4 -width 0 -bg {#EEEEEE} -bd 0 \
+ ] -row 4 -column 0 -sticky we
+ $middle_frame.lbl_ask insert end [mc "Do not always ask whether to add file to the project after the file is opened"]
+ $middle_frame.lbl_ask configure -state disabled
+ grid [checkbutton $middle_frame.cb_ask \
+ -onvalue 0 -offvalue 1 \
+ -variable ::FileList::ask__append_file_to_project \
+ ] -row 4 -column 1 -sticky w
+
+ # Finalize
+ grid columnconfigure $middle_frame 0 -minsize 200
+
+ ## Button frame at the bottom
+ set but_frame [frame $win.button_frame]
+ # Button "Reset"
+ pack [ttk::button $but_frame.but_default \
+ -text [mc "Reset to defaults"] \
+ -command {::configDialogs::global::DEFAULTS} \
+ ] -side left
+ DynamicHelp::add $but_frame.but_default \
+ -text [mc "Reset all settings to defaults"]
+ # Button "Ok"
+ pack [ttk::button $but_frame.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::global::OK} \
+ ] -side right
+ DynamicHelp::add $but_frame.but_ok \
+ -text [mc "Commit new settings"]
+ # Button "Cancel"
+ pack [ttk::button $but_frame.but_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::configDialogs::global::CANCEL} \
+ ] -side right
+ DynamicHelp::add $but_frame.but_cancel \
+ -text [mc "Take changes back and close dialog"]
+
+ # Pack frames and notebook
+ pack $win.header_label -side top -pady 6
+ pack $win.sep -side top -fill x -after $win.header_label
+ pack $middle_frame -side top -padx 10 -anchor nw -pady 10
+ pack $but_frame -side bottom -fill x -expand 1 -anchor s -padx 10 -pady 5
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::configure
+ wm transient $win .
+ wm title $win [mc "Configure MCU 8051 IDE"]
+ wm minsize $win 380 250
+ raise $win
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW {
+ ::configDialogs::global::CANCEL
+ }
+ tkwait window $win
+ }
+
+ ## Application language changed
+ # Takes any set of arguments and discards them
+ # @parm List - meaningless
+ # @return void
+ proc language_changed args {
+ tk_messageBox \
+ -parent .global_config_dialog \
+ -type ok -icon info \
+ -title [mc "Application language changed"] \
+ -message [mc "Language for this application has been changed. The change will take effect upon next start of application"]
+ }
+
+ ## Retrieve list of avaliable translations
+ # @return void
+ proc get_languages {} {
+ variable avaliable_languages ;# List of avaliable languages
+
+ set avaliable_languages {en}
+ set tmp [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set tmp [glob -nocomplain -types f -tails \
+ -directory "${::LIB_DIRNAME}/../translations" *.msg \
+ ]
+ }
+
+ foreach translation $tmp {
+ lappend avaliable_languages [file rootname $translation]
+ }
+ }
+
+ ## Set configuration variable
+ # @parm String variable - variable to set
+ # @parm Mixed value - new value
+ proc set_variable {variable value} {
+ variable show_splash ;# Bool: Show splash creen on startup
+ variable show_tips ;# Bool: Show tips on startup
+ variable language ;# String: Language
+
+ getSettings
+
+ switch -- $variable {
+ {splash} {
+ set show_splash $value
+ }
+ {tips} {
+ set show_tips $value
+ }
+ {language} {
+ set language $value
+ }
+ }
+
+ use_settings
+ save_config
+ }
+
+ ## Retrieve settings from main NS
+ # @return void
+ proc getSettings {} {
+ variable show_splash ;# Bool: Show splash creen on startup
+ variable show_tips ;# Bool: Show tips on startup
+ variable language ;# String: Language
+
+ set show_splash ${::GLOBAL_CONFIG(splash)}
+ set show_tips ${::GLOBAL_CONFIG(tips)}
+ set language ${::GLOBAL_CONFIG(language)}
+ }
+
+ ## Set application acording to local settings
+ # @return void
+ proc use_settings {} {
+ variable show_splash ;# Bool: Show splash creen on startup
+ variable show_tips ;# Bool: Show tips on startup
+ variable language ;# String: Language
+
+ if {${::GLOBAL_CONFIG(language)} != $language} {
+ set lang_changed 1
+ } {
+ set lang_changed 0
+ }
+
+ set ::GLOBAL_CONFIG(splash) $show_splash
+ set ::GLOBAL_CONFIG(tips) $show_tips
+ set ::GLOBAL_CONFIG(language) $language
+
+ if {$lang_changed} {
+ ::X::switch_language
+ }
+ }
+
+ ## Save settings to the config file
+ # @return void
+ proc save_config {} {
+ variable show_splash ;# Bool: Show splash creen on startup
+ variable show_tips ;# Bool: Show tips on startup
+ variable language ;# String: Language
+
+ if {[catch {
+ set conf_file [open "${::CONFIG_DIR}/base.conf" w]
+ puts -nonewline $conf_file \
+ [list $show_splash $show_tips $language]
+ close $conf_file
+ }]} {
+ puts stderr [mc "Unable to write to base configuration file"]
+ }
+ }
+
+ ## Destroy the dialog
+ # @return void
+ proc CANCEL {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Destroy dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Use settings and destroy the dialog
+ # @return void
+ proc OK {} {
+ variable win ;# ID of toplevel dialog window
+
+ # Use and save settings
+ use_settings
+ save_config
+
+ # Destroy dialog window
+ CANCEL
+ }
+
+ ## Restrore defaults
+ # @return void
+ proc DEFAULTS {} {
+ variable show_splash ;# Bool: Show splash creen on startup
+ variable show_tips ;# Bool: Show tips on startup
+ variable language ;# String: Language
+
+ set show_splash 1
+ set show_tips 1
+ set language {en}
+ }
+}
diff --git a/lib/configdialogs/rightpanel_config.tcl b/lib/configdialogs/rightpanel_config.tcl
new file mode 100755
index 0000000..4161b4f
--- /dev/null
+++ b/lib/configdialogs/rightpanel_config.tcl
@@ -0,0 +1,498 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements right panel configuration dialog
+# --------------------------------------------------------------------------
+
+namespace eval rightPanel {
+
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened 0 ;# Bool: True if this dialog is already opened
+
+ variable changed ;# Bool: Settings changed
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+
+ variable apply_button ;# ID of button "Apply"
+ variable instruction_tags ;# Highlighting tags for instruction details
+ variable watch_text_tags ;# Highlighting tags for register watches
+
+ ## Create the dialog
+ # @parm Int = 0 - number of tab to raise
+ # @return void
+ proc mkDialog args {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable changed ;# Bool: Settings changed
+ variable apply_button ;# ID of button "Apply"
+ variable instruction_tags ;# Highlighting tags for instruction details
+ variable watch_text_tags ;# Highlighting tags for register watches
+
+ # Destroy the dialog if it's alredy opened
+ if {$dialog_opened} {
+ destroy .rightPanel_config_dialog
+ }
+ set anything_modified 0
+ set dialog_opened 1
+ set changed 0
+
+ # Get settings from Compiler NS
+ getSettings
+
+ # Create toplevel window
+ set win [toplevel .rightPanel_config_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ label $win.header_label \
+ -compound left \
+ -text [mc "Right panel configuration"] \
+ -font [font create -size -20]
+
+ ## Create notebook
+ set nb [ttk::notebook $win.nb]
+ # Tab "Register watches"
+ set watches_tab [frame $nb.watches_tab]
+ $nb add $watches_tab -text [mc "Register watches"]
+ # Tab "Instruction details"
+ set instruction_tab [frame $nb.instruction_tab]
+ $nb add $instruction_tab -text [mc "Instruction details"]
+
+ #
+ ## Tab "Register watches"
+ #
+
+ # Create header
+ grid [label $watches_tab.lbl_header_1 -anchor w \
+ -text [mc "Bold"] \
+ ] -column 1 -row 0
+
+
+ # Create buttons
+ set idx 0 ;# Current tag index
+ set row 1 ;# Row in the grid
+ foreach tag $watch_text_tags {
+
+ # Local variables
+ set tag_name [lindex $tag 0] ;# Tag name
+ set color [lindex $tag 1] ;# Foreground color (RGB)
+ set boldItalic [lindex $tag 2] ;# Bool: 1 == Bold, 0 == Italic
+
+ # Short tag decription
+ grid [label $watches_tab.lbl_${tag_name} \
+ -text [tag2name $tag_name] -pady 0 \
+ -highlightthickness 0 -bd 0 -anchor w \
+ ] -column 0 -row $row -sticky we
+
+ # Checkbutton "Bold"
+ set checkbutton [checkbutton $watches_tab.chbut_${tag_name} \
+ -pady 0 -highlightthickness 0 \
+ -command "::configDialogs::rightPanel::change_style $idx 1" \
+ ]
+ if {$boldItalic == {1}} {
+ $checkbutton select
+ }
+ grid $checkbutton -column 1 -row $row -sticky we
+
+ # Button for selecting foreground color
+ grid [button $watches_tab.but_${tag_name} \
+ -bd 1 -relief raised -pady 0 -highlightthickness 0 \
+ -bg $color -width 10 -activebackground $color \
+ -command "::configDialogs::rightPanel::select_color $idx $watches_tab.but_${tag_name} 1"
+ ] -column 2 -row $row -sticky ns -padx 10
+
+ incr row ;# Row in the grid
+ incr idx ;# Current tag index
+ }
+
+ # Adjust the grid
+ grid columnconfigure $watches_tab 0 -minsize 200
+
+
+ #
+ ## Tab "Instruction details"
+ #
+
+ # Create header
+ grid [label $instruction_tab.lbl_header_2 -anchor w \
+ -text [mc "Bold"] \
+ ] -column 2 -row 0 -sticky we
+
+ # Create buttons
+ set row 1 ;# Row in the grid
+ set idx 0 ;# Current tag index
+ foreach tag $instruction_tags {
+
+ # Skip highlight for numbers
+ if {[llength $tag] != 3} {
+ incr idx
+ continue
+ }
+
+ # Local variables
+ set tag_name [lindex $tag 0] ;# Tag name
+ set color [lindex $tag 1] ;# Foreground color (RGB)
+ set boldItalic [lindex $tag 2] ;# Bool: 1 == Bold, 0 == Italic
+
+ # Short tag decription
+ grid [label $instruction_tab.lbl_${tag_name} \
+ -text [tag2name $tag_name] -pady 0 \
+ -highlightthickness 0 -bd 0 -anchor w \
+ ] -column 1 -row $row -sticky we
+
+ # Checkbutton "Bold"
+ set checkbutton [checkbutton $instruction_tab.chbut_${tag_name} \
+ -pady 0 -highlightthickness 0 \
+ -command "::configDialogs::rightPanel::change_style $idx 0" \
+ ]
+ if {$boldItalic} {
+ $checkbutton select
+ }
+ grid $checkbutton -column 2 -row $row -sticky we
+
+ # Button for selecting foreground color
+ grid [button $instruction_tab.but_${tag_name} \
+ -bd 1 -relief raised -pady 0 -highlightthickness 0 \
+ -bg $color -width 10 -activebackground $color \
+ -command "::configDialogs::rightPanel::select_color $idx $instruction_tab.but_${tag_name} 0"
+ ] -column 3 -row $row -sticky ns -padx 10
+
+
+ incr row ;# Row in the grid
+ incr idx ;# Current tag index
+ }
+
+ # Adjust the grid
+ grid columnconfigure $instruction_tab 1 -minsize 200
+
+ # Raise appropriate tab
+ if {$args == {}} {
+ $nb select $watches_tab
+ } {
+ $nb select [lindex [$nb tabs] $args]
+ }
+
+ # Create button frame at the bottom
+ set but_frame [frame $win.button_frame]
+ # Button "Apply"
+ set apply_button [ttk::button $but_frame.but_apply \
+ -state disabled \
+ -text [mc "Apply"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::rightPanel::APPLY} \
+ ]
+ pack $apply_button -side left
+ # Button "Ok"
+ pack [ttk::button $but_frame.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::rightPanel::OK} \
+ ] -side right
+ # Button "Cancel"
+ pack [ttk::button $but_frame.but_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::configDialogs::rightPanel::CANCEL} \
+ ] -side right
+
+ # Pack frames and notebook
+ pack $but_frame -side bottom -fill x -expand 0 -anchor s -padx 10 -pady 5
+ pack $win.header_label -side top -pady 6
+ pack $nb -side top -fill both -expand 1 -padx 10
+
+ # Finalize creation of the dialog
+ wm iconphoto $win ::ICONS::16::configure
+ wm transient $win .
+ wm title $win [mc "Configure right panel - %s" ${::APPNAME}]
+ wm geometry $win =390x380
+ wm resizable $win 0 0
+ raise $win
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW {
+ ::configDialogs::rightPanel::CANCEL
+ }
+ tkwait window $win
+ }
+
+ ## Traslate tag name to human readable string
+ # @return String - result or {}
+ proc tag2name {tag} {
+ switch -- $tag {
+ {tag_code8} {return "code8"}
+ {tag_code11} {return "code11"}
+ {tag_code16} {return "code16"}
+ {tag_imm8} {return "imm8"}
+ {tag_imm16} {return "imm16"}
+ {tag_data} {return "data"}
+ {tag_bit} {return "bit"}
+ {tag_DPTR} {return "DPTR"}
+ {tag_A} {return "A"}
+ {tag_AB} {return "AB"}
+ {tag_SFR} {return "C, R0..R7"}
+ {tag_indr} {return "@R0, @R0 etc."}
+ {tag_Baddr} {return "Bit"}
+ {tag_Xaddr} {return "XDATA"}
+ {tag_Eaddr} {return "EDATA"}
+ {tag_addr} {return "IDATA"}
+ {tag_name} {return "Name"}
+ default {return {}}
+ }
+ }
+
+ ## Toggle style flag for given text tag (Bold <-> Italic / Roman)
+ # @parm Int row - Index of the target text tag
+ # @parm Bool for - 0 == instruction_tags; 1 == watch_text_tags
+ # @return void
+ proc change_style {row for} {
+ variable instruction_tags ;# Highlighting tags for instruction details
+ variable watch_text_tags ;# Highlighting tags for register watches
+
+ if {$for} {
+ if {[lindex $watch_text_tags "$row 2"] != 1} {
+ lset watch_text_tags "$row 2" 1
+ } {
+ lset watch_text_tags "$row 2" {}
+ }
+ } {
+ lset instruction_tags "$row 2" [expr {!([lindex $instruction_tags "$row 2"])}]
+ }
+
+ # Adjust status changed
+ settings_changed
+ }
+
+ ## Change color for given text tag and adjust given bg color of given button
+ # @parm Int row - Index of the target text tag
+ # @parm Widget button - ID of source button
+ # @parm Bool for - 0 == instruction_tags; 1 == watch_text_tags
+ # @return void
+ proc select_color {row button for} {
+ variable instruction_tags ;# Highlighting tags for instruction details
+ variable watch_text_tags ;# Highlighting tags for register watches
+ variable win ;# ID of toplevel dialog window
+
+ # Destroy prevoisly opened color selection dialog
+ if {[winfo exists .select_color]} {
+ destroy .select_color
+ }
+
+ # Invoke new color selection dialog
+ if {$for} {
+ set color [lindex $watch_text_tags "$row 1"]
+ } {
+ set color [lindex $instruction_tags "$row 1"]
+ }
+ set color [SelectColor .select_color \
+ -parent $win \
+ -color $color \
+ -title [mc "Select color - %s" ${::APPNAME}] \
+ ]
+
+ # Change button background color
+ if {$color != {}} {
+ if {$for} {
+ lset watch_text_tags "$row 1" $color
+ } {
+ lset instruction_tags "$row 1" $color
+ }
+ $button configure -bg $color -activebackground $color
+
+ # Adjust status changed
+ settings_changed
+ }
+ }
+
+ ## Adjust all editors to fit new settings
+ # @return Bool - result
+ proc apply_settings {} {
+ # Check if there is at least 1 opened editor
+ if {[llength ${::X::openedProjects}] == 0} {
+ return 0
+ }
+
+ # Apply new settings in all projects
+ foreach project ${::X::openedProjects} {
+ $project rightPanel_refresh_instruction_highlighting
+ $project rightPanel_refresh_regwatches_highlighting
+ }
+
+ # Done ...
+ return 1
+ }
+
+ ## Change content of configuration variables RightPanel NS
+ # @return void
+ proc use_settings {} {
+ variable watch_text_tags ;# Highlighting tags for register watches
+ variable instruction_tags ;# Highlighting tags for instruction details
+
+ set ::InstructionDetails::instruction_tags $instruction_tags
+ set ::RegWatches::watch_text_tags $watch_text_tags
+ }
+
+ ## Retrieve settings related to this dialog from the program
+ # @return void
+ proc getSettings {} {
+ variable instruction_tags ;# Highlighting tags for instruction details
+ variable watch_text_tags ;# Highlighting tags for register watches
+
+ set instruction_tags ${::InstructionDetails::instruction_tags}
+ set watch_text_tags ${::RegWatches::watch_text_tags}
+ }
+
+ ## Save configuration to config file
+ # @return void
+ proc save_config {} {
+
+ # Save configuration of "Instruction details"
+ foreach item ${::InstructionDetails::instruction_tags} {
+ # Save config
+ set key [lindex $item 0]
+ set value [lrange $item 1 end]
+ ::settings setValue "Instruction details/$key" $value
+ }
+
+ # Save configuration of "Register watches"
+ foreach item ${::RegWatches::watch_text_tags} {
+ # Save config
+ set key [lindex $item 0]
+ set value [lrange $item 1 end]
+ ::settings setValue "Register watches/$key" $value
+ }
+
+ # Commit
+ ::settings saveConfig
+ }
+
+ ## Load configuratin from config file
+ # @return void
+ proc load_config {} {
+ variable instruction_tags ;# Highlighting tags for instruction details
+ variable watch_text_tags ;# Highlighting tags for register watches
+
+ set instruction_tags {}
+ set watch_text_tags {}
+ foreach item ${::InstructionDetails::instruction_tags} {
+ # Load config
+ set key [lindex $item 0]
+ set value [lrange $item 1 end]
+ set value [::settings getValue "Instruction details/$key" $value]
+ lappend instruction_tags "$key $value"
+ }
+ foreach item ${::RegWatches::watch_text_tags} {
+ # Load config
+ set key [lindex $item 0]
+ set value [lrange $item 1 end]
+ set value [::settings getValue "Register watches/$key" $value]
+ lappend watch_text_tags "$key $value"
+ }
+ set ::InstructionDetails::instruction_tags $instruction_tags
+ set ::RegWatches::watch_text_tags $watch_text_tags
+ unset instruction_tags
+ unset watch_text_tags
+ }
+
+ ## Set status changed to True
+ # @return true
+ proc settings_changed {} {
+ variable changed ;# Bool: Settings changed
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable apply_button ;# ID of button "Apply"
+
+ if {$changed} {return}
+
+ set changed 1
+ set anything_modified 1
+ $apply_button configure -state normal
+ }
+
+ ## Take back changes and destroy dialog window
+ # @return void
+ proc CANCEL {} {
+ variable win ;# ID of dialog toplevel window
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Restore previous configuration
+ if {$anything_modified} {
+ load_config
+ apply_settings
+ set anything_modified 0
+ }
+
+ # Get rid of dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Apply changes and destroy dialog window
+ # @return void
+ proc OK {} {
+ variable win ;# ID of dialog toplevel window
+ variable changed ;# Bool: Settings changed
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Apply new settings
+ if {$changed} {
+ use_settings ;# Adjust NS variables
+ apply_settings ;# Adjust GUI
+ save_config ;# Save new config
+ }
+
+ # Get rid of dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Apply changes in GUI
+ # @return Bool - result
+ proc APPLY {} {
+ variable apply_button ;# ID of button "Apply"
+ variable changed ;# Bool: Settings changed
+
+ # Check if there is at least 1 opened editor
+ if {[llength ${X::openedProjects}] == 0} {
+ return 0
+ }
+
+ # Reset status changed
+ set changed 0
+ $apply_button configure -state disabled
+
+ # Adjust NS variables
+ use_settings
+ # Adjust GUI in current project
+ ${X::actualProject} rightPanel_refresh_instruction_highlighting
+ ${X::actualProject} rightPanel_refresh_regwatches_highlighting
+
+ # done ...
+ return 1
+ }
+}
diff --git a/lib/configdialogs/shortcuts_config.tcl b/lib/configdialogs/shortcuts_config.tcl
new file mode 100755
index 0000000..e0be8fe
--- /dev/null
+++ b/lib/configdialogs/shortcuts_config.tcl
@@ -0,0 +1,1015 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements shortcuts configuration dialog
+# --------------------------------------------------------------------------
+
+namespace eval shortcuts {
+ variable dialog_opened 0 ;# Bool: True if this dialog is already opened
+ variable win ;# ID of dialog toplevel window
+
+ variable changed ;# Bool: Settings changed
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable local_DB ;# Array: Local database of shortcuts
+ variable root_hard_cd ;# List of hadrcoded shortcuts (main window only)
+ variable currentNode ;# ID of the currently selected tree node
+ variable search_in_P ;# Bool: search in progress
+ # Empty image
+ variable empty_image [image create bitmap]
+ # Font for entry "Current shortcut"
+ variable current_entry_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -weight bold \
+ -size -12 \
+ ]
+ # Normal font for tree widget nodes
+ variable node_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -weight normal \
+ -size -12 \
+ ]
+ # Bold font for tree widget nodes
+ variable node_font_b [font create \
+ -family {helvetica} \
+ -weight bold \
+ -size -14 \
+ ]
+
+ variable status_label ;# ID of status label
+ variable search_entry ;# ID of entry widget on search panel
+ variable search_clear ;# ID of button "Clear search entry"
+ variable treeWidget ;# ID of the tree widget
+ variable bottom_lf_label ;# ID of label for bottom label frame
+ variable discard_button ;# ID of button "Discard"
+ variable accept_button ;# ID of button "Accept"
+ variable default_entry ;# ID of label containging default key shortcut
+ variable default_button ;# ID of button "Restore default" (bottom label frame)
+ variable clear_button ;# ID of button "Clear"
+ variable current_entry ;# ID of entry "Current shortcut"
+
+ ## Create the dialog
+ # @return void
+ proc mkDialog {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+ variable local_DB ;# Array: Local database of shortcuts
+ variable changed ;# Bool: Settings changed
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable search_entry ;# ID of entry widget on search panel
+ variable search_clear ;# ID of button "Clear search entry"
+ variable treeWidget ;# ID of the tree widget
+ variable search_in_P ;# Bool: search in progress
+ variable bottom_lf_label ;# ID of label for bottom label frame
+ variable discard_button ;# ID of button "Discard"
+ variable accept_button ;# ID of button "Accept"
+ variable default_entry ;# ID of label containging default key shortcut
+ variable default_button ;# ID of button "Restore default" (bottom label frame)
+ variable clear_button ;# ID of button "Clear"
+ variable current_entry ;# ID of entry "Current shortcut"
+ variable empty_image ;# Empty image
+ variable current_entry_font ;# Font for entry "Current shortcut"
+ variable currentNode ;# ID of the currently selected tree node
+ variable status_label ;# ID of status label
+ variable root_hard_cd ;# List of hadrcoded shortcuts (main window only)
+ variable node_font ;# Normal font for tree widget nodes
+ variable node_font_b ;# Bold font for tree widget nodes
+
+ # Destroy dialog window if it is already opened
+ if {$dialog_opened} {
+ destroy .shortcuts_config_dialog
+ }
+ set anything_modified 0
+ set dialog_opened 1
+ set currentNode {}
+ set search_in_P 0
+ set changed 0
+
+ # Configure ttk styles
+ ttk::style configure Shortcuts_Default.TLabel -relief sunken -borderwidth 1 -background {#F0F0F0}
+
+ # Get settings from the program
+ getSettings
+
+ # Create list of hardcoded shortcuts related to main window
+ set root_hard_cd {}
+ foreach key ${::HARDCODED_SHORTCUTS} {
+ lappend root_hard_cd [simplify_key_seq $key]
+ }
+
+ # Create toplevel window
+ set win [toplevel .shortcuts_config_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ label $win.header_label \
+ -compound left \
+ -image ::ICONS::32::configure \
+ -text [mc "Configure key shortcuts"] \
+ -font [font create -size -20]
+
+ # Create header labels for label frames
+ set top_lf_label [label $win.top_lf_label \
+ -text [mc "Avaliable items"] \
+ -image ::ICONS::16::view_choose \
+ -compound left \
+ ]
+ set bottom_lf_label [label $win.bottom_lf_label \
+ -text [mc "<Nothing selected>"] \
+ -compound left -height 20 \
+ -image $empty_image \
+ ]
+
+ # Create label frames
+ set top_labelframe [ttk::labelframe $win.top_labelframe \
+ -labelwidget $top_lf_label -padding 7 \
+ ]
+ set bottom_labelframe [ttk::labelframe $win.bottom_labelframe \
+ -labelwidget $bottom_lf_label -padding 7 \
+ ]
+
+ # Create serach panel
+ set search_frame [frame $top_labelframe.search_frame]
+ pack [Label $search_frame.label \
+ -text [mc "Search:"] \
+ -helptext [mc "Enter your search string here"] \
+ ] -side left
+ set search_entry [ttk::entry $search_frame.entry \
+ -validate all \
+ -validatecommand {::configDialogs::shortcuts::search %P} \
+ ]
+ DynamicHelp::add $search_frame.entry \
+ -text [mc "Enter your search string here"]
+ pack $search_entry -side left -fill x -expand 1
+ set search_clear [ttk::button $search_frame.button \
+ -image ::ICONS::16::clear_left \
+ -style Flat.TButton \
+ -command "$search_entry delete 0 end" \
+ -state disabled \
+ ]
+ DynamicHelp::add $search_frame.button \
+ -text [mc "Clear"]
+ pack $search_clear -side right -after $search_entry
+ pack $search_frame -fill x -pady 5
+
+ # Create frame for the tree widget and its scrollbar
+ set tree_frame [frame $top_labelframe.tree_frame]
+ pack $tree_frame -fill both -expand 1
+
+ # Create tree widget showing avaliable items
+ set treeWidget [Tree $tree_frame.tree \
+ -selectfill 1 \
+ -showlines 1 \
+ -linesfill {#888888} \
+ -bg {#FFFFFF} \
+ -selectbackground {#CCCCFF} \
+ -selectforeground {#0000FF} \
+ -highlightthickness 0 \
+ -padx 5 \
+ -deltay 20 \
+ -deltax 20 \
+ -yscrollcommand "$tree_frame.scrollbar set" \
+ -crossopenimage ::ICONS::16::1downarrow \
+ -crosscloseimage ::ICONS::16::1rightarrow \
+ -selectcommand {::configDialogs::shortcuts::item_selected} \
+ ]
+ pack $treeWidget -fill both -expand 1 -side left
+ bind $treeWidget <Button-5> {%W yview scroll +5 units; break}
+ bind $treeWidget <Button-4> {%W yview scroll -5 units; break}
+
+ # Create scrollbar for the tree widget
+ pack [ttk::scrollbar $tree_frame.scrollbar \
+ -command "$treeWidget yview" \
+ -orient vertical \
+ ] -fill y -side left -after $treeWidget
+
+ # Fill in the tree
+ foreach block ${::SHORTCUTS_LIST} {
+ # Determinate category
+ set cat_org [lindex $block 0]
+ set cat "__$cat_org"
+
+ # Adjus list of harcoded shotcuts
+ set hardcoded {}
+ foreach key [lindex $block 2] {
+ lappend hardcoded [simplify_key_seq $key]
+ }
+
+ # Create category node
+ $treeWidget insert end root $cat \
+ -selectable 1 \
+ -data $hardcoded \
+ -text [mc [lindex $block 1]] \
+ -fill {#0000FF} \
+ -font $node_font_b
+
+ ## Create item node
+ set block [lreplace $block 0 2] ;# Item definitions
+ set len [llength $block] ;# Length of data block
+
+ # Iterate over item definitions
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+
+ # Local variables
+ set item [lindex $block $i] ;# Item ID
+ set image [lindex $block [list $j 2]] ;# Image ID or {}
+ set text [mc [lindex $block [list $j 3]]];# Item text
+ set txt_len [string length $text] ;# Item text length
+
+ # Adjust text width
+ append text [string repeat "\t" [expr {4 - ($txt_len / 8)}]]
+
+ # Determinate text to show in the node
+ set text_and_key $text
+ append text_and_key [simplify_key_seq $local_DB($cat_org:$item)]
+
+ # Determinate image ID
+ if {$image != {}} {
+ set image "::ICONS::16::$image"
+ } {
+ set image $empty_image
+ }
+
+ # Adjust key combination
+ set key_seq [regsub {Key(Press|Release)?\-} $local_DB($cat_org:$item) {}]
+
+ # Create node in the tree widget
+ $treeWidget insert end $cat $item \
+ -selectable 1 \
+ -font $node_font \
+ -text $text_and_key \
+ -data [list \
+ $text \
+ [lindex $block [list $j 0]] \
+ $key_seq \
+ ] \
+ -image $image -padx 25
+ }
+ }
+
+ ## Create widgets of bottom label frame
+ # Label and entry "Current"
+ grid [label $bottom_labelframe.current_label \
+ -text [mc "Current shortcut:"] \
+ ] -row 0 -column 0 -sticky w
+ set current_entry [ttk::entry $bottom_labelframe.current_entry \
+ -validatecommand {::configDialogs::shortcuts::cur_entry_val %P} \
+ ]
+ grid $current_entry -row 0 -column 1
+ bind $current_entry <KeyPress> \
+ {::configDialogs::shortcuts::current_entry_key %K; break}
+ bind $current_entry <Control-KeyPress> \
+ {::configDialogs::shortcuts::current_entry_key Ctrl+%K; break}
+ bind $current_entry <Alt-KeyPress> \
+ {::configDialogs::shortcuts::current_entry_key Alt+%K; break}
+ bind $current_entry <Control-Alt-KeyPress> \
+ {::configDialogs::shortcuts::current_entry_key Ctrl+Alt+%K; break}
+ set clear_button [ttk::button $bottom_labelframe.clear_button \
+ -image ::ICONS::16::clear_left \
+ -state disabled \
+ -style Flat.TButton \
+ -command {::configDialogs::shortcuts::clear_current} \
+ ]
+ DynamicHelp::add $bottom_labelframe.clear_button -text [mc "Clear"]
+ grid $clear_button -row 0 -column 2 -sticky w
+
+ # Label and entry "Default"
+ grid [label $bottom_labelframe.default_label \
+ -text [mc "Default:"] \
+ ] -row 1 -column 0 -sticky w
+ set default_entry [ttk::label $bottom_labelframe.default_entry \
+ -style Shortcuts_Default.TLabel \
+ ]
+ grid $default_entry -row 1 -column 1 -sticky we
+ set default_button [ttk::button $bottom_labelframe.default_button \
+ -image ::ICONS::16::up0 \
+ -state disabled \
+ -command {::configDialogs::shortcuts::to_default} \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $bottom_labelframe.default_button -text [mc "Restore default"]
+ grid $default_button -row 1 -column 2 -sticky w
+
+ # Button "Accept"
+ set accept_button [ttk::button $bottom_labelframe.accept_button \
+ -command {::configDialogs::shortcuts::accept_current} \
+ -text [mc "Accept"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -state disabled \
+ ]
+ DynamicHelp::add $bottom_labelframe.accept_button -text [mc "Accept new shortcut"]
+ grid $accept_button -row 0 -column 4 -rowspan 2
+ # Button "Original"
+ set discard_button [ttk::button $bottom_labelframe.discard_button \
+ -command {::configDialogs::shortcuts::discard_current} \
+ -text [mc "Original"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -state disabled \
+ ]
+ DynamicHelp::add $bottom_labelframe.discard_button -text [mc "Discard new shortcut"]
+ grid $discard_button -row 0 -column 5 -rowspan 2
+
+ # Create status label
+ set status_label [label $bottom_labelframe.status_label \
+ -fg {#DD0000} -anchor w -text {} \
+ ]
+ grid $status_label -row 2 -column 0 -columnspan 6 -sticky w
+
+ # Create empty space on column 3
+ grid columnconfigure $bottom_labelframe 3 -minsize 70
+
+
+ ## Button frame at the bottom
+ set but_frame [frame $win.button_frame]
+ # Button "Reset"
+ pack [ttk::button $but_frame.but_default \
+ -text [mc "Defaults"] \
+ -command {::configDialogs::shortcuts::DEFAULTS} \
+ ] -side left
+ DynamicHelp::add $but_frame.but_default -text [mc "Reset all settings to defaults"]
+ # Button "Ok"
+ pack [ttk::button $but_frame.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::shortcuts::OK} \
+ ] -side right
+ DynamicHelp::add $but_frame.but_ok -text [mc "Commit new settings"]
+ # Button "Cancel"
+ pack [ttk::button $but_frame.but_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::configDialogs::shortcuts::CANCEL} \
+ ] -side right
+ DynamicHelp::add $but_frame.but_cancel -text [mc "Take changes back and close dialog"]
+
+ # Pack frames
+ pack $win.header_label -side top -pady 6
+ pack $top_labelframe -side top -fill both -expand 1 -padx 10
+ pack $bottom_labelframe -side top -fill x -padx 10 -pady 10 -after $top_labelframe
+ pack $but_frame -side bottom -fill x -padx 10 -pady 5
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::configure
+ wm transient $win .
+ wm title $win [mc "Configure shortcuts - %s" ${::APPNAME}]
+ wm minsize $win 600 520
+ raise $win
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW {
+ ::configDialogs::shortcuts::CANCEL
+ }
+ tkwait window $win
+ }
+
+ ## Argument of parameter '-selectcommand' for the tree widget
+ # @parm Widget widget - Source tree widget
+ # @parm List nodes - Selected nodes
+ # @return void
+ proc item_selected {widget nodes} {
+ variable current_entry_font ;# Font for entry "Current shortcut"
+ variable node_font ;# Normal font for tree widget nodes
+ variable search_entry ;# ID of entry widget on search panel
+ variable search_in_P ;# Bool: search in progress
+ variable discard_button ;# ID of button "Discard"
+ variable accept_button ;# ID of button "Accept"
+ variable default_entry ;# ID of label containging default key shortcut
+ variable bottom_lf_label ;# ID of label for bottom label frame
+ variable default_button ;# ID of button "Restore default" (bottom label frame)
+ variable clear_button ;# ID of button "Clear"
+ variable current_entry ;# ID of entry "Current shortcut"
+ variable empty_image ;# Empty image
+ variable status_label ;# ID of status label
+ variable changed ;# Bool: Settings changed
+ variable currentNode ;# ID of the currently selected tree node
+
+ # Empty selection -> disable widgets on the bottom frame and return
+ if {$nodes == {}} {
+ # Save last changed item
+ if {$changed} {
+ current_item_changed
+ }
+
+ # Clear and disable componets of the bottom frame
+ $current_entry delete 0 end
+ $default_entry configure -text {}
+ $status_label configure -text {}
+ $current_entry configure -state disabled
+ $default_button configure -state disabled
+ $accept_button configure -state disabled
+ $discard_button configure -state disabled
+ $bottom_lf_label configure -text [mc "<Nothing selected>"] -image $empty_image
+ return
+ }
+
+ # Only one node can be selected
+ set node [lindex $nodes end]
+ if {[llength $nodes] > 1} {
+ foreach nd [lreplace $nodes end end] {
+ $widget selection remove $nd
+ }
+ return
+ }
+
+ # Clear status label, search entry and ask for saving the last change
+ $status_label configure -text {}
+ if {!$search_in_P} {
+ $search_entry delete 0 end
+ if {$changed} {
+ current_item_changed
+ }
+ }
+
+ # If the selected node is a toplevel one -> open its node
+ if {[regexp {^__} $node]} {
+ $widget toggle $node
+ $widget selection clear
+ return
+ }
+
+ if {$currentNode != {}} {
+ $widget itemconfigure $currentNode -font $node_font
+ }
+ $widget itemconfigure $node -font $current_entry_font
+
+ # Set the current node
+ set currentNode $node
+
+ # Adjust bottom frame
+ set data [$widget itemcget $node -data]
+ $bottom_lf_label configure \
+ -image [$widget itemcget $node -image] \
+ -text [string trimright [lindex $data 0]]
+ $current_entry configure -state normal
+ $current_entry delete 0 end
+ $current_entry insert end [simplify_key_seq [lindex $data 2]]
+ $default_entry configure -text [simplify_key_seq [lindex $data 1]]
+ $default_button configure -state normal
+ ena_dis__accept_discard 0
+ }
+
+ ## Binding for X-Key event for entry "Custom shortcut" (see proc. 'mkDialog')
+ # @parm String key_seq - human readable key combination string
+ # @return void
+ proc current_entry_key {key_seq} {
+ variable current_entry ;# ID of entry "Current shortcut"
+ variable status_label ;# ID of status label
+ variable changed ;# Bool: Settings changed
+ variable treeWidget ;# ID of the tree widget
+ variable currentNode ;# ID of the currently selected tree node
+ variable root_hard_cd ;# List of hadrcoded shortcuts (main window only)
+
+ if {$currentNode == {}} {
+ return
+ }
+
+ # Clear entry "Custom shortcut"
+ $current_entry delete 0 end
+
+ # Adjust key combination
+ set lastchar [string index $key_seq end]
+ if {[string index $key_seq end-1] == {+}} {
+ if {[string is lower -strict $lastchar]} {
+ set key_seq [string replace $key_seq \
+ end end [string toupper $lastchar]]
+ } {
+ set key_seq [string replace $key_seq end end \
+ "Shift+[string toupper $lastchar]"]
+ }
+ }
+
+ # Check for validity of the given shortcut and set flag "changed"
+ set changed 0
+ if {![regexp {^(Ctrl|Alt)\+} $key_seq] && ![regexp {^F\d\d?$} $key_seq]} {
+ $status_label configure -text [mc "Modifier required (Control or Alt)"]
+ } elseif {[lsearch $root_hard_cd $key_seq] != -1} {
+ $status_label configure -text \
+ [mc "This combination is hardcoded in the main window, so it cannot be used"]
+ } elseif {[lsearch [$treeWidget itemcget [$treeWidget parent $currentNode] -data] $key_seq] != -1} {
+ $status_label configure -text \
+ [mc "This combination is hardcoded, so it cannot be used"]
+ } else {
+ set changed 1
+ }
+ if {!$changed} {
+ $current_entry insert end $key_seq
+ ena_dis__accept_discard 0
+ return
+ }
+
+ # Change content of entry "Custom shortcut"
+ $current_entry insert end $key_seq
+
+ # Check if the given combination is not already assigned to something
+ set name [lindex [key_seq_to_name \
+ [extend_key_seq $key_seq] \
+ [$treeWidget parent $currentNode]] 1]
+ if {$name != {}} {
+ $status_label configure -text \
+ [mc "The '%s' key combination has already been assigned to \"%s\"." $key_seq $name]
+ } {
+ $status_label configure -text {}
+ }
+
+ # Enable buttons "Accept" and "Original"
+ ena_dis__accept_discard 1
+ }
+
+ ## Clear entry "Custom shortcut"
+ # @return void
+ proc clear_current {} {
+ variable changed ;# Bool: Settings changed
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable current_entry ;# ID of entry "Current shortcut"
+ variable status_label ;# ID of status label
+
+ # Adjust flag "Anything modified"
+ if {[$current_entry get] != {}} {
+ set anything_modified 1
+ }
+ # Clear the entry widget and status label
+ $current_entry delete 0 end
+ $status_label configure -text {}
+ # Enable buttons "Accept" and "Original"
+ ena_dis__accept_discard 1
+ # Set flag "Changed"
+ set changed 1
+ }
+
+ ## Validate content of entry "Current shortcut"
+ # @parm String content - content of entry "Current shortcut"
+ # @return Bool - always 1
+ proc cur_entry_val {content} {
+ variable clear_button ;# ID of button "Clear"
+
+ # Enable/Disable button "Clear"
+ if {$content == {}} {
+ $clear_button configure -state disabled
+ } {
+ $clear_button configure -state normal
+ }
+
+ return 1
+ }
+
+ ## Set current shortcut to default
+ # @return void
+ proc to_default {} {
+ variable treeWidget ;# ID of the tree widget
+ variable changed ;# Bool: Settings changed
+ variable currentNode ;# ID of the currently selected tree node
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable current_entry ;# ID of entry "Current shortcut"
+ variable default_entry ;# ID of label containging default key shortcut
+ variable status_label ;# ID of status label
+
+ # Se flag "Anything modified"
+ if {[$current_entry get] != [$default_entry cget -text]} {
+ set anything_modified 1
+ }
+
+ # Adjust content of entry "Current shortcut"
+ set key [$default_entry cget -text]
+ $current_entry delete 0 end
+ $current_entry insert 0 $key
+
+ # Check if the new setting is unique
+ set name [lindex [key_seq_to_name \
+ [extend_key_seq $key ] \
+ [$treeWidget parent $currentNode]] 1]
+ if {$name != {}} {
+ $status_label configure -text \
+ [mc "The '%s' key combination has already been assigned to \"%s\"." $key $name]
+ }
+
+ # Enable buttons "Accept" and "Original"
+ ena_dis__accept_discard 1
+ set changed 1
+ }
+
+ ## Accept new key combination fot the currently selected action
+ # @return void
+ proc accept_current {} {
+ variable changed ;# Bool: Settings changed
+ variable treeWidget ;# ID of the tree widget
+ variable current_entry ;# ID of entry "Current shortcut"
+ variable currentNode ;# ID of the currently selected tree node
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable local_DB ;# Local database of shortcuts
+ variable status_label ;# ID of status label
+
+ # Gain details about the current action
+ set data [$treeWidget itemcget $currentNode -data]
+ set parent [$treeWidget parent $currentNode]
+ set category [string replace $parent 0 1]
+ set text_org [lindex $data 0]
+ set default [lindex $data 1]
+ set current [extend_key_seq [$current_entry get]]
+ set text $text_org
+ append text [$current_entry get]
+
+ ## Redefine shortcut for action which have the same shortcut as the current one
+ $treeWidget itemconfigure $currentNode -data {}
+ set defined [key_seq_to_name $current $parent]
+ # Redefine
+ if {$defined != {}} {
+ $status_label configure -text \
+ [mc "Removing key combination for action \"%s\"" [lindex $defined 1]]
+ set defined [lindex $defined 0]
+ set cat [string replace [$treeWidget parent $defined] 0 1]
+ set local_DB($cat:$defined) {}
+ set dt [$treeWidget itemcget $defined -data]
+ set txt [lindex $dt 0]
+ set dt [lindex $dt 1]
+ $treeWidget itemconfigure $defined \
+ -text $txt \
+ -data [list $txt $dt {}]
+ # Keep
+ } {
+ $status_label configure -text {}
+ }
+
+ # Adjust local database and the tree widget
+ set local_DB($category:$currentNode) $current
+ $treeWidget itemconfigure $currentNode \
+ -text $text \
+ -data [list $text_org $default $current]
+
+ # Adjust modifed flags and disable buttons "Accept" and "Original"
+ set changed 0
+ set anything_modified 1
+ ena_dis__accept_discard 0
+ }
+
+ ## Discard new key combination fot the currently selected action
+ # @return void
+ proc discard_current {} {
+ variable changed ;# Bool: Settings changed
+ variable treeWidget ;# ID of the tree widget
+ variable current_entry ;# ID of entry "Current shortcut"
+ variable status_label ;# ID of status label
+ variable currentNode ;# ID of the currently selected tree node
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+
+ # Restore prevoius content of entry "Current shortcut"
+ $current_entry delete 0 end
+ $current_entry insert end [simplify_key_seq \
+ [lindex [$treeWidget itemcget $currentNode -data] 2]]
+
+ # Clear status label
+ $status_label configure -text {}
+
+ # Disable buttons "Accept" and "Original"
+ ena_dis__accept_discard 0
+ set changed 0
+ }
+
+ ## Ask user about saving the last change and conditionly save it
+ # @return void
+ proc current_item_changed {} {
+ variable changed ;# Bool: Settings changed
+ variable currentNode ;# ID of the currently selected tree node
+ variable win ;# ID of toplevel dialog window
+
+ set changed 0
+ if {![tk_messageBox \
+ -type yesno \
+ -parent $win \
+ -icon question \
+ -title [mc "Item changed"] \
+ -message [mc "The prevoius item was modified. Do you want to save it ?"] \
+ ]} {
+ return
+ }
+
+ accept_current
+ }
+
+ ## Translate key combination acceptable by Tk to "human readable" representation
+ # @parm String key_seq - Human readable representation of a key combination
+ # @return String - Key combination acceptable by Tk
+ proc extend_key_seq {key_seq} {
+ if {$key_seq == {}} {
+ return {}
+ }
+
+ regsub -all {\+} $key_seq {-} key_seq
+ regsub {Ctrl\-} $key_seq {Control-} key_seq
+ set last_char [string index $key_seq end]
+ if {![string compare {Shift-} [string range $key_seq {end-6} {end-1}]]} {
+ set last_char [string toupper $last_char]
+ set key_seq [string range $key_seq 0 {end-7}]
+ append key_seq $last_char
+ } elseif {[string index $key_seq {end-1}] == {-}} {
+ set key_seq [string replace $key_seq end end [string tolower $last_char]]
+ }
+
+ return $key_seq
+ }
+
+ ## Find name of action specified by the given key combination
+ # @parm String key_seq - Key combination acceptable by Tk
+ # @parm String parent_node - Parent node (category)
+ # @return String - Action name or {}
+ proc key_seq_to_name {key_seq parent_node} {
+ variable treeWidget ;# ID of the tree widget
+
+ if {$key_seq == {}} {
+ return {}
+ }
+
+ # Search the tree widget
+ foreach node [$treeWidget nodes $parent_node] {
+ if {![string compare $key_seq \
+ [lindex [$treeWidget itemcget $node -data] 2]]} \
+ {
+ return [list $node \
+ [string trimright \
+ [lindex [$treeWidget itemcget $node -data] 0]]]
+ }
+ }
+
+ return {}
+ }
+
+ ## Enable/Disable buttons "Discard" and "Accept"
+ # @parm Bool ena_dis - Enable/Disable (1 == enable; 0 == disable)
+ # @return void
+ proc ena_dis__accept_discard {ena_dis} {
+ variable discard_button ;# ID of button "Discard"
+ variable accept_button ;# ID of button "Accept"
+
+ if {$ena_dis} {
+ $discard_button configure -state normal
+ $accept_button configure -state normal
+ } {
+ $discard_button configure -state disabled
+ $accept_button configure -state disabled
+ }
+ }
+
+ ## Search the given string in the tree widget
+ # @parm String string - string to find
+ # @return Bool - always 1
+ proc search {string} {
+ variable search_entry ;# ID of entry widget on search panel
+ variable search_clear ;# ID of button "Clear search entry"
+ variable treeWidget ;# ID of the tree widget
+ variable search_in_P ;# Bool: search in progress
+ variable changed ;# Bool: Settings changed
+
+ # Empty input string
+ if {$string == {}} {
+ $search_clear configure -state disabled
+ $search_entry configure -style TEntry
+ return 1
+ }
+ $search_clear configure -state normal
+
+ # String to lowercase
+ set string [string tolower $string]
+
+ # Search all nodes
+ foreach top [$treeWidget nodes root] {
+ foreach node [$treeWidget nodes $top] {
+ set text [$treeWidget itemcget $node -text]
+ set text [string tolower $text]
+
+ # String found
+ if {[string first $string $text] != -1} {
+ # Select the node
+ set search_in_P 1
+ $treeWidget opentree [$treeWidget parent $node]
+ $treeWidget selection set $node
+ $treeWidget see $node
+
+ # Adjust entry widget and return
+ set search_in_P 0
+ $search_entry configure -style StringFound.TEntry
+ return 1
+ }
+ }
+ }
+
+ # String not found
+ $search_entry configure -style StringNotFound.TEntry
+ return 1
+ }
+
+ ## Retrieve settings related to this dialog from the program
+ # @return void
+ proc getSettings {} {
+ variable local_DB ;# Local database of shortcuts
+
+ foreach key [array names ::SHORTCUTS_DB] {
+ set local_DB($key) $::SHORTCUTS_DB($key)
+ }
+ }
+
+ ## Change content of configuration variables
+ # @return void
+ proc use_settings {} {
+ variable local_DB ;# Local database of shortcuts
+
+ foreach key [array names local_DB] {
+ set ::SHORTCUTS_DB($key) $local_DB($key)
+ }
+ }
+
+ ## Adjust application to fit new settings
+ # @return Bool - result
+ proc apply_settings {} {
+ # Adjust main window
+ shortcuts_reevaluate
+ mainmenu_redraw
+
+ # Adjust projects
+ foreach project ${::X::openedProjects} {
+
+ # Adjust editors
+ foreach editor [$project cget -editors] {
+ $editor shortcuts_reevaluate
+ $editor makePopupMenu
+ }
+
+ # Adjust right panel
+ $project rightPanel_makePopupMenu
+ $project rightPanel_watch_shortcuts_reevaluate
+ # Adjust todo list
+ $project TodoProc_makePopupMenu
+ $project TodoProc_shortcuts_reevaluate
+ # Adjust messages text
+ $project messages_text_makePopupMenu
+ $project messages_text_shortcuts_reevaluate
+ # Adjust filelist
+ $project filelist_makePopupMenu
+ $project filelist_fsb_makePopupMenu
+ }
+
+ # Restore previous state of menu items (enabled / disabled)
+ ::X::disaena_menu_toolbar_for_current_project
+ }
+
+ ## Save configuration to config file
+ # @return void
+ proc save_config {} {
+ variable local_DB ;# Local database of shortcuts
+
+ foreach key [array names local_DB] {
+ ::settings setValue "Shortcuts/$key" $local_DB($key)
+ }
+
+ # Commit
+ ::settings saveConfig
+ }
+
+ ## Load configuratin from config file
+ # @return void
+ proc load_config {} {
+ array unset ::SHORTCUTS_DB
+ foreach block ${::SHORTCUTS_LIST} {
+ set category [lindex $block 0] ;# Shortcut category (eg. 'edit')
+ set block [lreplace $block 0 2] ;# Item definitions
+ set len [llength $block] ;# Length of data block
+
+ # Iterate over data block and redefine local database
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ set key [lindex $block $i] ;# Item name
+
+ set ::SHORTCUTS_DB($category:$key) \
+ [::settings getValue "Shortcuts/$category:$key" \
+ [lindex $block [list $j 0]]]
+ }
+ }
+ }
+
+ ## Destroy the dialog
+ # @return void
+ proc CANCEL {} {
+ variable win ;# ID of toplevel dialog window
+ variable local_DB ;# Local database of shortcuts
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+ variable root_hard_cd ;# List of hadrcoded shortcuts (main window only)
+
+ # Discard local database of shortcuts
+ array unset local_DB
+ unset root_hard_cd
+
+ # Destroy dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Use settings and destroy the dialog
+ # @return void
+ proc OK {} {
+ variable win ;# ID of toplevel dialog window
+ variable changed ;# Bool: Settings changed
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+
+ # Save last changed item
+ if {$changed} {
+ current_item_changed
+ }
+
+ # Use and save settings
+ if {$anything_modified} {
+ use_settings
+ apply_settings
+ save_config
+ }
+
+ # Destroy the dialog window
+ CANCEL
+ }
+
+ ## Restrore defaults
+ # @return void
+ proc DEFAULTS {} {
+ variable local_DB ;# Local database of shortcuts
+ variable treeWidget ;# ID of the tree widget
+ variable win ;# ID of toplevel dialog window
+ variable changed ;# Bool: Settings changed
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+
+ # Ask user
+ if {![tk_messageBox \
+ -parent $win \
+ -type yesno \
+ -title [mc "Confirmation required"] \
+ -icon question \
+ -message [mc "This will discard all shortcut settings and replace them with defaults. Are you sure by that ?"]\
+ ]
+ } {
+ return
+ }
+
+ # Adjust flags
+ set changed 0 ;# Last item modified --> NO
+ set anything_modified 1 ;# Any item modified --> YES
+
+ # Reset local database of shortcuts
+ array unset local_DB
+ foreach block ${::SHORTCUTS_LIST} {
+ set category [lindex $block 0] ;# Shortcut category (eg. 'edit')
+ set block [lreplace $block 0 2] ;# Item definitions
+ set len [llength $block] ;# Length of data block
+
+ # Redefine local database
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ set key [lindex $block $i]
+ set local_DB($category:$key) [lindex $block [list $j 0]]
+ }
+ }
+
+ ## Refresh content of the tree widget
+ $treeWidget selection clear
+ # Iterate over toplevel items
+ foreach top [$treeWidget nodes root] {
+ set cat [string replace $top 0 1] ;# Shortcut category (eg. 'edit')
+
+ # Iterate over lowlevel items
+ foreach node [$treeWidget nodes $top] {
+ # Long key sequence (for Tk)
+ set key_seq [regsub {Key(Press|Release)?\-} $local_DB($cat:$node) {}]
+
+ # Determinate new item data
+ set data [$treeWidget itemcget $node -data]
+ lset data 2 $key_seq
+
+ # Determinate item text
+ set text_and_key [lindex $data 0]
+ append text_and_key [simplify_key_seq $key_seq]
+
+ # Adjust item
+ $treeWidget itemconfigure $node \
+ -data $data \
+ -text $text_and_key
+ }
+ }
+ }
+}
diff --git a/lib/configdialogs/simulator_config.tcl b/lib/configdialogs/simulator_config.tcl
new file mode 100755
index 0000000..38e9e49
--- /dev/null
+++ b/lib/configdialogs/simulator_config.tcl
@@ -0,0 +1,423 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements simulator configuration dialog
+# --------------------------------------------------------------------------
+
+namespace eval simulator {
+
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened 0 ;# Bool: True if this dialog is already opened
+
+ # List of default settings
+ variable defaults {
+ {reverse_run_steps 10}
+ {ignore_read_from_wr_only 0}
+ {ignore_invalid_reti 0}
+ {ignore_watchdog_reset 0}
+ {ignore_stack_overflow 0}
+ {ignore_stack_underflow 0}
+ {ignore_invalid_ins 0}
+ {ignore_invalid_IDATA 0}
+ {ignore_invalid_XDATA 0}
+ {ignore_invalid_BIT 0}
+ {ignore_invalid_CODE 0}
+ {ignore_EEPROM_WR_fail 0}
+ {ignore_EEPROM_WR_abort 0}
+ {ignore_invalid_USB 0}
+ {ignore_invalid_UMC 0}
+ {ignore_invalid_TMC 0}
+ {undefined_value 2}
+ }
+
+ # Option variables
+ variable reverse_run_steps ;# Int: Number of steps which can be taken back
+ variable ignore_watchdog_reset ;# Bool: Ignore reset invoked by watchdog overflow
+ variable ignore_read_from_wr_only ;# Bool: Ignore reading from read only register
+ variable ignore_stack_overflow ;# Bool: Do not show "Stack overflow" dialog
+ variable ignore_stack_underflow ;# Bool: Do not show "Stack underflow" dialog
+ variable ignore_invalid_reti ;# Bool: Ignore invalid return fom interrupt
+ variable ignore_invalid_ins ;# Bool: Ignore invalid instructions
+ variable ignore_invalid_IDATA ;# Bool: Ignore access to unimplemented IDATA memory
+ variable ignore_invalid_XDATA ;# Bool: Ignore access to unimplemented XDATA memory
+ variable ignore_invalid_BIT ;# Bool: Ignore access to unimplemented bit
+ variable ignore_invalid_CODE ;# Bool: Ignore access to unimplemented CODE memory
+ variable ignore_EEPROM_WR_fail ;# Bool: Ignore EEPROM write failure
+ variable ignore_EEPROM_WR_abort ;# Bool: Ignore EEPROM write abort
+ variable ignore_invalid_USB ;# Bool: Ignore UART frame discart
+ variable ignore_invalid_UMC ;# Bool: Ignore invalid UART mode change
+ variable ignore_invalid_TMC ;# Bool: Ignore invalid Timer/Counter mode change
+ variable undefined_value ;# Int: How to handle undefined values (0 == 0; 1 == 255; 2 == random)
+
+
+ ## Create the dialog
+ # @return void
+ proc mkDialog {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Destroy the dialog if it's alredy opened
+ if {$dialog_opened} {
+ destroy .simulator_config_dialog
+ }
+ set dialog_opened 1
+
+ # Get settings from Compiler NS
+ getSettings
+
+ # Create toplevel window
+ set win [toplevel .simulator_config_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ label $win.header_label \
+ -compound left \
+ -image ::ICONS::32::kcmmemory \
+ -text [mc "Simulator configuration"] \
+ -font [font create \
+ -size -20]
+
+ ## Create notebook
+ set nb [ttk::notebook $win.nb]
+ # Tab "Warning dialogs"
+ set warnings_tab [frame $nb.warnings_tab]
+ $nb add $warnings_tab -text [mc "Warning dialogs"]
+ # Tab "Other"
+ set other_tab [frame $nb.other_tab]
+ $nb add $other_tab -text [mc "Other"]
+
+ #
+ ## Tab "Warning dialogs"
+ #
+ set row 0
+ foreach text {
+ {Ignore stack overflow}
+ {Ignore stack underflow}
+ {-}
+ {Ignore invalid instructions}
+ {Ignore watchdog overflow}
+ {Ignore invalid return from interrupt}
+ {Ignore reading from write only register}
+ {-}
+ {Ignore invalid access to IDATA/SFR}
+ {Ignore invalid access to EDATA}
+ {Ignore invalid access to XDATA}
+ {Ignore invalid access to bit}
+ {Ignore invalid access to CODE}
+ {-}
+ {Ignore EEPROM write failure}
+ {Ignore EEPROM write abort}
+ {-}
+ {Ignore UART frame discard}
+ {Ignore illegal UART mode change}
+ {Ignore illegal Timer/Counter mode change}
+ } helptext {
+ {Check this to disable warning on stack overflow}
+ {Check this to disable warning on stack underflow}
+ {-}
+ {Check this to disable warning on\ninvalid instruction}
+ {Do not stop simulation on device reset\ninvoked by watchog timer overflow}
+ {Do not show warning dialog when program tring to return from interrupt which has not been invoked}
+ {Do not display warning dialog when\nreading from write-only register}
+ {-}
+ {Do not display dialog "Undefined result" when simulated program\naccessing unimplemented Internal Data Memory (IDATA) or SFR area}
+ {Do not display dialog "Undefined result" when simulated program\naccessing unimplemented Expanded Data Memory (EDATA)}
+ {Do not display dialog "Undefined result" when simulated program\naccessing unimplemented External Data Memory (XDATA)}
+ {Do not display dialog "Undefined result" when simulated program\naccessing unimplemented bit in IDATA or SFR area}
+ {Do not display dialog "Undefined result" when simulated program\naccessing unimplemented Program Memory (CODE)}
+ {-}
+ {Check this to disable warning on\ndata eeprom write failure}
+ {Check this to disable warning on\ndata eeprom write abort}
+ {-}
+ {Check this to disable warning on UART frame discard}
+ {Check this to disable warning on illegal UART mode change}
+ {Check this to disable warning on illegal Timer/Counter mode change}
+ } variable {
+ ignore_stack_overflow ignore_stack_underflow
+ -
+ ignore_invalid_ins ignore_watchdog_reset
+ ignore_invalid_reti ignore_read_from_wr_only
+ -
+ ignore_invalid_IDATA ignore_invalid_EDATA
+ ignore_invalid_XDATA ignore_invalid_BIT
+ ignore_invalid_CODE
+ -
+ ignore_EEPROM_WR_fail ignore_EEPROM_WR_abort
+ -
+ ignore_invalid_USB ignore_invalid_UMC
+ ignore_invalid_TMC
+ } {
+ incr row
+
+ # Create separator
+ if {$text == {-}} {
+ grid [ttk::separator $warnings_tab.sep_$row \
+ -orient horizontal \
+ ] -column 0 -row $row -columnspan 2 -sticky we -pady 5 -padx 5
+ continue
+ }
+
+ # Create
+ grid [Label $warnings_tab.label__$row \
+ -text $text -helptext [subst $helptext] \
+ ] -row $row -column 0 -sticky w -padx 5
+ grid [checkbutton $warnings_tab.chbutton_$row \
+ -variable ::configDialogs::simulator::$variable \
+ ] -row $row -column 1 -sticky e -padx 5
+ DynamicHelp::add $warnings_tab.chbutton_$row \
+ -text [subst $helptext]
+ }
+ grid columnconfigure $warnings_tab 0 -minsize 250
+ grid columnconfigure $warnings_tab 1 -weight 1
+
+ #
+ # Tab "Other"
+ #
+
+ # LabelFrame: "Undefined values"
+ set undefined_labelframe [ttk::labelframe $other_tab.undefined_labelframe \
+ -text [mc "Undefined values"] -padding 7 \
+ ]
+ pack [radiobutton $undefined_labelframe.random \
+ -value 2 -text [mc "Return random value"] \
+ -variable ::configDialogs::simulator::undefined_value \
+ ] -anchor w
+ pack [radiobutton $undefined_labelframe.zero \
+ -value 0 -text [mc "Return zero value"] \
+ -variable ::configDialogs::simulator::undefined_value \
+ ] -anchor w
+ pack [radiobutton $undefined_labelframe.one \
+ -value 1 -text [mc "Return highest possible value"] \
+ -variable ::configDialogs::simulator::undefined_value \
+ ] -anchor w
+ pack $undefined_labelframe -fill x -padx 5 -pady 10
+
+ # LabelFrame: "Reverse run"
+ set reverse_run_labelframe [ttk::labelframe $other_tab.reverse_run_labelframe \
+ -text [mc "Reverse run"] -padding 7 \
+ ]
+ grid [Label $reverse_run_labelframe.rrun_lbl \
+ -text [mc "Stack capacity"] \
+ -helptext [mc "Number of steps which can be taken back"] \
+ ] -row 4 -column 0 -sticky w -padx 5
+ grid [spinbox $reverse_run_labelframe.rrun_spinbox \
+ -from 0 -to 1000 -bg white -validate all -width 4 \
+ -vcmd "::configDialogs::simulator::rrun_spinbox_val %P" \
+ -textvariable ::configDialogs::simulator::reverse_run_steps \
+ ] -row 4 -column 1 -sticky we -padx 5
+ DynamicHelp::add $reverse_run_labelframe.rrun_spinbox \
+ -text [mc "Number of steps which can be taken back"]
+ grid columnconfigure $reverse_run_labelframe 0 -minsize 250
+ grid columnconfigure $reverse_run_labelframe 1 -weight 1
+ pack $reverse_run_labelframe -fill x -padx 5 -pady 10
+
+ # Raise tab "Output"
+ $nb select $warnings_tab
+
+ # Create button frame at the bottom
+ set but_frame [frame $win.button_frame]
+ # Button "Defaults"
+ pack [ttk::button $but_frame.but_default \
+ -text [mc "Defaults"] \
+ -command {::configDialogs::simulator::DEFAULTS} \
+ ] -side left
+ DynamicHelp::add $but_frame.but_default -text [mc "Reset settings to defaults"]
+ # Button "Ok"
+ pack [ttk::button $but_frame.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::simulator::OK} \
+ ] -side right
+ # Button "Cancel"
+ pack [ttk::button $but_frame.but_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::configDialogs::simulator::CANCEL} \
+ ] -side right
+
+ # Pack frames and notebook
+ pack $win.header_label -side top -pady 6
+ pack $nb -side top -fill both -expand 1 -padx 10
+ pack $but_frame -side top -fill x -expand 1 -anchor s -padx 10 -pady 5
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::configure
+ wm transient $win .
+ wm title $win [mc "Simulator configuration - %s" ${::APPNAME}]
+ wm minsize $win 380 480
+ raise $win
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW {
+ ::configDialogs::simulator::CANCEL
+ }
+ tkwait window $win
+ }
+
+ ## Validate contents of spinbox in section "Reverse Run"
+ # @parm String content - String to validate
+ # @return Bool - validation result (0 == failed; 1 == successfull)
+ proc rrun_spinbox_val {content} {
+ if {![string is digit $content]} {
+ return 0
+ }
+ if {$content > 1000} {
+ return 0
+ }
+ return 1
+ }
+
+ ## Set configuration variable
+ # This function is unsafe -- you must be sure by the given arguments
+ # @parm String variable - variable to set
+ # @parm Mixed value - new value
+ proc set_variable {variable value} {
+ variable reverse_run_steps ;# Int: Number of steps which can be taken back
+ variable ignore_watchdog_reset ;# Bool: Ignore reset invoked by watchdog overflow
+ variable ignore_read_from_wr_only ;# Bool: Ignore reading from read only register
+ variable ignore_invalid_reti ;# Bool: Ignore invalid return fom interrupt
+ variable ignore_stack_overflow ;# Bool: Do not show "Stack overflow" dialog
+ variable ignore_stack_underflow ;# Bool: Do not show "Stack underflow" dialog
+ variable ignore_invalid_ins ;# Bool: Ignore invalid instructions
+ variable ignore_invalid_IDATA ;# Bool: Ignore access to unimplemented IDATA memory
+ variable ignore_invalid_EDATA ;# Bool: Ignore access to unimplemented EDATA memory
+ variable ignore_invalid_XDATA ;# Bool: Ignore access to unimplemented XDATA memory
+ variable ignore_invalid_BIT ;# Bool: Ignore access to unimplemented bit
+ variable ignore_invalid_CODE ;# Bool: Ignore access to unimplemented CODE memory
+ variable ignore_EEPROM_WR_fail ;# Bool: Ignore EEPROM write failure
+ variable ignore_EEPROM_WR_abort ;# Bool: Ignore EEPROM write abort
+ variable undefined_value ;# Int: How to handle undefined values (0 == 0; 1 == 255; 2 == random)
+
+ getSettings
+ set $variable $value
+ use_settings
+ save_config
+ }
+
+ ## Retrieve settings from simulator NS
+ # @return void
+ proc getSettings {} {
+ variable defaults ;# List of default settings
+
+ # Set local option variables
+ foreach var $defaults {
+ set var [lindex $var 0]
+ set ::configDialogs::simulator::${var} [subst "\$::Simulator::$var"]
+ }
+ }
+
+ ## Set simulator acording to local settings
+ # @return void
+ proc use_settings {} {
+ variable reverse_run_steps ;# Int: Number of steps which can be taken back
+ variable defaults ;# List of default settings
+
+ # Adjust RR stack capacity
+ if {$reverse_run_steps == {}} {
+ set reverse_run_steps 0
+ }
+
+ # Set option variables
+ foreach var $defaults {
+ set var [lindex $var 0]
+ set ::Simulator::$var [subst "\$::configDialogs::simulator::${var}"]
+ }
+ }
+
+ ## Save settings to the config file
+ # @return void
+ proc save_config {} {
+ variable defaults ;# List of default settings
+
+ # Save option variables
+ foreach var $defaults {
+ set var [lindex $var 0]
+ ::settings setValue "Simulator/$var" [subst "\$::Simulator::${var}"]
+ }
+
+ # Synchronize
+ ::settings saveConfig
+ }
+
+ ## Load settings from config file
+ # @return void
+ proc load_config {} {
+ variable defaults ;# List of default settings
+
+ # Load normal options
+ foreach item $defaults {
+ set var [lindex $item 0]
+ set val [lindex $item 1]
+ set ::Simulator::${var} [::settings getValue "Simulator/$var" $val]
+ }
+ }
+
+ ## Destroy the dialog
+ # @return void
+ proc CANCEL {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Destroy dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Use settings and destroy the dialog
+ # @return void
+ proc OK {} {
+ # Use and save settings
+ use_settings
+ save_config
+
+ # Destroy dialog window
+ CANCEL
+ }
+
+ ## Restrore defaults
+ # @return void
+ proc DEFAULTS {} {
+ variable win ;# ID of toplevel dialog window
+ variable defaults ;# List of default settings
+
+ if {[tk_messageBox \
+ -parent $win \
+ -type yesno \
+ -icon question \
+ -title [mc "Are you sure ?"] \
+ -message [mc "Are you sure you want to resore default settings"] \
+ ] != {yes}} {
+ return
+ }
+
+ # Restore normal options
+ foreach item $defaults {
+ set var [lindex $item 0]
+ set val [lindex $item 1]
+ set ::configDialogs::simulator::${var} $val
+ }
+ }
+}
diff --git a/lib/configdialogs/terminal_config.tcl b/lib/configdialogs/terminal_config.tcl
new file mode 100755
index 0000000..831540f
--- /dev/null
+++ b/lib/configdialogs/terminal_config.tcl
@@ -0,0 +1,374 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements terminal configuration dialog
+# --------------------------------------------------------------------------
+
+namespace eval terminal {
+ variable dialog_opened 0 ;# Bool: True if this dialog is already opened
+ variable win ;# ID of dialog toplevel window
+ variable changed 0 ;# Bool: Settings changed
+ variable example_text ;# Widget: Label widget containing example text
+ variable selected_font ;# Font: Current font
+ variable fg_clr_but ;# Widget: Button for selecting foreground color
+ variable bg_clr_but ;# Widget: Button for selecting background color
+
+ ## Configuration variables
+ variable configuration ;# Array: Configuration array
+
+ ## Create the dialog
+ # @return void
+ proc mkDialog {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+ variable configuration ;# Array: Configuration array
+ variable changed ;# Bool: Settings changed
+ variable example_text ;# Widget: Label widget containing example text
+ variable selected_font ;# Font: Current font
+ variable fg_clr_but ;# Widget: Button for selecting foreground color
+ variable bg_clr_but ;# Widget: Button for selecting background color
+
+ # Destroy the dialog if it's alredy opened
+ if {$dialog_opened} {
+ destroy .terminal_config_dialog
+ }
+
+ set dialog_opened 1
+ set changed 0
+
+ # Get settings from main NS
+ getSettings
+
+ # Create toplevel window
+ set win [toplevel .terminal_config_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ label $win.header_label \
+ -text [mc "Terminal configuration"] \
+ -font [font create -size -20]
+
+ # Create horizontal separator
+ Separator $win.sep -orient horizontal
+
+ ## Create main frame
+ set main_frame [frame $win.main_frame]
+ set row 0
+ # Foreground color
+ grid [label $main_frame.fg_lbl \
+ -text [mc "Foreground color"] \
+ ] -row $row -column 0 -sticky w
+ set fg_clr_but [button $main_frame.fg_but \
+ -bd 1 -relief raised -pady 0 -width 10 \
+ -bg $configuration(fg) \
+ -activebackground $configuration(fg) \
+ -command "::configDialogs::terminal::select_color {foreground} fg $main_frame.fg_but" \
+ ]
+ grid $fg_clr_but -column 1 -row $row -sticky wens
+ incr row
+ # Background color
+ grid [label $main_frame.bg_lbl \
+ -text [mc "Background color"] \
+ ] -row $row -column 0 -sticky w
+ set bg_clr_but [button $main_frame.bg_but \
+ -bd 1 -relief raised -pady 0 -width 10 \
+ -bg $configuration(bg) \
+ -activebackground $configuration(bg) \
+ -command "::configDialogs::terminal::select_color {background} bg $main_frame.bg_but" \
+ ]
+ grid $bg_clr_but -column 1 -row $row -sticky wens
+ incr row
+ # Font size
+ grid [label $main_frame.font_size_lbl \
+ -text [mc "Font size"] \
+ ] -row $row -column 0 -sticky w
+ grid [spinbox $main_frame.font_size_spb \
+ -from 4 -to 22 -validate all -width 0 \
+ -vcmd {::configDialogs::terminal::font_size_valiade %P} \
+ -textvariable ::configDialogs::terminal::configuration(font_size) \
+ -command ::configDialogs::terminal::font_changed \
+ ] -row $row -column 1 -sticky we
+ incr row
+ # Font family
+ grid [label $main_frame.font_family_lbl \
+ -text [mc "Font family"] \
+ ] -row $row -column 0 -sticky w
+ grid [ttk::combobox $main_frame.font_family_cbx \
+ -state readonly \
+ -values [lsort [font families]] \
+ -width 20 \
+ -textvariable ::configDialogs::terminal::configuration(font_family) \
+ ] -row $row -column 1 -sticky we
+ bind $main_frame.font_family_cbx <<ComboboxSelected>> \
+ {::configDialogs::terminal::font_changed}
+ incr row
+ # Example text
+ set selected_font [font create \
+ -family $configuration(font_family) \
+ -size -$configuration(font_size) \
+ ]
+ set example_text [label $main_frame.example_text_lbl \
+ -text "rxvt-unicode " \
+ -font $selected_font \
+ ]
+ grid $example_text -row $row -column 0 -sticky w -columnspan 2
+ # Finalize
+ grid columnconfigure $main_frame 0 -weight 1
+
+ # Button "Restart terminal emulator"
+ set restart_but [ttk::button $win.restart_but \
+ -text [mc "Use settings and restart terminal emulator"] \
+ -compound left \
+ -image ::ICONS::16::reload \
+ -command {::configDialogs::terminal::RESTART} \
+ ]
+
+ ## Button frame at the bottom
+ set but_frame [frame $win.button_frame]
+ # Button "Reset"
+ pack [ttk::button $but_frame.but_default \
+ -text [mc "Reset to defaults"] \
+ -command {::configDialogs::terminal::DEFAULTS} \
+ ] -side left
+ DynamicHelp::add $but_frame.but_default \
+ -text [mc "Reset all settings to defaults"]
+ # Button "Ok"
+ pack [ttk::button $but_frame.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::terminal::OK} \
+ ] -side right
+ DynamicHelp::add $but_frame.but_ok \
+ -text [mc "Commit new settings"]
+ # Button "Cancel"
+ pack [ttk::button $but_frame.but_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::configDialogs::terminal::CANCEL} \
+ ] -side right
+ DynamicHelp::add $but_frame.but_cancel \
+ -text [mc "Take changes back and close dialog"]
+
+ # Pack frames and notebook
+ pack $win.header_label -side top -pady 6
+ pack $win.sep -side top -fill x -after $win.header_label
+ pack $main_frame -side top -padx 10 -anchor nw -pady 10 -fill x
+ pack $but_frame -side bottom -fill x -anchor s -padx 10 -pady 5
+ pack $restart_but -side bottom -fill x -expand 1 -anchor s -padx 10
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::configure
+ wm transient $win .
+ wm title $win [mc "Configure terminal emulator"]
+ wm minsize $win 380 250
+ raise $win
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW {
+ ::configDialogs::terminal::CANCEL
+ }
+ tkwait window $win
+ }
+
+ ## Valiadte content of font size spinbox
+ # @pamr String content - String to valiadte
+ # @return void
+ proc font_size_valiade {content} {
+ if {![string is digit $content]} {
+ return 0
+ }
+ if {$content < 4 || $content > 22} {
+ return 0
+ }
+ return 1
+ }
+
+ ## Change font for example text
+ # @return void
+ proc font_changed {} {
+ variable configuration ;# Array: Configuration array
+ variable example_text ;# Widget: Label widget containing example text
+ variable selected_font ;# Font: Current font
+ variable changed ;# Bool: Settings changed
+
+ font delete $selected_font
+ set selected_font [font create \
+ -family $configuration(font_family) \
+ -size -$configuration(font_size) \
+ ]
+ $example_text configure -font $selected_font
+ set changed 1
+ }
+
+ ## Select color
+ # @parm String what_clr - What color (foreground / background ...)
+ # @parm String var - Key in configuration array
+ # @parm Widget button - Source button
+ # @return void
+ proc select_color {what_clr var button} {
+ variable configuration ;# Array: Configuration array
+ variable win ;# ID of toplevel dialog window
+ variable changed ;# Bool: Settings changed
+
+ switch -- $what_clr {
+ {foreground} {
+ set txt [mc "Select foreground color"]
+ }
+ {background} {
+ set txt [mc "Select background color"]
+ }
+ }
+
+ set color [SelectColor .select_color \
+ -parent $win \
+ -color $configuration($var) \
+ -title $txt \
+ ]
+
+ # Set new content of the given variable and button background color
+ if {$color != {}} {
+ set configuration($var) $color
+ $button configure -bg $color -activebackground $color
+
+ # Adjust status changed
+ set changed 1
+ }
+ }
+
+ ## Retrieve settings from main NS
+ # @return void
+ proc getSettings {} {
+ variable configuration ;# Array: Configuration array
+ array set configuration [array get ::Terminal::configuration]
+ }
+
+ ## Set application acording to local settings
+ # @return void
+ proc use_settings {} {
+ variable configuration ;# Array: Configuration array
+ array set ::Terminal::configuration [array get configuration]
+ }
+
+ ## Save settings to the config file
+ # @return void
+ proc save_config {} {
+ variable configuration ;# Array: Configuration array
+
+ foreach key [array names configuration] {
+ ::settings setValue "Terminal emulator/$key" $::Terminal::configuration($key)
+ }
+
+ ::settings saveConfig
+ }
+
+ ## Load configuration from config file
+ # @return void
+ proc load_config {} {
+ # Load configuration
+ array set default_conf ${::Terminal::configuration_def}
+ foreach key [array names ::Terminal::configuration] {
+ set ::Terminal::configuration($key) [::settings getValue \
+ "Terminal emulator/$key" $default_conf($key) \
+ ]
+ }
+
+ # Validate configuration
+ if {![regexp {^#[0-9a-fA-F]{6}$} ${::Terminal::configuration(bg)}]} {
+ puts stderr [mc "Invalid value of key: '%s'" {bg}]
+ set ::Terminal::configuration(bg) {#FFFFFF}
+ }
+ if {![regexp {^#[0-9a-fA-F]{6}$} ${::Terminal::configuration(fg)}]} {
+ puts stderr [mc "Invalid value of key: '%s'" {fg}]
+ set ::Terminal::configuration(fg) {#000000}
+ }
+ if {
+ ![regexp {^\d+$} ${::Terminal::configuration(font_size)}]
+ ||
+ ${::Terminal::configuration(font_size)} < 4
+ ||
+ ${::Terminal::configuration(font_size)} > 22
+ } {
+ puts stderr [mc "Invalid value of key: '%s'" {font_size}]
+ set ::Terminal::configuration(font_size) 13
+ }
+ if {![string length [string trim ${::Terminal::configuration(font_family)}]]} {
+ puts stderr [mc "Invalid value of key: '%s'" {font_family}]
+ set ::Terminal::configuration(font_family) $::DEFAULT_FIXED_FONT
+ }
+ }
+
+ ## Resart terminal emulators for all projects
+ # @return void
+ proc RESTART {} {
+ use_settings
+ foreach project ${::X::openedProjects} {
+ $project terminal_restart
+ }
+ }
+
+ ## Destroy the dialog
+ # @return void
+ proc CANCEL {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Destroy dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Use settings and destroy the dialog
+ # @return void
+ proc OK {} {
+ variable win ;# ID of toplevel dialog window
+ variable changed ;# Bool: Settings changed
+
+ # Use and save settings
+ if {$changed} {
+ use_settings
+ save_config
+ }
+
+ # Destroy dialog window
+ CANCEL
+ }
+
+ ## Restrore defaults
+ # @return void
+ proc DEFAULTS {} {
+ variable configuration ;# Array: Configuration array
+ variable fg_clr_but ;# Widget: Button for selecting foreground color
+ variable bg_clr_but ;# Widget: Button for selecting background color
+
+ array set configuration ${::Terminal::configuration_def}
+ $fg_clr_but configure \
+ -bg $configuration(fg) \
+ -activebackground $configuration(fg)
+ $bg_clr_but configure \
+ -bg $configuration(bg) \
+ -activebackground $configuration(bg)
+ }
+}
diff --git a/lib/configdialogs/toolbar_config.tcl b/lib/configdialogs/toolbar_config.tcl
new file mode 100755
index 0000000..1ae5b5c
--- /dev/null
+++ b/lib/configdialogs/toolbar_config.tcl
@@ -0,0 +1,706 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements main toolbar configuration dialog
+# --------------------------------------------------------------------------
+
+namespace eval toolbar {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened 0 ;# Bool: True if this dialog is already opened
+
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable changed ;# Bool: Settings changed
+ variable apply_button ;# ID of button "Apply"
+
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+ variable options_ListBox ;# ID of ListBox containing avaliable icons
+ variable current_search_entry ;# ID of search EntryBox for $current_ListBox
+ variable options_search_entry ;# ID of search EntryBox for $options_ListBox
+ variable current_search_clear ;# ID of search EntryBox clear button for $current_ListBox
+ variable options_search_clear ;# ID of search EntryBox clear button for $options_ListBox
+ variable up_button ;# ID of button "Up"
+ variable left_button ;# ID of button "Left"
+ variable right_button ;# ID of button "Right"
+ variable down_button ;# ID of button "Down"
+
+ ## Create the dialog
+ # @return void
+ proc mkDialog {} {
+ variable win ;# ID of toplevel dialog window
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable changed ;# Bool: Settings changed
+ variable apply_button ;# ID of button "Apply"
+
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+ variable options_ListBox ;# ID of ListBox containing avaliable icons
+ variable current_search_entry ;# ID of search EntryBox for $current_ListBox
+ variable options_search_entry ;# ID of search EntryBox for $options_ListBox
+ variable current_search_clear ;# ID of search EntryBox clear button for $current_ListBox
+ variable options_search_clear ;# ID of search EntryBox clear button for $options_ListBox
+ variable up_button ;# ID of button "Up"
+ variable left_button ;# ID of button "Left"
+ variable right_button ;# ID of button "Right"
+ variable down_button ;# ID of button "Down"
+
+ # Destroy the dialog if it's alredy opened
+ if {$dialog_opened} {
+ destroy .toolbar_config_dialog
+ }
+ set anything_modified 0
+ set dialog_opened 1
+ set changed 0
+
+ # Create toplevel window
+ set win [toplevel .toolbar_config_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ label $win.header_label \
+ -compound left \
+ -image ::ICONS::32::configure \
+ -text [mc "Toolbar configuration"] \
+ -font [font create -size -20]
+
+ # Create main frame (ListBoxes and Arrows)
+ set main_frame [frame $win.main_frame]
+
+ ## Create arrows frame and buttons
+ set arrows [frame $main_frame.arrows]
+ # Arrow "Up"
+ set up_button [ttk::button $arrows.up \
+ -image ::ICONS::16::up \
+ -state disabled \
+ -style Flat.TButton \
+ -command {::configDialogs::toolbar::up} \
+ ]
+ # Arrow "Left"
+ set left_button [ttk::button $arrows.left \
+ -image ::ICONS::16::left \
+ -state disabled \
+ -style Flat.TButton \
+ -command {::configDialogs::toolbar::left} \
+ ]
+ # Arrow "Right"
+ set right_button [ttk::button $arrows.right \
+ -image ::ICONS::16::right \
+ -state disabled \
+ -style Flat.TButton \
+ -command {::configDialogs::toolbar::right} \
+ ]
+ # Arrow "Down"
+ set down_button [ttk::button $arrows.down \
+ -image ::ICONS::16::down \
+ -state disabled \
+ -style Flat.TButton \
+ -command {::configDialogs::toolbar::down} \
+ ]
+
+ # Place arrows to the grid
+ grid $up_button -column 1 -row 0
+ grid $left_button -column 0 -row 1
+ grid $right_button -column 2 -row 1
+ grid $down_button -column 1 -row 2
+
+ # Create ListBox of avaliable items and its scrollbar
+ set options_frame [frame $main_frame.options_frame]
+ set listbox_frame [frame $options_frame.listbox_frame]
+ set options_ListBox [ListBox $listbox_frame.options_ListBox \
+ -background {#FFFFFF} -deltay 21 \
+ -selectmode single \
+ -highlightcolor {#FFFFFF} \
+ -yscrollcommand "$listbox_frame.options_scrollbar set" \
+ -highlightthickness 0 \
+ ]
+ if {[winfo exists $options_ListBox.c]} {
+ bind $options_ListBox.c <Button-5> {%W yview scroll +5 units; break}
+ bind $options_ListBox.c <Button-4> {%W yview scroll -5 units; break}
+ }
+ pack $options_ListBox -fill both -expand 1 -side left
+ pack [ttk::scrollbar $listbox_frame.options_scrollbar \
+ -takefocus 0 \
+ -orient vertical \
+ -command "$options_ListBox yview" \
+ ] -side right -after $options_ListBox -fill y
+
+ # Create search bar for ListBox of avaliable items
+ set search_frame [frame $options_frame.search_frame]
+ set options_search_entry [ttk::entry $search_frame.entry \
+ -validate all \
+ -validatecommand {::configDialogs::toolbar::search O %P} \
+ ]
+ DynamicHelp::add $search_frame.entry -text [mc "Search for a string in ListBox"]
+ pack $options_search_entry -side left -fill x -expand 1
+ set options_search_clear [ttk::button $search_frame.button \
+ -image ::ICONS::16::clear_left \
+ -style Flat.TButton \
+ -command "$options_search_entry delete 0 end" \
+ -state disabled \
+ ]
+ DynamicHelp::add $search_frame.button \
+ -text [mc "Clear"]
+ pack $options_search_clear -side right -after $options_search_entry
+
+ # Pack frames of the left part (avaliable items)
+ pack $search_frame -fill x
+ pack [label $options_frame.label -text [mc "Avaliable items"]] -pady 5
+ pack $listbox_frame -fill both -expand 1
+
+
+ # Create ListBox of current items and its scrollbar
+ set current_frame [frame $main_frame.current_frame]
+ set listbox_frame [frame $current_frame.listbox_frame]
+ set current_ListBox [ListBox $listbox_frame.current_ListBox \
+ -background {#FFFFFF} -deltay 21 \
+ -selectmode single \
+ -highlightcolor {#FFFFFF} \
+ -yscrollcommand "$listbox_frame.current_scrollbar set" \
+ -highlightthickness 0 \
+ ]
+ if {[winfo exists $current_ListBox.c]} {
+ bind $current_ListBox.c <Button-5> {%W yview scroll +5 units; break}
+ bind $current_ListBox.c <Button-4> {%W yview scroll -5 units; break}
+ }
+ pack $current_ListBox -fill both -expand 1 -side left
+ pack [ttk::scrollbar $listbox_frame.current_scrollbar \
+ -takefocus 0 \
+ -orient vertical \
+ -command "$current_ListBox yview" \
+ ] -side right -after $current_ListBox -fill y
+
+ # Create search bar for ListBox of current items
+ set search_frame [frame $current_frame.search_frame]
+ set current_search_entry [ttk::entry $search_frame.entry \
+ -validate all \
+ -validatecommand {::configDialogs::toolbar::search C %P} \
+ ]
+ DynamicHelp::add $search_frame.entry -text [mc "Search for a string in ListBox"]
+ pack $current_search_entry -side left -fill x -expand 1
+ set current_search_clear [ttk::button $search_frame.button \
+ -image ::ICONS::16::clear_left \
+ -style Flat.TButton \
+ -command "$current_search_entry delete 0 end" \
+ -state disabled \
+ ]
+ DynamicHelp::add $search_frame.button \
+ -text [mc "Clear"]
+ pack $current_search_clear -side right -after $current_search_entry
+
+ # Pack frames of the left part (current items)
+ pack $search_frame -fill x
+ pack [label $current_frame.label -text [mc "Current toolbar items"]] -pady 5
+ pack $listbox_frame -fill both -expand 1
+
+
+ # Set event bindings for ListBoxes
+ bind $options_ListBox <<ListboxSelect>> \
+ "::configDialogs::toolbar::reevaluateArrows"
+ bind $current_ListBox <<ListboxSelect>> \
+ "::configDialogs::toolbar::reevaluateArrows"
+
+
+ # Pack left ListBox, arrows frame, right ListBox
+ pack $options_frame -side left -anchor n -fill both -expand 1 -padx 5
+ pack $arrows -side left -anchor center
+ pack $current_frame -side left -anchor n -fill both -expand 1 -padx 5
+
+ # Fill up ListBoxes
+ fillListBox ${::ICONBAR_CURRENT}
+
+ # Create button frame at the bottom
+ set but_frame [frame $win.button_frame]
+ # Button "Defaults"
+ pack [ttk::button $but_frame.but_default \
+ -text [mc "Defaults"] \
+ -command {::configDialogs::toolbar::DEFAULTS} \
+ ] -side left
+ DynamicHelp::add $but_frame.but_default \
+ -text [mc "Reset settings to defaults"]
+ # Button "Ok"
+ pack [ttk::button $but_frame.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::toolbar::OK} \
+ ] -side right
+ # Button "Apply"
+ set apply_button [ttk::button $but_frame.but_apply \
+ -state disabled \
+ -text [mc "Apply"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::configDialogs::toolbar::APPLY} \
+ ]
+ pack $apply_button -side right
+ # Button "Cancel"
+ pack [ttk::button $but_frame.but_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::configDialogs::toolbar::CANCEL} \
+ ] -side right
+
+ # Pack frames and notebook
+ pack $but_frame -side bottom -fill x -expand 0 -anchor s -padx 10 -pady 5
+ pack $win.header_label -side top -pady 6
+ pack $main_frame -side top -fill both -expand 1 -padx 10
+
+ # Finalize creation of the dialog
+ wm iconphoto $win ::ICONS::16::configure
+ wm transient $win .
+ wm title $win [mc "Configure Main Toolbar - %s" ${::APPNAME}]
+ wm minsize $win 600 400
+ raise $win
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW {
+ ::configDialogs::toolbar::CANCEL
+ }
+ tkwait window $win
+ }
+
+ ## Validator procedure for search EntryBoxes
+ # Search for the given string in the given ListBox and
+ #+ adjust EntryBox background color acording to search result
+ # @parm Char where -
+ # "O" (O as Omega not 0 as zero) == Options ListBox (avaliable items)
+ # "C" == ListBox containing current onfiguration
+ # @parm String what - String to search for
+ # @return Bool - Always true
+ proc search {where what} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+ variable options_ListBox ;# ID of ListBox containing avaliable icons
+ variable current_search_entry ;# ID of search EntryBox for $current_ListBox
+ variable options_search_entry ;# ID of search EntryBox for $options_ListBox
+ variable current_search_clear ;# ID of search EntryBox clear button for $current_ListBox
+ variable options_search_clear ;# ID of search EntryBox clear button for $options_ListBox
+
+ if {$where == {C}} {
+ set listbox $current_ListBox
+ set entry $current_search_entry
+ set clearbut $current_search_clear
+ } {
+ set listbox $options_ListBox
+ set entry $options_search_entry
+ set clearbut $options_search_clear
+ }
+
+ # Empty string
+ if {$what == {}} {
+ $entry configure -style TEntry
+ $clearbut configure -state disabled
+ return 1
+ } {
+ $clearbut configure -state normal
+ }
+
+ # Search for the given string
+ set what [string tolower $what]
+ foreach item [$listbox items] {
+ if {
+ [string first $what \
+ [string tolower \
+ [$listbox itemcget $item -text] \
+ ] \
+ ] != -1
+ } {
+ $listbox selection clear
+ $listbox selection set $item
+ $listbox see $item
+ $entry configure -style StringFound.TEntry
+ return 1
+ }
+ }
+
+ # String not found
+ $entry configure -style StringNotFound.TEntry
+ return 1
+ }
+
+ ## Fill ListBoxes acoring to the given toolbar definition
+ # Note: function depends on toplevel variable 'ICONBAR_ICONS'
+ # @parm List definition - Definition of current toolbar (eg. {new open | exit})
+ # @return void
+ proc fillListBox {definition} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+ variable options_ListBox ;# ID of ListBox containing avaliable icons
+
+ # Fill in left ListBox
+ $options_ListBox insert end sep -text [mc " -- SEPARATOR --"]
+ for {set i 0} {$i < [llength ${::ICONBAR_ICONS}]} {incr i} {
+ # Determinate item name
+ set item [lindex ${::ICONBAR_ICONS} $i]
+ incr i
+ # Skip invalid items
+ if {[lsearch $definition $item] != -1} {continue}
+ # Insert item
+ $options_ListBox insert end $item \
+ -text [lindex ${::ICONBAR_ICONS} "$i 0"] \
+ -image ::ICONS::16::[lindex ${::ICONBAR_ICONS} "$i 2"]
+ }
+
+ # Fill in right ListBox
+ foreach key $definition {
+ # Insert separator
+ if {$key == {|}} {
+ $current_ListBox insert end #auto -text [mc " -- SEPARATOR --"]
+ }
+ # Deteminate item index
+ set i [lsearch ${::ICONBAR_ICONS} $key]
+ if {$i == -1} {continue}
+ incr i
+ # Insert regular item
+ $current_ListBox insert end $key \
+ -text [lindex ${::ICONBAR_ICONS} "$i 0"] \
+ -image ::ICONS::16::[lindex ${::ICONBAR_ICONS} "$i 2"]
+ }
+ }
+
+ ## Enable/Disable arrow buttons acording to selection in ListBoxes
+ # @return void
+ proc reevaluateArrows {} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+ variable options_ListBox ;# ID of ListBox containing avaliable icons
+ variable left_button ;# ID of button "Left"
+ variable right_button ;# ID of button "Right"
+
+ # Button "Left"
+ if {[$current_ListBox selection get] == {}} {
+ $left_button configure -state disabled
+ } {
+ $left_button configure -state normal
+ }
+
+ # Button "Right"
+ if {[$options_ListBox selection get] == {}} {
+ $right_button configure -state disabled
+ } {
+ $right_button configure -state normal
+ }
+
+ # Evaluate buttons "Up/Down"
+ reevaluateUpDown
+
+ }
+
+ ## Enable/Disable Up/Down arrow acording to selection in the right ListBox
+ # @return void
+ proc reevaluateUpDown {} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+ variable down_button ;# ID of button "Down"
+ variable up_button ;# ID of button "Up"
+
+ # Determinate ID of selected item
+ set sel [$current_ListBox selection get]
+
+ # Valid selection
+ if {$sel != {}} {
+ # Button "Up"
+ set curIndex [$current_ListBox index $sel]
+ if {$curIndex == 0} {
+ $up_button configure -state disabled
+ } {
+ $up_button configure -state normal
+ }
+
+ # Button "Down"
+ set numberOfItems [llength [$current_ListBox items]]
+ if {$curIndex == ($numberOfItems - 1)} {
+ $down_button configure -state disabled
+ } {
+ $down_button configure -state normal
+ }
+ # Empty selection
+ } {
+ $up_button configure -state disabled
+ $down_button configure -state disabled
+ }
+ }
+
+ ## Command for button "Up"
+ # Move selected item in the right listbox up
+ # @return void
+ proc up {} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+
+ # Deteminate ID of selected item
+ set sel [$current_ListBox selection get]
+ # Determinate target index
+ set trgIdx [$current_ListBox index $sel]
+ incr trgIdx -1
+ # Move item
+ $current_ListBox move $sel $trgIdx
+ $current_ListBox see $sel
+
+ # Enable/Disabled buttons "Up/Down"
+ reevaluateUpDown
+ # Adjust status changed
+ settings_changed
+ }
+
+ ## Command for button "Down"
+ # Move selected item in the right listbox down
+ # @return void
+ proc down {} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+
+ # Deteminate ID of selected item
+ set sel [$current_ListBox selection get]
+ # Determinate target index
+ set trgIdx [$current_ListBox index $sel]
+ incr trgIdx
+ # Move item
+ $current_ListBox move $sel $trgIdx
+ $current_ListBox see $sel
+
+ # Enable/Disabled buttons "Up/Down"
+ reevaluateUpDown
+ # Adjust status changed
+ settings_changed
+ }
+
+ ## Command for button "Left"
+ # Move selected item from the right ListBox to the left one
+ # @return void
+ proc left {} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+ variable options_ListBox ;# ID of ListBox containing avaliable icons
+
+ # Local variables
+ set sel [$current_ListBox selection get] ;# ID of the selected item
+ set idx [$current_ListBox index $sel] ;# Index of the selected item
+
+ # Remove selected item
+ $current_ListBox delete $sel
+
+ # Regular item (no separator)
+ if {![regexp {^\d+$} $sel]} {
+ # Find index of the item (in avaliable icons)
+ set i [lsearch ${::ICONBAR_ICONS} $sel]
+ if {$i == -1} {return}
+ incr i
+
+ # Insert removed item into left ListBox
+ $options_ListBox insert 1 $sel \
+ -text [lindex ${::ICONBAR_ICONS} "$i 0"] \
+ -image ::ICONS::16::[lindex ${::ICONBAR_ICONS} "$i 2"]
+ }
+
+ # Restore selection
+ if {[llength [$current_ListBox items]] == $idx} {
+ if {$idx} {
+ incr idx -1
+ }
+ }
+ set idx [$current_ListBox item $idx]
+ $current_ListBox selection set $idx
+ $current_ListBox see $idx
+ $options_ListBox see $sel
+
+ # Enable/Disable arrow buttons
+ reevaluateArrows
+ # Adjust status changed
+ settings_changed
+ }
+
+ ## Command for button "Right"
+ # Move selected item from the left ListBox to the right one
+ # @return void
+ proc right {} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+ variable options_ListBox ;# ID of ListBox containing avaliable icons
+
+ # Determinate target index
+ set sel [$current_ListBox selection get]
+ if {$sel == {}} {
+ set trgIdx {end}
+ } {
+ set trgIdx [$current_ListBox index $sel]
+ }
+ # Determinate source index and source item ID
+ set sel [$options_ListBox selection get]
+ set idx [$options_ListBox index $sel]
+
+ # Separator
+ if {$sel == {sep}} {
+ $current_ListBox insert $trgIdx #auto -text [mc " -- SEPARATOR --"]
+ # Regular item
+ } {
+ set i [lsearch ${::ICONBAR_ICONS} $sel]
+ if {$i == -1} {return}
+ incr i
+ $current_ListBox insert $trgIdx $sel \
+ -text [lindex ${::ICONBAR_ICONS} "$i 0"] \
+ -image ::ICONS::16::[lindex ${::ICONBAR_ICONS} "$i 2"]
+
+ $options_ListBox delete $sel
+ }
+
+ # Restore selection
+ if {[llength [$options_ListBox items]] == $idx} {
+ if {$idx} {
+ incr idx -1
+ }
+ }
+ set idx [$options_ListBox item $idx]
+ $options_ListBox selection set $idx
+ $options_ListBox see $idx
+ $current_ListBox see [$current_ListBox item $trgIdx]
+
+ # Enable/Disable arrow buttons
+ reevaluateArrows
+ # Adjust status changed
+ settings_changed
+ }
+
+ ## Change content of configuration variables
+ # @return void
+ proc use_settings {} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+
+ set ::ICONBAR_CURRENT { }
+ append ::ICONBAR_CURRENT [$current_ListBox items]
+ append ::ICONBAR_CURRENT { }
+ regsub -all {\s\d+\s} ${::ICONBAR_CURRENT} { | } ::ICONBAR_CURRENT
+ regsub -all {\s\d+\s} ${::ICONBAR_CURRENT} { | } ::ICONBAR_CURRENT
+ set ::ICONBAR_CURRENT [string trim ${::ICONBAR_CURRENT}]
+ }
+
+ ## Save configuration to config file
+ # @return void
+ proc save_config {} {
+ ::settings setValue "Main toolbar" ${::ICONBAR_CURRENT}
+
+ # Commit
+ ::settings saveConfig
+ }
+
+ ## Load configuratin from config file
+ # @return void
+ proc load_config {} {
+ set ::ICONBAR_CURRENT [::settings getValue "Main toolbar" ${::ICONBAR_DEFAULT}]
+ }
+
+ ## Set status changed to True
+ # @return true
+ proc settings_changed {} {
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable changed ;# Bool: Settings changed
+ variable apply_button ;# ID of button "Apply"
+
+ if {$changed} {return}
+
+ set changed 1
+ set anything_modified 1
+ $apply_button configure -state normal
+ }
+
+ ## Take back changes and destroy dialog window
+ # @return void
+ proc CANCEL {} {
+ variable win ;# ID of dialog toplevel window
+ variable anything_modified ;# Bool: Settings changed (stay set to 1 even after APPLY)
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Restore previous configuration
+ if {$anything_modified} {
+ load_config
+ iconbar_redraw
+ set anything_modified 0
+ ::X::disaena_menu_toolbar_for_current_project
+ }
+
+ # Get rid of dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Apply changes and destroy dialog window
+ # @return void
+ proc OK {} {
+ variable win ;# ID of dialog toplevel window
+ variable changed ;# Bool: Settings changed
+ variable dialog_opened ;# Bool: True if this dialog is already opened
+
+ # Apply new settings
+ if {$changed} {
+ use_settings ;# Adjust NS variables
+ iconbar_redraw ;# Adjust GUI
+ save_config ;# Save new config
+ # Restore previous state of menu items (enabled / disabled)
+ ::X::disaena_menu_toolbar_for_current_project
+ }
+
+ # Get rid of dialog window
+ set dialog_opened 0
+ grab release $win
+ destroy $win
+ }
+
+ ## Apply changes in GUI
+ # @return Bool - result
+ proc APPLY {} {
+ variable apply_button ;# ID of button "Apply"
+ variable changed ;# Bool: Settings changed
+
+ # Reset status changed
+ set changed 0
+ $apply_button configure -state disabled
+
+ # Adjust NS variables
+ use_settings
+ iconbar_redraw
+ # Restore previous state of menu items (enabled / disabled)
+ ::X::disaena_menu_toolbar_for_current_project
+
+ # done ...
+ return 1
+ }
+
+ ## Restrore defaults
+ # @return void
+ proc DEFAULTS {} {
+ variable current_ListBox ;# ID of ListBox containing current toolbar setup
+ variable options_ListBox ;# ID of ListBox containing avaliable icons
+ variable win ;# ID of dialog toplevel window
+
+ # Ask user
+ if {[tk_messageBox \
+ -parent $win -type yesno \
+ -icon question -title [mc "Restore defaults"] \
+ -message [mc "Are you sure that you want restore default settings ?"]
+ ] != {yes}} {
+ return
+ }
+
+ # Clear ListBoxes
+ $current_ListBox delete [$current_ListBox items]
+ $options_ListBox delete [$options_ListBox items]
+ # Refill ListBoxes
+ fillListBox ${::ICONBAR_DEFAULT}
+ # Adjust status changed
+ settings_changed
+ }
+}
diff --git a/lib/custom_command.tcl b/lib/custom_command.tcl
new file mode 100755
index 0000000..63a42c5
--- /dev/null
+++ b/lib/custom_command.tcl
@@ -0,0 +1,98 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Execute custom command
+# USAGE:
+# set pid [exec -- tclsh custom_command.tcl [tk appname] $custom_command_NUM($cmd_num) &]
+# --------------------------------------------------------------------------
+
+# Initialize
+package require Tk
+wm withdraw .
+wm command . "$argv0 $argv"
+wm client . [info hostname]
+
+## Perform secure send command
+ # Secure means that it will not crash or something like that in case of any errors.
+ # But instead it will popup an error message to the user (Tk dialog).
+ # @parm List args - Arguments for the send command
+ # @return void
+proc secure_send args {
+ if {[catch {
+ eval "send $args"
+ } result]} {
+ puts "Unknown IO Error :: $result"
+ tk_messageBox \
+ -title "Unknown IO Error" \
+ -icon error \
+ -type ok \
+ -message "$result"
+
+ if {[ \
+ tk_messageBox \
+ -title "X server security workaround" \
+ -icon warning \
+ -type yesno \
+ -message "If the error was related to X server security, it is possible to temporarily workaround it by running this command: \"/bin/sh << 'for i in `xhost`; do xhost -\$i; done'\"\n\nDo you want to do it ?"
+ ] == {yes}} then {
+ catch {
+ exec -- /bin/sh << {xhost -; for i in `xhost`; do xhost -$i; done}
+ }
+ } else {
+ exit 1
+ }
+
+ if {[catch {
+ eval "send $args"
+ }]} {
+ tk_messageBox \
+ -title "Workaround failed" \
+ -icon error \
+ -type ok \
+ -message "Sorry this doesn't work ...\nIt's a strange bug somewhere in your operating system"
+ exit 1
+ }
+
+ return 1
+
+ } else {
+ return 1
+ }
+}
+
+# Load command from standard input
+set cmd {}
+while {![eof stdin]} {
+ append cmd [gets stdin] "\n"
+}
+
+# Execute loaded command
+if {[catch {exec /bin/sh << $cmd} result]} {
+ secure_send [lindex $argv 0] ::X::custom_cmd_error [lindex $argv 1] "{" [regsub -all {[\{\}]} $result {\\&}] "}"
+} else {
+ secure_send [lindex $argv 0] ::X::custom_cmd_finish [lindex $argv 1] "{" [regsub -all {[\{\}]} $result {\\&}] "}"
+}
+
+exit 0
diff --git a/lib/dialogs/errorhandler.tcl b/lib/dialogs/errorhandler.tcl
new file mode 100755
index 0000000..ac1b553
--- /dev/null
+++ b/lib/dialogs/errorhandler.tcl
@@ -0,0 +1,172 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Background error handler
+# --------------------------------------------------------------------------
+
+namespace eval ErrorHandler {
+ variable num_of_opended 0 ;# Int: Number of currently opened dialogs
+ variable count 0 ;# Int: Counter of ivokations
+ variable enabled 1 ;# Bool: Dialog window enabled
+
+ ## Open dialog window
+ # @parm String message - Error message
+ # @return void
+ proc open_dialog {message} {
+ variable count ;# Int: Counter of ivokations
+ variable enabled ;# Bool: Dialog window enabled
+ variable num_of_opended ;# Int: Number of currently opened dialogs
+
+ if {$num_of_opended > 2} {
+ puts stderr "ERROR MESSAGE SUPPRESED (too many error dialogs opened at the time)"
+ return
+ }
+ incr num_of_opended
+
+ # Send error message to standard error output
+ puts stderr [string repeat # 64]
+ puts stderr "# PROGRAM ERROR #"
+ puts stderr [string repeat # 64]
+ puts stderr $::errorInfo
+ puts stderr [string repeat # 64]
+
+ # Save log file
+ if {![catch {set log_file [open [file join ${::X::defaultDirectory} mcu8051ide_errors.log] a]}]} {
+ puts $log_file [string repeat # 64]
+ puts $log_file "Program version:\t${::VERSION}"
+ puts $log_file "Tcl version:\t\t${::tcl_version}"
+ puts $log_file "Tk version:\t\t${::tk_version}"
+ puts $log_file [string repeat - 64]
+ puts $log_file $::errorInfo
+ close $log_file
+ }
+
+ # Create dialog window
+ if {!$enabled} {return}
+ incr count
+ set win [toplevel .error_dialog$count -bg {#EE0000} -class {Error message} -bg {#EEEEEE}]
+
+ # Create window frames
+ set main_frame [frame $win.main_frame]
+ set top_frame [frame $main_frame.top_frame -bg {#EE0000}]
+ set middle_frame [frame $main_frame.middle_frame]
+ set bottom_frame [frame $main_frame.bottom_frame]
+
+ # Create window header
+ pack [label $top_frame.header_lbl \
+ -text [mc "PROGRAM ERROR "] \
+ -bg {#EE0000} -fg {#FFFFFF} \
+ -font [font create \
+ -family helvetica \
+ -size -24 \
+ -weight bold \
+ ] \
+ ] -side left -fill x -expand 1
+
+ # Create error message text and scrollbar
+ pack [text $middle_frame.text \
+ -bg {white} -bd 0 \
+ -yscrollcommand "$middle_frame.scrollbar set" \
+ -width 0 -height 0 -relief flat -wrap word \
+ ] -side left -fill both -expand 1 -padx 5 -pady 5
+ bind $middle_frame.text <Button-1> {focus %W}
+ pack [ttk::scrollbar $middle_frame.scrollbar \
+ -orient vertical \
+ -command "$middle_frame.text yview" \
+ ] -fill y -side right
+
+ # Create text tags
+ $middle_frame.text tag configure tag_bold \
+ -font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -weight bold \
+ -size -14 \
+ ]
+ $middle_frame.text tag configure tag_big_bold \
+ -font [font create \
+ -family {helvetica} \
+ -weight bold \
+ -size -17 \
+ ]
+
+ # Write error message
+ $middle_frame.text insert end [mc "Error log saved in: %s\n" "${::X::defaultDirectory}/mcu8051ide_errors.log"]
+ $middle_frame.text insert end [mc "Please send this file to %s or report this bug at http://mcu8051ide.sf.net/forum\n\n\n" <martin.osmera@gmail.com>]
+ $middle_frame.text tag add tag_big_bold 1.0 3.0
+ $middle_frame.text insert end [mc "ERROR DETAILS:\n--------------\n"]
+ $middle_frame.text tag add tag_bold 5.0 7.0
+ $middle_frame.text insert end $::errorInfo
+ $middle_frame.text configure -state disabled
+
+ # Create button frame
+ pack [ttk::button $bottom_frame.skip \
+ -text [mc "Skip errors"] \
+ -compound left \
+ -command "
+ set ::ErrorHandler::enabled 0
+ ::ErrorHandler::close_dialog $count
+ " \
+ ] -side left
+ pack [ttk::button $bottom_frame.ok \
+ -text [mc "Close"] \
+ -style GreenBg.TButton \
+ -command "::ErrorHandler::close_dialog $count" \
+ ] -side right
+ focus -force $bottom_frame.ok
+
+ # Pack window frames
+ pack $top_frame -fill x -anchor n
+ pack $middle_frame -fill both -expand 1
+ pack $bottom_frame -fill x
+ pack $main_frame -fill both -expand 1 -padx 5 -pady 5
+
+ # Configure dialog window
+ set x [expr {[winfo screenwidth $win] / 2 - 225}]
+ set y [expr {[winfo screenheight $win] / 2 - 125}]
+ wm iconphoto $win ::ICONS::16::bug
+ wm title $win [mc "PROGRAM ERROR - MCU 8051 IDE"]
+ wm minsize $win 450 250
+ wm geometry $win =550x250+$x+$y
+ wm protocol $win WM_DELETE_WINDOW "::ErrorHandler::close_dialog $count"
+ update
+ raise $win
+ catch {grab $win}
+ }
+
+ ## Close dialog window
+ # @parm Int number - Dialog unique number
+ # @return void
+ proc close_dialog {number} {
+ variable num_of_opended ;# Int: Number of currently opened dialogs
+
+ incr num_of_opended -1
+ destroy .error_dialog$number
+ }
+}
+
+# Register error handler
+proc bgerror {message} {
+ ::ErrorHandler::open_dialog $message
+}
diff --git a/lib/dialogs/fsd.tcl b/lib/dialogs/fsd.tcl
new file mode 100755
index 0000000..959eae4
--- /dev/null
+++ b/lib/dialogs/fsd.tcl
@@ -0,0 +1,2775 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# This class provides file selection dialog
+# Usage:
+# KIFSD::FSD <fsd_object> ;# Create dialog object
+# <fsd_object> setokcmd {set filename [<fsd_object> get]} ;# Set command for Ok button
+# <fsd_object> activate <some_command> ;# Show up the dialog
+#
+# Constructor options:
+# -title String = {} ;# Dialog title
+# -initialfile String = {} ;# Initial file
+# -directory String = {~} ;# Initiali directory
+# -multiple Bool = 0 ;# Allow selection of multiple files (get will return list instead of string)
+# -filetypes List = {{All} {*}} ;# { {{Some string} {GLOB} ... }
+# -defaultmask Int = 0 ;# Number of detault mask (see -filetypes) (1st is zero)
+# -modal Bool = 1 ;# Create as modal window
+# -doubleclick Bool = 0 ;# Use double click to open folder instead of single click
+# -autoclose Bool = 1 ;# Close dialog after pressure of Ok button
+# -master Widget = . ;# Master window (wm transient $master)
+# -fileson Bool = 1 ;# 1 == Select file(s); 0 == Select directory/ies
+#
+# Other public methods:
+# set_bookmark_change_command Command ;# Set command to invoke when bookmarks changes
+# deactivate ;# Deactivate the dialog
+# close_dialog ;# Close dialog window but keep object alive
+# get_config_array -> List ;# Get dialog configuration array for proc. load_config_array
+# load_config_array List ;# Load dialog configuration array
+# get_window_name -> Widget ;# Get path to dialog window
+# --------------------------------------------------------------------------
+
+itcl::class KIFSD::FSD {
+
+ common bookmark_change_command {} ;# Command to invoke on bokmark change
+ # Font for quick navigation panel
+ common quick_nav_panel_font [font create \
+ -family {helvetica} \
+ -size -12 \
+ -weight bold \
+ ]
+ # Font for files listbox in mode (Short view)
+ common listbox_font_short [font create \
+ -family {helvetica} \
+ -size -14 \
+ -weight normal \
+ ]
+ # Font for files listbox in mode (Detailed view) and directories listbox
+ common listbox_font_detailed [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight normal \
+ ]
+ # Font for listbox header
+ common listbox_header_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ ]
+
+ ## Values given by constructor arguments
+ private variable option_title {Select file} ;# Dialog title
+ private variable option_filetypes {{All} {*}} ;# File types
+ if {!$::MICROSOFT_WINDOWS} {
+ variable option_directory ${::env(HOME)} ;# Initial directory
+ } {
+ variable option_directory ${::env(USERPROFILE)} ;# Initial directory
+ }
+ private variable option_master {.} ;# Window master
+ private variable option_fileson {1} ;# 1 == Files on (select file); 0 == Files off (select directory)
+ private variable option_doubleclick {0} ;# Use doble click instead of single clicks
+ private variable option_modal {1} ;# Open dialog windown as modal window
+ private variable option_initialfile {} ;# Initial file
+ private variable option_multiple {0} ;# Allow mulstiple selection
+ private variable option_defaultmask {0} ;# Index of default mask in $option_filetypes
+ private variable option_autoclose {1} ;# 1 == Close dialog after press of Ok button
+
+ private variable bookmark_edit_listbox {} ;# Widget: ListBox in bookmarks editor
+ private variable bookmark_menu {} ;# Widget: Bookmarks menu
+ private variable config_menu {} ;# Widget: Configuration menu
+ private variable listbox_font {} ;# Font: Current font for files listbox
+ private variable current_directory {} ;# String: Current directory
+ private variable back_history {} ;# List: Backward history
+ private variable forward_history {} ;# List: Forward hitory
+ private variable ok_command {} ;# String: Ok command
+ private variable current_mask {*} ;# GLOB: Current fileter mask
+ private variable item_menu_request 0 ;# Bool: Item popup menu request
+ private variable current_item {} ;# String: ID of currenly selected item
+ private variable current_item_index 0 ;# Int: Index of currently selected item
+ private variable cur_listbox {} ;# String currently selected listbox {dir} or {file}
+
+ private variable dialog_loaded 0 ;# Bool: Dialog is completely loaded
+ private variable win ;# Widget: Dialog window
+ private variable ok_button ;# Widget: Button "Ok"
+ private variable location_cb ;# Widget: Location ComboBox
+ private variable filter_cb ;# Widget: Filter ComboBox
+ private variable dir_combobox ;# Widget: Directory ComboBox
+ private variable toolbar ;# Widget: Frame containing toolbar
+ private variable quick_access_bar ;# Widget: Quick access bar ListBox
+ private variable dir_listbox_scrollbar ;# Widget: Directory ListBox scrollbar
+ private variable dir_listbox ;# Widget: Directory ListBox
+ private variable main_paned_window ;# Widget: Paned window for quick access bar and other LBs
+ private variable leftframe ;# Widget: Frame contaning quick access bar and its scrollbar
+ private variable rightframe ;# Widget: Frame containing directory & file ListBoxes
+ private variable right_top_right_frame ;# Widget: files ListBox
+ private variable right_top_left_frame ;# Widget: Frame for files ListBox
+ private variable right_top_frame ;# Widget: Frame for $right_paned_window
+ private variable right_paned_window ;# Widget: Paned window for directories ListBox and files ListBox
+ private variable file_listbox ;# Widget: Files ListBox
+ private variable file_listbox_header ;# Widget: Header for files ListBox
+ private variable file_listbox_frame ;# Widget: Frame for $file_listbox_header and $file_listbox
+ private variable file_listbox_vscrollbar ;# Widget: Vertical scollbar for files ListBox
+ private variable file_listbox_hscrollbar ;# Widget: Hotizontal scollbar for files ListBox
+ private variable right_top_right_top_frame ;# Widget: Frame for $file_listbox_frame and scrollbars
+
+
+ ## Dialog constructor
+ # For complite list of possible arguments see desctiption above
+ constructor args {
+
+ # Configure local ttk styles
+ ttk::style configure FSD_RedBg.TCombobox -fieldbackground {#FFDDDD}
+
+ ## Parse given arguments and set appropriate object variables
+ set arglen [llength $args]
+ set arg {}
+ for {set i 0} {$i < $arglen} {incr i} {
+ set arg [lindex $args $i]
+ switch -- $arg {
+ -modal {
+ incr i
+ set option_modal [lindex $args $i]
+ if {![string is boolean -strict $option_modal]} {
+ error "-fileson must have value eighter 0 or 1"
+ }
+ }
+ -doubleclick {
+ incr i
+ set option_doubleclick [lindex $args $i]
+ if {![string is boolean -strict $option_doubleclick]} {
+ error "-doubleclick must have value eighter 0 or 1"
+ }
+ }
+ -autoclose {
+ incr i
+ set option_autoclose [lindex $args $i]
+ if {![string is boolean -strict $option_autoclose]} {
+ error "-autoclose must have value eighter 0 or 1"
+ }
+ }
+ -initialfile {
+ incr i
+ set option_initialfile [lindex $args $i]
+ }
+ -multiple {
+ incr i
+ set option_multiple [lindex $args $i]
+ if {![string is boolean -strict $option_multiple]} {
+ error "-multiple must have value eighter 0 or 1"
+ }
+ }
+ -defaultmask {
+ incr i
+ set option_defaultmask [lindex $args $i]
+ if {![string is integer -strict $option_defaultmask]} {
+ error "-defaultmask must be an integer"
+ }
+ }
+ -title {
+ incr i
+ set option_title [lindex $args $i]
+ }
+ -filetypes {
+ incr i
+ set option_filetypes [lindex $args $i]
+ }
+ -directory {
+ incr i
+ set option_directory [lindex $args $i]
+ }
+ -master {
+ incr i
+ set option_master [lindex $args $i]
+ }
+ -fileson {
+ incr i
+ set option_fileson [lindex $args $i]
+ if {![string is boolean -strict $option_modal]} {
+ error "-fileson must have value eighter 0 or 1"
+ }
+ }
+ default {
+ error "Option '$arg' is not valid"
+ }
+ }
+ }
+ set args {}
+ set current_directory [file normalize $option_directory]
+
+ # Cretate dialog window
+ create_dialog
+
+ # Initalize window key shortcuts
+ create_shortcuts
+
+ # Finalize
+ set dialog_loaded 1
+ }
+
+ ## Destrurtor
+ destructor {
+ catch {
+ # Save position of right paned window sash
+ if {[winfo ismapped $right_paned_window]} {
+ set ::KIFSD::FSD::config(right_PW_size) \
+ [lindex [$right_paned_window sash coord 0] 0]
+ }
+ # Save position of main paned window sash
+ if {[winfo ismapped $main_paned_window]} {
+ set ::KIFSD::FSD::config(main_PW_size) \
+ [lindex [$main_paned_window sash coord 0] 0]
+ }
+ # Save window geometry
+ set ::KIFSD::FSD::config(win_geometry) [wm geometry $win]
+ }
+
+ # Destroy dialog window
+ grab release $win
+ destroy $win
+ }
+
+ ## Create dialog GUI elements
+ # @return void
+ private method create_dialog {} {
+ # Determinate window name (path)
+ set win_base .[string tolower [regsub -all {:} $this {}]]
+ set win $win_base
+ set i 0
+ while [winfo exists $win] {
+ set win $win_base
+ append win $i
+ incr i
+ }
+
+ # Create and configure dialog window
+ toplevel $win -bg {#EEEEEE}
+ wm iconphoto $win ::ICONS::16::fileopen
+ wm withdraw $win
+ wm title $win $option_title
+ wm minsize $win 540 260
+ wm protocol $win WM_DELETE_WINDOW "catch {itcl::delete object $this}"
+ wm transient $win $option_master
+ wm geometry $win ${::KIFSD::FSD::config(win_geometry)}
+ wm resizable $win 0 0
+ raise $win
+ update
+ if {$option_modal} {
+ catch {
+ grab $win
+ }
+ }
+
+
+ create_popup_menus ;# Create popup menus
+ set topframe [frame $win.topframe] ;# Create frame above ListBoxes
+ set toolbar [frame $topframe.toobar] ;# Create toolbar frame
+ create_tool_bar ;# Create toolbar
+
+ # Create directory ComboBox
+ set dir_combobox [ttk::combobox $topframe.dir_cb \
+ -values {} \
+ -exportselection 0 \
+ -validate all \
+ -validatecommand "::KIFSD::FSD::dir_validate $topframe.dir_cb %W %P" \
+ ]
+ bind $dir_combobox <<ComboboxSelected>> [list $this dir_cb_modify]
+ bind $dir_combobox <KP_Enter> [list $this dir_cb_modify]
+ bind $dir_combobox <Return> [list $this dir_cb_modify]
+
+ DynamicHelp::add $dir_combobox -text [mc "Current directory"]
+ pack $dir_combobox -side right -expand 1 -fill x -padx 5
+
+ # Create main paned window and some frames
+ set mainframe [frame $win.mainframe]
+ set main_paned_window [panedwindow $mainframe.main_paned_window \
+ -orient horizontal -opaqueresize 1 -sashwidth 2 \
+ -showhandle 0 -sashrelief flat \
+ ]
+ set leftframe [frame $mainframe.leftframe]
+ set rightframe [frame $mainframe.rightframe]
+
+ # Create quick access bar
+ set quick_access_bar [ListBox $leftframe.quick_access_bar \
+ -selectfill 1 -selectbackground white -bd 1 -padx 30 -width 15 \
+ -selectmode single -highlightthickness 0 -bg white -deltay 30 \
+ -selectforeground black -highlightcolor {#BBBBFF} \
+ ]
+ refresh_quick_access_bar
+ $quick_access_bar bindText <ButtonRelease-3> [list $this quick_access_bar_item_menu %X %Y ]
+ $quick_access_bar bindImage <ButtonRelease-3> [list $this quick_access_bar_item_menu %X %Y ]
+ $quick_access_bar bindText <Double-Button-1> [list $this quick_access_bar_doubleclick ]
+ $quick_access_bar bindImage <Double-Button-1> [list $this quick_access_bar_doubleclick ]
+ bind $quick_access_bar <<ListboxSelect>> [list $this quick_access_bar_select ]
+ if {[winfo exists $quick_access_bar.c]} {
+ bind $quick_access_bar.c <Button-5> {%W yview scroll +5 units; break}
+ bind $quick_access_bar.c <Button-4> {%W yview scroll -5 units; break}
+ bind $quick_access_bar.c <ButtonRelease-3> [list $this quick_access_bar_menu %X %Y ]
+ }
+ pack $quick_access_bar -fill both -expand 1
+
+ # Create right paned window
+ set right_top_frame [frame $rightframe.topframe]
+ set right_bottom_frame [frame $rightframe.bottomframe]
+ set right_paned_window [panedwindow $right_top_frame.right_paned_window \
+ -orient horizontal -opaqueresize 1 -sashwidth 2 \
+ -showhandle 0 -sashrelief flat \
+ ]
+ set right_top_left_frame [frame $win.left_frame]
+ set right_top_right_frame [frame $win.right_frame]
+
+ # Create directories ListBox
+ if {$option_fileson} {
+ set dir_listbox [ListBox $right_top_left_frame.dir_listbox \
+ -bd 1 -padx 19 -selectfill 1 -width 1 -highlightcolor {#BBBBFF} \
+ -selectmode single -highlightthickness 0 -bg white -deltay 18 \
+ -yscrollcommand "catch {$this dir_listbox_scroll}" \
+ ]
+ set dir_listbox_scrollbar [ttk::scrollbar \
+ $right_top_left_frame.scrollbar \
+ -orient vertical -command "$dir_listbox yview" \
+ ]
+ $dir_listbox bindText <Double-Button-1> [list $this dir_listbox_doubleclick ]
+ $dir_listbox bindImage <Double-Button-1> [list $this dir_listbox_doubleclick ]
+ $dir_listbox bindText <ButtonRelease-3> [list $this dir_listbox_item_menu %X %Y ]
+ $dir_listbox bindImage <ButtonRelease-3> [list $this dir_listbox_item_menu %X %Y ]
+ bind $dir_listbox <<ListboxSelect>> [list $this dir_listbox_select ]
+ if {[winfo exists $dir_listbox.c]} {
+ bind $dir_listbox.c <Button-5> {%W yview scroll +5 units; break}
+ bind $dir_listbox.c <Button-4> {%W yview scroll -5 units; break}
+ bind $dir_listbox.c <ButtonRelease-3> [list $this dir_listbox_menu %X %Y ]
+ }
+ pack $dir_listbox -side left -fill both -expand 1
+ }
+
+ # Create files ListBox
+ if {$option_multiple} {
+ set selmode {multiple}
+ } {
+ set selmode {single}
+ }
+ set right_top_right_top_frame [frame $right_top_right_frame.right_top_right_top_frame]
+ set file_listbox_frame [frame $right_top_right_top_frame.file_listbox_frame]
+ set file_listbox_header [text $file_listbox_frame.text \
+ -width 1 -height 1 -takefocus 0 -bg white \
+ -font $listbox_header_font -bd 1 -relief sunken \
+ -cursor left_ptr -wrap none \
+ ]
+ $file_listbox_header delete 1.0 end
+ if {!$::MICROSOFT_WINDOWS} {
+ $file_listbox_header insert end \
+ [mc " Name\t\t\t\t Size Rights Date "]
+ } else {
+ $file_listbox_header insert end \
+ [mc " Name\t\t\t\t Size Date "]
+ }
+ bindtags $file_listbox_header $file_listbox_header
+ $file_listbox_header configure -state disabled
+ set file_listbox [ListBox $file_listbox_frame.file_listbox -height 1 \
+ -selectfill 1 -selectbackground {#88AAFF} -bd 1 -padx 17 -width 1 \
+ -selectmode $selmode -highlightthickness 0 -bg white -deltay 18 \
+ -yscrollcommand "catch {$this file_listbox_vscroll}" -highlightcolor {#BBBBFF} \
+ -xscrollcommand "catch {$this file_listbox_hscroll}" \
+ ]
+ pack $file_listbox -fill both -expand 1
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ $file_listbox configure -multicolumn 0
+ set listbox_font $listbox_font_detailed
+ pack $file_listbox_header -before $file_listbox -fill x -expand 0
+ } {
+ $file_listbox configure -multicolumn 1
+ set listbox_font $listbox_font_short
+ }
+ set file_listbox_vscrollbar [ttk::scrollbar \
+ $right_top_right_top_frame.vscrollbar \
+ -orient vertical -command "$file_listbox yview" \
+ ]
+ set file_listbox_hscrollbar [ttk::scrollbar \
+ $right_top_right_frame.hscrollbar \
+ -orient horizontal \
+ -command "$this file_listbox_hscrollbar_cmd" \
+ ]
+ $file_listbox bindText <Double-Button-1> [list $this file_listbox_doubleclick]
+ $file_listbox bindImage <Double-Button-1> [list $this file_listbox_doubleclick]
+ $file_listbox bindText <ButtonRelease-3> [list $this file_listbox_item_menu %X %Y]
+ $file_listbox bindImage <ButtonRelease-3> [list $this file_listbox_item_menu %X %Y]
+ bind $file_listbox <<ListboxSelect>> [list $this file_listbox_select]
+ if {[winfo exists $file_listbox.c]} {
+ bind $file_listbox.c <Button-5> [list $this file_listbox_scroll +5 units]
+ bind $file_listbox.c <Button-4> [list $this file_listbox_scroll -5 units]
+ bind $file_listbox.c <ButtonRelease-3> [list $this file_listbox_menu %X %Y]
+ }
+ pack $file_listbox_frame -fill both -expand 1 -side left
+ pack $right_top_right_top_frame -fill both -expand 1 -side top
+ pack $right_top_frame -side top -fill both -expand 1
+
+ # Create Location Label+ComboBox and Filter Label+ComboBox
+ grid [label $right_bottom_frame.location_label \
+ -text [mc "Location:"] \
+ ] -sticky w -column 0 -row 0
+ grid [label $right_bottom_frame.filter_label \
+ -text [mc "Filter:"] \
+ ] -sticky w -column 0 -row 1
+
+ set location_cb [ttk::combobox $right_bottom_frame.location_cb \
+ -values {} \
+ -exportselection 0 \
+ ]
+ bind $location_cb <<ComboboxSelected>> "$file_listbox selection clear"
+ DynamicHelp::add $location_cb -text [mc "Selected file(s)"]
+ bind $location_cb <Key> "$file_listbox selection clear"
+ bind $location_cb <KP_Enter> [list $this ok]
+ bind $location_cb <Return> [list $this ok]
+
+ set tmp_option_filetypes {}
+ foreach type $option_filetypes {
+ lappend tmp_option_filetypes "[lindex $type 0] ([lindex $type 1])"
+ }
+ set filter_cb [ttk::combobox $right_bottom_frame.filter_cb \
+ -state readonly \
+ -values $tmp_option_filetypes \
+ -exportselection 0 \
+ ]
+ DynamicHelp::add $right_bottom_frame.filter_cb -text [mc "Filter"]
+ set tmp_option_filetypes {}
+ foreach type $option_filetypes {
+ lappend tmp_option_filetypes [lindex $type 1]
+ }
+ set option_filetypes $tmp_option_filetypes
+ $filter_cb current $option_defaultmask
+ set current_mask [lindex $option_filetypes $option_defaultmask]
+ bind $filter_cb <<ComboboxSelected>> [list $this filter_cb_modify]
+ grid $location_cb -sticky ew -column 1 -row 0
+ grid $filter_cb -sticky ew -column 1 -row 1
+
+ if {!$option_fileson} {
+ $filter_cb configure -state disabled
+ }
+
+ # Create buttons "Ok" and "Cancel"
+ set ok_button [ttk::button $right_bottom_frame.ok_button\
+ -text [mc "Ok"] \
+ -compound left \
+ -width 8 \
+ -image ::ICONS::16::ok \
+ -command [list $this ok] \
+ ]
+ grid $ok_button -sticky w -column 2 -row 0 -padx 7
+ grid [ttk::button $right_bottom_frame.cancel_button \
+ -text [mc "Cancel"] \
+ -compound left \
+ -width 8 \
+ -image ::ICONS::16::button_cancel \
+ -command "itcl::delete object $this" \
+ ] -sticky w -column 2 -row 1 -padx 7
+
+ grid columnconfigure $right_bottom_frame 1 -weight 1
+
+ pack $right_bottom_frame -side bottom -fill x -expand 0 -anchor w
+
+ pack $topframe -side top -fill x -padx 12 -pady 10
+ pack $mainframe -side bottom -fill both -expand 1 -padx 12
+
+ # Adjust paned windows to current configuration
+ quick_access_panel_onoff
+ separate_folders_onoff
+
+ # Finalize
+ $location_cb set $option_initialfile
+ focus -force $location_cb
+ catch {
+ $location_cb.e selection range 0 end
+ }
+ }
+
+ ## Create dialog toolbar
+ # @return void
+ private method create_tool_bar {} {
+ set si 0
+ foreach item {
+ {up "Parent folder" {1uparrow}
+ {up}}
+ {back "Back" {1leftarrow}
+ {back}}
+ {forward "Forward" {1rightarrow}
+ {forward}}
+ {reload "Reload" {reload}
+ {reload}}
+ {separator}
+ {newdir "New folder" {folder_new}
+ {newdir}}
+ {separator}
+ {short "Short view" {view_icon}
+ {short_view}}
+ {detail "Detailed view" {view_detailed}
+ {detail_view}}
+ {separator}
+ {bookmark "Bookmarks" {bookmark}
+ {bookmark_menu}}
+ {configure "Configure" {configure}
+ {config_menu}}
+ } {
+ # Create separator
+ if {$item == {separator}} {
+ pack [ttk::separator $toolbar.sep$si \
+ -orient vertical \
+ ] -side left -padx 4 -fill both -expand 1
+ incr si
+ continue
+ }
+
+ # Create button
+ if {[lindex $item 0] == {bookmark}} {
+ set buttonWidget [ttk::menubutton $toolbar.[lindex $item 0] \
+ -image ::ICONS::22::[lindex $item 2] \
+ -menu $bookmark_menu \
+ -style Flat.TMenubutton \
+ ]
+ } elseif {[lindex $item 0] == {configure}} {
+ set buttonWidget [ttk::menubutton $toolbar.[lindex $item 0] \
+ -image ::ICONS::22::[lindex $item 2] \
+ -menu $config_menu \
+ -style Flat.TMenubutton \
+ ]
+ } else {
+ set buttonWidget [ttk::button $toolbar.[lindex $item 0] \
+ -command "$this [lindex $item 3]" \
+ -style Flat.TButton \
+ -image ::ICONS::22::[lindex $item 2] \
+ ]
+ }
+ DynamicHelp::add $buttonWidget -text [mc [lindex $item 1]]
+
+ # Pack it
+ pack $buttonWidget -side left -padx 2
+ }
+
+ # Disable button for manipulating history
+ $toolbar.back configure -state disabled
+ $toolbar.forward configure -state disabled
+
+ # Pack toolbar frame
+ pack $toolbar -side left -expand 0 -fill none
+ }
+
+
+ ## Create dialog popup menus
+ # @return void
+ private method create_popup_menus {} {
+ # Create configuration menu
+ set config_menu [menu $win.config_menu -tearoff 0]
+
+ ## Create menu: Configuration -> Sorting
+ set sorting_menu [menu $win.config_menu.sorting_menu -tearoff 0]
+ # Entry: "By name"
+ $sorting_menu add radiobutton -label [mc "By name"] \
+ -variable ::KIFSD::FSD::config(sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::raoff -selectimage ::ICONS::raon \
+ -value {name} -underline 3 -command [list $this reload]
+ # Entry: "By date"
+ $sorting_menu add radiobutton -label [mc "By date"] \
+ -variable ::KIFSD::FSD::config(sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::raoff -selectimage ::ICONS::raon \
+ -value {date} -underline 3 -command [list $this reload]
+ # Entry: "By size"
+ $sorting_menu add radiobutton -label [mc "By size"] \
+ -variable ::KIFSD::FSD::config(sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::raoff -selectimage ::ICONS::raon \
+ -value {size} -underline 3 -command [list $this reload]
+ $sorting_menu add separator
+ # Entry: "Reverse"
+ $sorting_menu add checkbutton -label [mc "Reverse"] \
+ -variable ::KIFSD::FSD::config(reverse_sorting) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 0
+ # Entry: "Folders first"
+ $sorting_menu add checkbutton -label [mc "Folders first"] \
+ -variable ::KIFSD::FSD::config(folders_first) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 0
+ # Entry: "Case insensitive"
+ $sorting_menu add checkbutton -label [mc "Case insensitive"] \
+ -variable ::KIFSD::FSD::config(case_insensitive) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 0
+
+ ## Create entries for configuraion menu (accessable from toolbar)
+ # Entry: "Sorting"
+ $win.config_menu add cascade -label [mc "Sorting"] -underline 1 -menu $sorting_menu
+ $win.config_menu add separator
+ # Entry: "Short view"
+ $win.config_menu add command -label [mc "Short view"] -compound left \
+ -accelerator "F6" -command "$this short_view" -underline 0 \
+ -image ::ICONS::16::view_icon
+ # Entry: "Detailed view"
+ $win.config_menu add command -label [mc "Detailed view"] -compound left \
+ -accelerator "F7" -command "$this detail_view" -underline 0 \
+ -image ::ICONS::16::view_detailed
+ $win.config_menu add separator
+ # Entry: "Show hidden files"
+ $win.config_menu add checkbutton -label [mc "Show hidden files"] \
+ -accelerator "F8" -variable ::KIFSD::FSD::config(show_hidden_files) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this reload" -underline 5
+ # Entry: "Quick access navigation panel"
+ $win.config_menu add checkbutton -label [mc "Quick access navigation panel"] \
+ -accelerator "F9" -variable ::KIFSD::FSD::config(quick_access_panel) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this quick_access_panel_onoff" -underline 0
+ # Entry: "Separate folders"
+ $win.config_menu add checkbutton -label [mc "Separate folders"] \
+ -accelerator "F12" -variable ::KIFSD::FSD::config(separate_folders) \
+ -indicatoron 0 -compound left -image ::ICONS::choff -selectimage ::ICONS::chon \
+ -command "$this separate_folders_onoff" -underline 9
+ if {!$option_fileson} {
+ $win.config_menu entryconfigure [mc "Separate folders"] -state disabled
+ $sorting_menu entryconfigure [mc "Folders first"] -state disabled
+ $sorting_menu entryconfigure [mc "By size"] -state disabled
+ }
+
+ ## Create bookmarks menu (accessable from toolbar)
+ set bookmark_menu [menu $win.bookmark_menu -tearoff 0]
+ # Entry: "Add bookmark"
+ $bookmark_menu add command -label [mc "Add bookmark"] \
+ -command "$this add_bookmark" \
+ -underline 0 -image ::ICONS::16::bookmark_add -compound left
+ # Entry: "Edit bookmarks"
+ $bookmark_menu add command -label [mc "Edit bookmarks"] -compound left \
+ -command "$this edit_bookmarks" -underline 0 -image ::ICONS::16::bookmark
+ $bookmark_menu add separator
+ refresh_bookmarks
+
+ ## Create ListBox item menu
+ menu $win.listbox_menu -tearoff 0
+ # Entry: "Up"
+ $win.listbox_menu add command -label [mc "Up"] -compound left \
+ -underline 0 -command [list $this up] \
+ -image ::ICONS::16::up
+ # Entry: "Back"
+ $win.listbox_menu add command -label [mc "Back"] -compound left \
+ -underline 0 -command [list $this back] \
+ -image ::ICONS::16::left -state disabled
+ # Entry: "Forward"
+ $win.listbox_menu add command -label [mc "Forward"] -compound left \
+ -underline 0 -command [list $this forward] \
+ -image ::ICONS::16::right -state disabled
+ $win.listbox_menu add separator
+ # Entry: "Rename"
+ $win.listbox_menu add command -label [mc "Rename"] \
+ -underline 0 -command [list $this rename_item_command] \
+ -compound left -image ::ICONS::16::edit
+ # Entry: "Delete"
+ $win.listbox_menu add command -label [mc "Delete"] \
+ -underline 0 -command [list $this delete_item_command] \
+ -compound left -image ::ICONS::16::editdelete
+ # Entry: "New folder"
+ $win.listbox_menu add command -label [mc "New folder"] \
+ -accelerator "F10" \
+ -underline 0 -command [list $this newdir] \
+ -compound left -image ::ICONS::16::folder_new
+ # Entry: "Bookmark folder"
+ $win.listbox_menu add command -label [mc "Bookmark folder"] \
+ -underline 0 -command [list $this item_bookmark_add] \
+ -compound left -image ::ICONS::16::bookmark_add
+ $win.listbox_menu add separator
+ # Entry: "Properties"
+ $win.listbox_menu add command -label [mc "Properties"] \
+ -underline 0 -command [list $this properties_item_command]
+
+ ## Create quick access bar popup menu
+ menu $win.quick_access_panel_menu -tearoff 0
+ # Entry: "Add entry"
+ $win.quick_access_panel_menu add command -label [mc "Add entry"] \
+ -underline 0 -image ::ICONS::16::filenew -compound left \
+ -command "$this quick_access_panel_add_entry"
+ $win.quick_access_panel_menu add separator
+ # Entry: "Hide panel"
+ $win.quick_access_panel_menu add command -label [mc "Hide panel"] \
+ -underline 0 -image ::ICONS::16::2leftarrow -compound left \
+ -accelerator "F9" -command "
+ set ::KIFSD::FSD::config(quick_access_panel) \
+ \[expr {!\${::KIFSD::FSD::config(quick_access_panel)}}\]
+ $this quick_access_panel_onoff"
+
+ ## Create quick access bar ITEM popup menu
+ menu $win.quick_access_panel_item_menu -tearoff 0
+ # Entry: "Move up"
+ $win.quick_access_panel_item_menu add command -label [mc "Move up"] \
+ -underline 0 -image ::ICONS::16::1uparrow -compound left \
+ -command "$this quick_access_panel_up"
+ # Entry: "Move down"
+ $win.quick_access_panel_item_menu add command -label [mc "Move down"] \
+ -underline 0 -image ::ICONS::16::1downarrow -compound left \
+ -command "$this quick_access_panel_down"
+ $win.quick_access_panel_item_menu add separator
+ # Entry: "Edit entry"
+ $win.quick_access_panel_item_menu add command -label [mc "Edit entry"] \
+ -underline 0 -image ::ICONS::16::edit -compound left \
+ -command "$this quick_access_panel_edit_entry"
+ $win.quick_access_panel_item_menu add separator
+ # Entry: "Add entry"
+ $win.quick_access_panel_item_menu add command -label [mc "Add entry"] \
+ -underline 0 -image ::ICONS::16::filenew -compound left \
+ -command "$this quick_access_panel_add_entry"
+ # Entry: "Remove entry"
+ $win.quick_access_panel_item_menu add command -label [mc "Remove entry"]\
+ -underline 0 -image ::ICONS::16::editdelete -compound left \
+ -command "$this quick_access_panel_remove_entry"
+ $win.quick_access_panel_item_menu add separator
+ # Entry: "Hide panel"
+ $win.quick_access_panel_item_menu add command -label [mc "Hide panel"] \
+ -underline 0 -image ::ICONS::16::2leftarrow -compound left \
+ -accelerator "F9" \
+ -command "
+ set ::KIFSD::FSD::config(quick_access_panel) \
+ \[expr {!\${::KIFSD::FSD::config(quick_access_panel)}}\]
+ $this quick_access_panel_onoff"
+ }
+
+ ## Define key shortcuts for the dialog
+ # @return void
+ private method create_shortcuts {} {
+ bind $win <Key-F5> "$this reload; break"
+ bind $win <Key-F6> "$this short_view; break"
+ bind $win <Key-F7> "$this detail_view; break"
+ bind $win <Key-F8> "
+ set ::KIFSD::FSD::config(show_hidden_files) \
+ \[expr {!\${::KIFSD::FSD::config(show_hidden_files)}}\]
+ $this reload
+ break
+ "
+ bind $win <Key-F9> "
+ set ::KIFSD::FSD::config(quick_access_panel) \
+ \[expr {!\${::KIFSD::FSD::config(quick_access_panel)}}\]
+ $this quick_access_panel_onoff
+ break
+ "
+ bind $win <Key-F10> "$this newdir; break"
+ if {$option_fileson} {
+ bind $win <Key-F12> "
+ set ::KIFSD::FSD::config(separate_folders) \
+ \[expr {!\${::KIFSD::FSD::config(separate_folders)}}\]
+ $this separate_folders_onoff
+ break
+ "
+ }
+ }
+
+ ## Change current directory
+ # This function checks for directory validity
+ # @parm String dir - New directory
+ # @return void
+ public method change_directory {dir} {
+ if {$::MICROSOFT_WINDOWS} {
+ # Transform for instance "C:" to "C:/"
+ if {[regexp {^\w+:$} $dir]} {
+ append dir {/}
+ }
+ }
+
+ # Check if the specified directory is valid
+ if {![file exists $dir] || ![file isdirectory $dir]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [mc "Invalid folder"] \
+ -message [mc "The specified folder does not exist:\n%s" $dir]
+ return
+ }
+ set dir [file normalize $dir]
+
+ # Adjust history
+ if {$dir != $current_directory} {
+ lappend back_history $current_directory
+ set forward_history {}
+ $win.listbox_menu entryconfigure [mc "Forward"] -state disabled
+ $win.listbox_menu entryconfigure [mc "Back"] -state normal
+ $toolbar.forward configure -state disabled
+ $toolbar.back configure -state normal
+ }
+
+ # Option separate_folders ON
+ set current_directory $dir
+ if {${::KIFSD::FSD::config(separate_folders)} && $option_fileson} {
+ # Fill up directory ListBox with directories
+ $dir_listbox delete [$dir_listbox items]
+ foreach folder [dir_cmd $dir 1] {
+ if {$folder == {..}} {
+ set image {up}
+ } {
+ set image {fileopen}
+ }
+ $dir_listbox insert end #auto \
+ -text $folder \
+ -image ::ICONS::16::$image \
+ -font $listbox_font_short
+ }
+
+ # Fill up file ListBox with files
+ $file_listbox delete [$file_listbox items]
+ foreach file [file_cmd $dir $current_mask] {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set filename [lindex $file 1]
+ set file [lindex $file 0]
+ } {
+ set filename $file
+ }
+ $file_listbox insert end #auto \
+ -text $file \
+ -image ::ICONS::16::ascii \
+ -font $listbox_font \
+ -data [list $filename {}]
+ }
+ # Option separate_folders OFF
+ } else {
+ # Option folders_first ON or option_fileson OFF
+ $file_listbox delete [$file_listbox items]
+ if {!$option_fileson || ${::KIFSD::FSD::config(folders_first)}} {
+ # Fill up files ListBox with directories
+ foreach folder [dir_cmd $dir] {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set fullname [lindex $folder 1]
+ set folder [lindex $folder 0]
+ } else {
+ set fullname $folder
+ }
+
+ if {$folder == {..}} {
+ set image {up}
+ set fullname $folder
+ } else {
+ set image {fileopen}
+ }
+
+ $file_listbox insert end #auto \
+ -text $folder \
+ -image ::ICONS::16::$image \
+ -font $listbox_font \
+ -data [list {} $fullname]
+ }
+ # Option: option_fileson ON
+ if {$option_fileson} {
+ # Fill up files ListBox with files
+ foreach file [file_cmd $dir $current_mask] {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set filename [lindex $file 1]
+ set file [lindex $file 0]
+ } else {
+ set filename $file
+ }
+
+ $file_listbox insert end #auto \
+ -text $file \
+ -image ::ICONS::16::ascii \
+ -font $listbox_font \
+ -data [list $filename {}]
+ }
+ }
+ # Option NOT ( folders_first ON or option_fileson OFF )
+ } else {
+ # Fill up files ListBox with files and directories
+ foreach file [dir_file_cmd $dir $current_mask] {
+ set filename {}
+ set folder {}
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set fullname [lindex $file {0 1}]
+ set text [lindex $file {0 0}]
+ } else {
+ set fullname [lindex $file 0]
+ set text $fullname
+ }
+
+ switch -- [lindex $file 1] {
+ u {
+ set image {up}
+ set folder {..}
+ }
+ d {
+ set image {fileopen}
+ set folder $fullname
+ }
+ f {
+ set image {ascii}
+ set filename $fullname
+ }
+ }
+
+ $file_listbox insert end #auto \
+ -text $text \
+ -image ::ICONS::16::$image \
+ -font $listbox_font \
+ -data [list $filename $folder]
+ }
+ }
+ }
+
+ # Fill up location ComboBox with avaliable files or directories
+ if {$option_fileson} {
+ $location_cb configure -values [file_cmd $dir $current_mask 1]
+ } {
+ $location_cb configure -values [dir_cmd $dir 1]
+ }
+ $location_cb configure -text {}
+
+ # Fill up directory ComboBox
+ set values {}
+ set folder $dir
+ while 1 {
+ lappend values $folder
+ if {$folder == [file separator]} {break}
+ if {$::MICROSOFT_WINDOWS} {
+ if {[regexp {^\w+:[\\\/]?$} $folder]} {break}
+ }
+ set folder [file normalize [file join $folder {..}]]
+ }
+ foreach folder [dir_cmd $dir 1] {
+ if {$folder == {..}} {continue}
+ lappend values [file join $dir $folder]
+ }
+ if {$::MICROSOFT_WINDOWS} { ;# Include drive letters on Microsoft Windows
+ foreach drive_letter {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
+ if {[file exists "${drive_letter}:/"]} {
+ lappend values "${drive_letter}:/"
+ }
+ }
+ }
+
+ $dir_combobox configure -values $values
+ $dir_combobox current 0
+ $dir_combobox icursor end
+
+ # Enable / Disable button "Up (Parent folder)"
+ if {$dir == [file separator]} {
+ $toolbar.up configure -state disabled
+ $win.listbox_menu entryconfigure [mc "Up"] -state disabled
+ } {
+ $toolbar.up configure -state normal
+ $win.listbox_menu entryconfigure [mc "Up"] -state normal
+ }
+ }
+
+ ## This function shoul be called after Filter ComboBox change
+ # @return void
+ public method filter_cb_modify {} {
+ set current_mask [lindex $option_filetypes [$filter_cb current]]
+ reload
+ }
+
+ ## Show / Hide quick access bar acording to configuration variable quick_access_panel
+ # @return void
+ public method quick_access_panel_onoff {} {
+ # Show the panel
+ if {${::KIFSD::FSD::config(quick_access_panel)}} {
+ pack $main_paned_window -fill both -expand 1
+ $main_paned_window add $leftframe
+ $main_paned_window add $rightframe
+ $main_paned_window paneconfigure $leftframe -minsize 100
+ $main_paned_window paneconfigure $rightframe -minsize 300
+ if {$dialog_loaded} {update}
+ $main_paned_window sash place 0 ${::KIFSD::FSD::config(main_PW_size)} 0
+ if {$dialog_loaded} {update}
+ # Hide the panel
+ } {
+ if {[winfo ismapped $main_paned_window]} {
+ set ::KIFSD::FSD::config(main_PW_size) \
+ [lindex [$main_paned_window sash coord 0] {0 0}]
+ $main_paned_window forget $leftframe
+ $main_paned_window forget $rightframe
+ pack forget $main_paned_window
+ }
+ pack $rightframe -fill both -expand 1 -padx 5
+ }
+ }
+
+ ## Show / Hide folders ListBox acording to configuration variable separate_folders
+ # This function will show folders ListBox only if option_fileson == 1
+ # @return void
+ public method separate_folders_onoff {} {
+ # Show folders ListBox
+ if {${::KIFSD::FSD::config(separate_folders)} && $option_fileson} {
+ pack $right_paned_window -fill both -expand 1
+ $right_paned_window add $right_top_left_frame
+ $right_paned_window add $right_top_right_frame
+ $right_paned_window paneconfigure $right_top_left_frame -minsize 150
+ $right_paned_window paneconfigure $right_top_right_frame -minsize 200
+ if {$dialog_loaded} {update}
+ $right_paned_window sash place 0 ${::KIFSD::FSD::config(right_PW_size)} 0
+ if {$dialog_loaded} {update}
+
+ # Hide folders ListBox
+ } {
+ if {[winfo ismapped $right_paned_window]} {
+ set ::KIFSD::FSD::config(right_PW_size) \
+ [lindex [$right_paned_window sash coord 0] {0 0}]
+ $right_paned_window forget $right_top_left_frame
+ $right_paned_window forget $right_top_right_frame
+ pack forget $right_paned_window
+ }
+ pack $right_top_right_frame -expand 1 -fill both -in $right_top_frame
+ }
+
+ # Refresh files and folders ListBoxes
+ change_directory $current_directory
+ }
+
+ ## Invoke bookmark menu
+ # @return void
+ public method bookmark_menu {} {
+ set x [winfo rootx $toolbar.bookmark]
+ set y [winfo rooty $toolbar.bookmark]
+ incr y [winfo height $toolbar.bookmark]
+ tk_popup $win.bookmark_menu $x $y
+ }
+
+ ## Invoke configuration menu
+ # @return void
+ public method config_menu {} {
+ set x [winfo rootx $toolbar.configure]
+ set y [winfo rooty $toolbar.configure]
+ incr y [winfo height $toolbar.configure]
+ tk_popup $win.config_menu $x $y
+ }
+
+ ## Scroll folders ListBox and (Un)Map its scrollbar
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method dir_listbox_scroll {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $dir_listbox_scrollbar]} {
+ pack forget $dir_listbox_scrollbar
+ }
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $dir_listbox_scrollbar]} {
+ pack $dir_listbox_scrollbar -fill y -expand 1 -after $dir_listbox
+ }
+ $dir_listbox_scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Switch to mode "Short View"
+ # @return void
+ public method short_view {} {
+ if {!${::KIFSD::FSD::config(detailed_view)}} {return}
+ set ::KIFSD::FSD::config(detailed_view) 0
+ $file_listbox configure -multicolumn 1
+ set listbox_font $listbox_font_short
+ pack forget $file_listbox_header
+ reload
+ }
+
+ ## Switch to mode "Detailed View"
+ # @return void
+ public method detail_view {} {
+ if {${::KIFSD::FSD::config(detailed_view)}} {return}
+ set ::KIFSD::FSD::config(detailed_view) 1
+ $file_listbox configure -multicolumn 0
+ set listbox_font $listbox_font_detailed
+ pack $file_listbox_header -before $file_listbox -fill x -expand 0
+ reload
+ }
+
+ ## Bookmark current folder
+ # @return void
+ public method add_bookmark {} {
+ lappend ::KIFSD::FSD::config(bookmarks) $current_directory
+ $bookmark_menu add command \
+ -label $current_directory -compound left \
+ -image ::ICONS::16::fileopen \
+ -command "$this change_directory {$current_directory}"
+ uplevel #0 $bookmark_change_command
+ }
+
+ ## Invoke bookmark editor
+ # @return void
+ public method edit_bookmarks {} {
+ # Create dialog window
+ set dialog [toplevel ${win}_edit_bookmarks -class {Edit bookmarks} -bg {#EEEEEE}]
+
+ # Create top frame (ListBox containing bookmarks and its scrollbar)
+ set top_frame [frame $dialog.top_frame]
+ set bookmark_edit_listbox [ListBox $top_frame.listbox \
+ -yscrollcommand "$top_frame.scrollbar set" \
+ -bg white -selectfill 1 -selectmode single \
+ -highlightcolor {#BBBBFF} \
+ ]
+ $bookmark_edit_listbox bindText <Double-1> "$this edit_bookmarks_edit"
+ pack $bookmark_edit_listbox -side left -fill both -expand 1
+ pack [ttk::scrollbar $top_frame.scrollbar \
+ -orient vertical \
+ -command "$bookmark_edit_listbox yview" \
+ ] -fill y -expand 1
+
+ # Fill up ListBox with defined bookmarks
+ foreach item ${::KIFSD::FSD::config(bookmarks)} {
+ $bookmark_edit_listbox insert end #auto -text $item
+ }
+
+ ## Create bottom frame (buttons)
+ set bottom_frame [frame $dialog.bottom_frame]
+ # Button: "Remove"
+ pack [ttk::button $bottom_frame.remove \
+ -text "Remove" \
+ -compound left \
+ -image ::ICONS::16::editdelete \
+ -command "$this edit_bookmarks_remove" \
+ -width 8 \
+ ] -side left
+ # Button: "Edit"
+ pack [ttk::button $bottom_frame.edit \
+ -text "Edit" \
+ -compound left \
+ -image ::ICONS::16::edit \
+ -command "$this edit_bookmarks_edit" \
+ -width 8 \
+ ] -side left
+ # Button: "Up"
+ pack [ttk::button $bottom_frame.up \
+ -text "Up" \
+ -compound left \
+ -image ::ICONS::16::up \
+ -command "$this edit_bookmarks_up" \
+ -width 8 \
+ ] -side left
+ # Button: "Down"
+ pack [ttk::button $bottom_frame.down \
+ -text "Down" \
+ -compound left \
+ -image ::ICONS::16::down \
+ -command "$this edit_bookmarks_down" \
+ -width 8 \
+ ] -side left
+ # Button: "Ok"
+ pack [ttk::button $bottom_frame.ok \
+ -text "Ok" -compound left \
+ -image ::ICONS::16::ok \
+ -width 8 \
+ -command "
+ $this bookmark_edit_ok
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side right
+ # Button: "Cancel"
+ pack [ttk::button $bottom_frame.cancel \
+ -text "Cancel" \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -width 8 \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side right
+
+ # Pack dialog frames (top and bottom)
+ pack $top_frame -side top -fill both -expand 1
+ pack $bottom_frame -side top -after $top_frame -fill x -expand 0 -pady 5
+
+ # Configure dialog window
+ wm iconphoto $dialog ::ICONS::16::bookmark
+ wm title $dialog "Edit bookmarks"
+ wm minsize $dialog 550 240
+ wm geometry $dialog 550x340
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ "
+ if {[winfo ismapped $win]} {
+ wm transient $dialog $win
+ } {
+ wm transient $dialog .
+ }
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Remove current bookmark
+ # @return void
+ public method edit_bookmarks_remove {} {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ $bookmark_edit_listbox delete $item
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Edit current bookmark
+ # @return void
+ public method edit_bookmarks_edit args {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ set text [$bookmark_edit_listbox edit $item \
+ [$bookmark_edit_listbox itemcget $item -text]]
+ if {$text == {}} {return}
+ $bookmark_edit_listbox itemconfigure $item -text $text
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Move current bookmark up
+ # @return void
+ public method edit_bookmarks_up {} {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ if {
+ ![$bookmark_edit_listbox index $item]
+ ||
+ ([llength [$bookmark_edit_listbox items]] < 2)
+ } {
+ return
+ }
+ $bookmark_edit_listbox move $item [expr {[$bookmark_edit_listbox index $item] - 1}]
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Move current bookmark down
+ # @return void
+ public method edit_bookmarks_down {} {
+ set item [$bookmark_edit_listbox selection get]
+ if {$item == {}} {return}
+ if {
+ [$bookmark_edit_listbox index $item]
+ >=
+ ([llength [$quick_access_bar items]] - 1)
+ } {
+ return
+ }
+ $bookmark_edit_listbox move $item [expr {[$bookmark_edit_listbox index $item] + 1}]
+ }
+
+ ## Auxiliary procedure for bookmark editor
+ # Confirm bookmark edit dialog
+ # @return void
+ public method bookmark_edit_ok {} {
+ set ::KIFSD::FSD::config(bookmarks) {}
+ foreach item [$bookmark_edit_listbox items] {
+ lappend ::KIFSD::FSD::config(bookmarks) \
+ [$bookmark_edit_listbox itemcget $item -text]
+ }
+ refresh_bookmarks
+ uplevel #0 $bookmark_change_command
+ }
+
+ ## Reload items to bookmarks menu
+ # @return void
+ private method refresh_bookmarks {} {
+ if {[$bookmark_menu index end] > 2} {
+ $bookmark_menu delete 3 end
+ }
+ foreach dir ${::KIFSD::FSD::config(bookmarks)} {
+ $bookmark_menu add command \
+ -label $dir -compound left \
+ -image ::ICONS::16::fileopen \
+ -command "$this change_directory {$dir}"
+ }
+ }
+
+ ## Set command to execute when bookmark list changes
+ # @parm String command - Command to invoke from root namespace
+ # @return void
+ proc set_bookmark_change_command {command} {
+ set bookmark_change_command $command
+ }
+
+ ## Unmap dialog window (but keep object alive)
+ # @return void
+ public method deactivate {} {
+ wm withdraw $win
+ }
+
+ ## Activate (map) dialog window
+ # And wait until window is unmapped
+ # @return void
+ public method activate {} {
+ wm resizable $win 1 1
+ wm deiconify $win
+ update idle
+ if {[winfo ismapped $right_paned_window]} {
+ $right_paned_window sash place 0 ${::KIFSD::FSD::config(right_PW_size)} 0
+ }
+ if {[winfo ismapped $main_paned_window]} {
+ $main_paned_window sash place 0 ${::KIFSD::FSD::config(main_PW_size)} 0
+ }
+ tkwait window $win
+ }
+
+ ## Get selected item(s)
+ # @return String/List - Full path(s) to selected item(s)
+ public method get {} {
+ # Return List
+ if {$option_multiple} {
+ set result {}
+ foreach item [$file_listbox selection get] {
+ lappend result [file join $current_directory \
+ [lindex [$file_listbox itemcget $item -data] 0]]
+ }
+ if {$result == {}} {
+ lappend result [file join $current_directory [$location_cb get]]
+ }
+ return $result
+ # Return String
+ } {
+ return [file join $current_directory [$location_cb get]]
+ }
+ }
+
+ ## Destroy dialog object
+ # @return void
+ public method close_dialog {} {
+ itcl::delete object $this
+ }
+
+ ## Set command to invoke from root namespace on action "Ok"
+ # @parm String command - Command (with arguments)
+ # @return void
+ public method setokcmd {cmd} {
+ set ok_command $cmd
+ }
+
+ ## Ok action - command for button "Ok"
+ # @return void
+ public method ok {} {
+ if {$option_autoclose} {wm withdraw $win}
+ uplevel #0 $ok_command
+ if {$option_autoclose} {close_dialog}
+ }
+
+ ## Command for files ListBox horizontal scrollbar
+ # Takes any list of arguments (see code)
+ # @return void
+ public method file_listbox_hscrollbar_cmd args {
+ eval "$file_listbox_header xview $args"
+ eval "$file_listbox xview $args"
+ }
+
+ ## Scroll files ListBox vertically
+ # This function manages scrollbar visibility
+ # @parm Float frac0 - 1st fraction (see Tk manual)
+ # @parm Float frac1 - 2nd fraction (see Tk manual)
+ # @return void
+ public method file_listbox_vscroll {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $file_listbox_vscrollbar]} {
+ pack forget $file_listbox_vscrollbar
+ update
+ }
+
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $file_listbox_vscrollbar]} {
+ pack $file_listbox_vscrollbar \
+ -after $file_listbox_frame \
+ -fill y -expand 1
+ update
+ }
+ $file_listbox_vscrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Scroll files ListBox horizontaly
+ # This function manages scrollbar visibility
+ # @parm Float frac0 - 1st fraction (see Tk manual)
+ # @parm Float frac1 - 2nd fraction (see Tk manual)
+ # @return void
+ public method file_listbox_hscroll {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $file_listbox_hscrollbar]} {
+ pack forget $file_listbox_hscrollbar
+ update
+ }
+
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $file_listbox_hscrollbar]} {
+ pack $file_listbox_hscrollbar \
+ -after $right_top_right_top_frame \
+ -side bottom -fill x -expand 0
+ update
+ }
+ catch {
+ $file_listbox_hscrollbar set $frac0 $frac1
+ }
+ }
+ }
+
+ ## Event handler for quick access bar ListBox, event <<ListboxSelect>>
+ # @return void
+ public method quick_access_bar_select {} {
+ if {$option_doubleclick} {return}
+ change_directory [$quick_access_bar itemcget [$quick_access_bar selection get] -data]
+ }
+
+ ## Event handler for quick access bar ListBox, item event <Double-1>
+ # @parm String item - Item identifier
+ # @return void
+ public method quick_access_bar_doubleclick {item} {
+ if {!$option_doubleclick} {return}
+ change_directory [$quick_access_bar itemcget [$quick_access_bar selection get] -data]
+ }
+
+ ## Event handler for directories ListBox, item event <Double-1>
+ # @parm String item - Item identifier
+ # @return void
+ public method dir_listbox_doubleclick {item} {
+ if {!$option_doubleclick} {return}
+ change_directory [file join $current_directory \
+ [$dir_listbox itemcget $item -text]]
+ }
+
+ ## Event handler for directories ListBox, event <<ListboxSelect>>
+ # @return void
+ public method dir_listbox_select {} {
+ if {$option_doubleclick} {return}
+ change_directory [file join $current_directory \
+ [$dir_listbox itemcget [$dir_listbox selection get] -text]]
+ }
+
+ ## Event handler for files ListBox, item event <Double-1>
+ # @parm String item - Item identifier
+ # @return void
+ public method file_listbox_doubleclick {item} {
+ # Item directory or {} if it is file
+ set folder [lindex [$file_listbox itemcget $item -data] 1]
+
+ if {!$option_fileson} {
+ if {$folder != {}} {
+ change_directory [file join $current_directory $folder]
+ }
+ return
+ }
+
+ if {$option_doubleclick && !${::KIFSD::FSD::config(separate_folders)}} {
+ if {$folder != {}} {
+ change_directory [file join $current_directory $folder]
+ }
+ }
+
+ if {!$option_doubleclick && ($folder == {})} {
+ ok
+ }
+ }
+
+ ## Scroll files listbox
+ # Arguments are passed to yview or xview command
+ # @return void
+ public method file_listbox_scroll args {
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ set cmd {yview}
+ } {
+ set cmd {xview}
+ }
+ eval "$file_listbox.c $cmd scroll $args"
+ }
+
+ ## Event handler for files ListBox, event <<ListboxSelect>>
+ # @return void
+ public method file_listbox_select {} {
+ set selection [$file_listbox selection get]
+
+ # Change directory if item was folder
+ if {$option_fileson && !${::KIFSD::FSD::config(separate_folders)}} {
+ set folder [$file_listbox itemcget [lindex $selection end] -data]
+ set folder [lindex $folder 1]
+ if {$folder != {}} {
+ if {!$option_doubleclick} {
+ change_directory [file join $current_directory $folder]
+ }
+ return
+ }
+ }
+
+ # Change content of location ComboBox if item was file
+ if {[llength $selection] == 1} {
+ set index [lindex [$file_listbox itemcget $selection -data] [expr {$option_fileson ? 0 : 1}]]
+ if {$index != {..}} {
+ set index [lsearch -ascii [$location_cb cget -values] $index]
+ if {$index != -1} {
+ $location_cb current $index
+ }
+ }
+ } elseif {[llength $selection] > 1} {
+ set text {}
+ foreach item $selection {
+ append text "\""
+ append text [lindex [$file_listbox itemcget $item -data] [expr {$option_fileson ? 0 : 1}]]
+ append text "\" "
+ }
+ $location_cb configure -text $text
+ }
+ }
+
+ ## Reload content of quick access bar ListBox
+ # @return void
+ private method refresh_quick_access_bar {} {
+ # Remove existing items
+ $quick_access_bar delete [$quick_access_bar items]
+
+ # Create new items
+ foreach item ${::KIFSD::FSD::config(quick_access_bar_data)} {
+ # Determinate item icon
+ switch -- [lindex $item 0] {
+ 0 {set image hdd_unmount}
+ 1 {set image folder_home}
+ 2 {set image desktop}
+ 3 {set image bookmark_folder}
+ }
+ # Insert item
+ $quick_access_bar insert end #auto \
+ -font $quick_nav_panel_font \
+ -image ::ICONS::22::$image \
+ -text [lindex $item 1] \
+ -data [lindex $item 2] \
+ }
+ }
+
+ ## Invoke popup menu for ListBox of Quick access bar
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @return void
+ public method quick_access_bar_menu {x y} {
+ if {$item_menu_request} {
+ set item_menu_request 0
+ return
+ }
+ tk_popup $win.quick_access_panel_menu $x $y
+ }
+
+ ## Invoke popup menu for particular item in ListBox of Quick access bar
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm String item - Item identifier
+ # @return void
+ public method quick_access_bar_item_menu {x y item} {
+ set item_menu_request 1
+ set current_item $item
+ set current_item_index [$quick_access_bar index $item]
+ set len [llength [$quick_access_bar items]]
+
+ # Enable / Disabled entry "Move down"
+ if {$current_item_index >= ($len - 1)} {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move down"] -state disabled
+ } {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move down"] -state normal
+ }
+
+ # Enable / Disabled entry "Move up"
+ if {!$current_item_index || ($len < 2)} {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move up"] -state disabled
+ } {
+ $win.quick_access_panel_item_menu entryconfigure [mc "Move up"] -state normal
+ }
+
+ # Invoke the menu
+ tk_popup $win.quick_access_panel_item_menu $x $y
+ }
+
+ ## Move current item in quick access bar down
+ # @return void
+ public method quick_access_panel_down {} {
+ # Check if the item is not the topmost one
+ if {$current_item_index >= ([llength [$quick_access_bar items]] - 1)} {
+ return
+ }
+
+ set ::KIFSD::FSD::config(quick_access_bar_data) [lreplace \
+ ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index [expr {$current_item_index + 1}] \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ [expr {$current_item_index + 1}]] \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index]
+ ]
+ refresh_quick_access_bar
+ }
+
+ ## Move current item in quick access bar up
+ # @return void
+ public method quick_access_panel_up {} {
+ # Check if the item is not the bottommost one
+ if {!$current_item_index || ([llength [$quick_access_bar items]] < 2)} {
+ return
+ }
+
+ set ::KIFSD::FSD::config(quick_access_bar_data) [lreplace \
+ ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ [expr {$current_item_index - 1}] $current_item_index \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index] \
+ [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ [expr {$current_item_index - 1}]]
+ ]
+ refresh_quick_access_bar
+ }
+
+ ## Invoke dialog to add entry to quick access bar
+ # @return void
+ public method quick_access_panel_add_entry {} {
+ set data [qa_panel_dialog "Add entry" {3} {New entry} {~}]
+ if {![string length [lindex $data 1]]} {return}
+ if {![string length [lindex $data 2]]} {return}
+ lappend ::KIFSD::FSD::config(quick_access_bar_data) $data
+ refresh_quick_access_bar
+ }
+
+ ## Invoke dialog to edit current entry in quick access bar
+ # @return void
+ public method quick_access_panel_edit_entry {} {
+ set data [lindex ${::KIFSD::FSD::config(quick_access_bar_data)} $current_item_index]
+ set data [qa_panel_dialog "Edit entry" [lindex $data 0] [lindex $data 1] [lindex $data 2]]
+ if {![string length [lindex $data 1]]} {return}
+ if {![string length [lindex $data 2]]} {return}
+ set ::KIFSD::FSD::config(quick_access_bar_data) [lreplace \
+ ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index $current_item_index $data \
+ ]
+ refresh_quick_access_bar
+ }
+
+ ## Select icon in quick access bar edit dialog
+ # @parm Int index - Icon index [0; 4]
+ # @return void
+ public method qa_panel_dialog_icon {index} {
+ for {set i 0} {$i < 4} {incr i} {
+ ${win}_qa_panel_dialog.labelframe.button_$i configure -style Flat.TButton
+ }
+ ${win}_qa_panel_dialog.labelframe.button_$index configure -style TButton
+ set ::KIFSD::FSD::qa_panel_dialog_icon $index
+ }
+
+ ## EntryBox validator
+ # If the content was an empty string then set entry background color to red
+ # @parm Widget widget - EntryBox widget
+ # @parm String content - EntryBox content
+ # @return Bool - Always 1
+ proc not_empty_entry_validator {widget content} {
+ if {![string length $content]} {
+ $widget configure -style StringNotFound.TEntry
+ } {
+ $widget configure -style TEntry
+ }
+ return 1
+ }
+
+ ## Invoke dialog for editing entries in the quick access bar
+ # Auxiliary procedure for:
+ # * quick_access_panel_add_entry
+ # * quick_access_panel_edit_entry
+ # @parm String title - Dialog title
+ # @parm Int icon - Icon number [0;3]
+ # @parm String name - Item name
+ # @parm String url - Target URL
+ # @return List - {new_icon_number new_name new_url}
+ private method qa_panel_dialog {title icon name url} {
+ # Create dialog window
+ set dialog [toplevel "${win}_qa_panel_dialog" -class {Configuration dialog} -bg {#EEEEEE}]
+
+ # Set dialog variables
+ set ::KIFSD::FSD::qa_panel_dialog_icon $icon
+ set ::KIFSD::FSD::qa_panel_dialog_name_entry $name
+ set ::KIFSD::FSD::qa_panel_dialog_url_entry $url
+
+ ## Create main frame (Name: and URL:)
+ set mid_frame [frame $dialog.middle]
+ # Label: "Name"
+ grid [label $mid_frame.name_lbl \
+ -text "Name" \
+ ] -row 0 -column 0 -sticky w
+ # Label: "URL"
+ grid [label $mid_frame.url_lbl \
+ -text "URL" \
+ ] -row 1 -column 0 -sticky w
+ # EntryBox: "Name"
+ grid [ttk::entry $mid_frame.name_entry \
+ -width 1 \
+ -validate all \
+ -validatecommand "::KIFSD::FSD::not_empty_entry_validator %W %P" \
+ -textvariable ::KIFSD::FSD::qa_panel_dialog_name_entry \
+ ] -row 0 -column 1 -sticky we
+ # EntryBox: "URL"
+ grid [ttk::entry $mid_frame.url_entry \
+ -width 1 \
+ -validate all \
+ -textvariable ::KIFSD::FSD::qa_panel_dialog_url_entry \
+ -validatecommand "::KIFSD::FSD::dir_validate {} %W %P" \
+ ] -row 1 -column 1 -sticky we
+ grid columnconfigure $mid_frame 1 -weight 1
+ pack $mid_frame -padx 10 -pady 5 -fill x -expand 1
+
+ # Create frame for selecting icon
+ pack [ttk::labelframe $dialog.labelframe \
+ -text "Icon" \
+ ] -fill none -expand 1 -anchor w -padx 10
+ foreach icon {hdd_unmount folder_home desktop bookmark_folder} index {0 1 2 3} {
+ pack [ttk::button $dialog.labelframe.button_$index \
+ -image ::ICONS::22::$icon \
+ -command "$this qa_panel_dialog_icon $index" \
+ -width 6 \
+ -style Flat.TButton \
+ ] -side left -padx 5 -pady 5
+ }
+ $dialog.labelframe.button_${::KIFSD::FSD::qa_panel_dialog_icon} \
+ configure -style TButton
+
+ ## Create bottom frame (Buttons "Ok" and "Cancel")
+ set bot_frame [frame $dialog.bot]
+ # Button: "Ok"
+ pack [ttk::button $bot_frame.ok \
+ -text "Ok" \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "
+ if \[string length \${::KIFSD::FSD::qa_panel_dialog_name_entry}\] {
+ if \[string length \${::KIFSD::FSD::qa_panel_dialog_url_entry}\] {
+ grab release $dialog
+ destroy $dialog
+ }
+ }" \
+ ] -side left -fill none -expand 0
+ # Button: "Cancel"
+ pack [ttk::button $bot_frame.cancel \
+ -text "Cancel" \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ set ::KIFSD::FSD::qa_panel_dialog_url_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_name_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_icon {}
+ grab release $dialog
+ destroy $dialog" \
+ ] -side left -fill none -expand 0
+ pack $bot_frame -anchor e -padx 10 -pady 5
+
+ # Configure dialog window
+ wm title $dialog $title
+ wm resizable $dialog 0 0
+ wm geometry $dialog 380x160
+ wm protocol $dialog WM_DELETE_WINDOW "
+ set ::KIFSD::FSD::qa_panel_dialog_url_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_name_entry {}
+ set ::KIFSD::FSD::qa_panel_dialog_icon {}
+ grab release $dialog
+ destroy $dialog
+ "
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ focus -force $mid_frame.name_entry
+ tkwait window $dialog
+
+ # Return results
+ return [list \
+ ${::KIFSD::FSD::qa_panel_dialog_icon} \
+ ${::KIFSD::FSD::qa_panel_dialog_name_entry} \
+ ${::KIFSD::FSD::qa_panel_dialog_url_entry} \
+ ]
+ }
+
+ ## Remove entry from quick access bar (popup menu action)
+ # @return void
+ public method quick_access_panel_remove_entry {} {
+ set ::KIFSD::FSD::config(quick_access_bar_data) \
+ [lreplace ${::KIFSD::FSD::config(quick_access_bar_data)} \
+ $current_item_index $current_item_index]
+ refresh_quick_access_bar
+ }
+
+ ## Invoke popup menu for directories ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @return void
+ public method dir_listbox_menu {x y} {
+ if {$item_menu_request} {
+ set item_menu_request 0
+ return
+ }
+ foreach entry {Rename Delete Properties {Bookmark folder}} {
+ $win.listbox_menu entryconfigure [mc $entry] -state disabled
+ }
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Invoke popup menu for item in directories ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm String item - Item identifier
+ # @return void
+ public method dir_listbox_item_menu {x y item} {
+ set item_menu_request 1
+ foreach entry {Rename Delete Properties {Bookmark folder}} {
+ $win.listbox_menu entryconfigure [mc $entry] -state normal
+ }
+ set cur_listbox {dir}
+ set current_item $item
+ set current_item_index [$dir_listbox index $item]
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Invoke popup menu for files ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @return void
+ public method file_listbox_menu {x y} {
+ if {$item_menu_request} {
+ set item_menu_request 0
+ return
+ }
+ foreach entry {Rename Delete Properties} {
+ $win.listbox_menu entryconfigure [mc $entry] -state disabled
+ }
+ $win.listbox_menu entryconfigure [mc {Bookmark folder}] -state normal
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Invoke popup menu for item in files ListBox
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm String item - Item identifier
+ # @return void
+ public method file_listbox_item_menu {x y item} {
+ set item_menu_request 1
+ set current_item $item
+ set current_item_index [$dir_listbox index $item]
+ foreach entry {Rename Delete Properties {Bookmark folder}} {
+ $win.listbox_menu entryconfigure [mc $entry] -state normal
+ }
+ set cur_listbox {file}
+ set current_item $item
+ set current_item_index [$dir_listbox index $item]
+ tk_popup $win.listbox_menu $x $y
+ }
+
+ ## Remove selected file or directory
+ # @return void
+ public method delete_item_command {} {
+ # Determinate URL to delete
+ if {$cur_listbox == {dir}} {
+ set filename [$dir_listbox itemcget $current_item -text]
+ } {
+ set data [$file_listbox itemcget $current_item -data]
+ if {[lindex $data 0] == {}} {
+ set filename [lindex $data 1]
+ } {
+ set filename [lindex $data 0]
+ }
+ }
+ if {$filename == {}} {return}
+
+ # Invoke confirmation dialog
+ if {[tk_messageBox \
+ -parent $win \
+ -type yesno \
+ -icon question \
+ -title "Delete file" \
+ -message "Do you really want to delete file:\n$filename"]
+ ==
+ {yes}
+ } {
+ # Delete file/directory (+ invoke error dialog)
+ if {[catch {file delete -force -- [file join $current_directory $filename]}]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title "Permission denied" \
+ -message "Unable to remove file:\n$filename"
+ }
+ }
+ reload
+ }
+
+ ## Bookmark selected folder
+ # @return void
+ public method item_bookmark_add {} {
+ set tmp $current_directory
+ if {$cur_listbox == {dir}} {
+ set current_directory [file join $current_directory \
+ [$dir_listbox itemcget $current_item -text]]
+ }
+ add_bookmark
+ set current_directory $tmp
+ }
+
+ ## Rename selected file or directory
+ # @return void
+ public method rename_item_command {} {
+ if {$cur_listbox == {dir}} {
+ set listbox $dir_listbox
+ } {
+ set listbox $file_listbox
+ }
+
+ # Determinate old and new name
+ set original [$listbox itemcget $current_item -text]
+ set newname [$listbox edit $current_item \
+ [$listbox itemcget $current_item -text]]
+ if {$newname == {}} {
+ return
+ }
+
+ # Adjust old and new name
+ set original [file join $current_directory $original]
+ set newname [file join $current_directory $newname]
+
+ # Rename file
+ if {[catch {file rename -force $original $newname}]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title "Permission denied" \
+ -message "Unable to rename file:\n$original"
+ }
+ reload
+ }
+
+ ## Invoke item properties dialog
+ # @return void
+ public method properties_item_command {} {
+ # Determinate item name, type (File or Directory)
+ if {$cur_listbox == {dir}} {
+ set name [$dir_listbox itemcget $current_item -text]
+ set type "Directory"
+ } {
+ set name [$file_listbox itemcget $current_item -data]
+ if {[lindex $name 0] == {}} {
+ set name [lindex $name 1]
+ set type "Directory"
+ } {
+ set name [lindex $name 0]
+ set type "File"
+ }
+ }
+
+ # Determinate full name
+ set fullname [file join $current_directory $name]
+ if {![file exists $fullname]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title "Unknown Error" \
+ -message "This file apparently does not exist"
+ return
+ }
+ # Determinate size
+ set size [file size $fullname]
+ append size { B}
+ # Determinate time of the last mofication
+ set modified [clock format [file mtime $fullname] -format {%D %R}]
+ # Determinate time of the last access
+ set accessed [clock format [file atime $fullname] -format {%D %R}]
+ # Determinate group, owner and permissions
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set perms [file attributes $fullname]
+ set group [lindex $perms 1]
+ set owner [lindex $perms 3]
+ set perms [lindex $perms 5]
+ set perms [string range $perms {end-3} end]
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ mask {0400 0200 0100 040 020 010 04 02 01} \
+ {
+ set ::KIFSD::FSD::item_properties($var) [expr {($perms & $mask) > 0}]
+ }
+ }
+
+ # Create dialog window and Notebook
+ set dialog [toplevel ${win}_properties_dialog -class {Configuration dialog} -bg {#EEEEEE}]
+ set nb [NoteBook $dialog.nb -bg {#EEEEEE}]
+ $nb insert end general -text "General"
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ $nb insert end permission -text "Permissions"
+ }
+ $nb raise general
+
+ ## Create GUI elements for tag "General"
+ set frame [frame [$nb getframe general].frame]
+ pack $frame -side top -anchor n -fill x -expand 1
+ # Name:
+ set row 0
+ grid [label $frame.lbl_$row \
+ -text "Name:" -anchor w \
+ -font $listbox_font_short \
+ ] -column 0 -row $row -sticky w -pady 3
+ set ::KIFSD::FSD::item_properties(name) $name
+ grid [ttk::entry $frame.val_lbl_$row \
+ -validate all \
+ -textvariable ::KIFSD::FSD::item_properties(name) \
+ -validatecommand "::KIFSD::FSD::not_empty_entry_validator %W %P" \
+ ] -column 1 -row $row -sticky w -pady 3
+ # Type, Location, Size, Modified, Accessed
+ incr row
+ foreach lbl {Type Location Size Modified Accessed} \
+ value [list $type $current_directory $size $modified $accessed] \
+ {
+ grid [label $frame.lbl_$row \
+ -text "$lbl:" -anchor w \
+ -font $listbox_font_short \
+ ] -column 0 -row $row -sticky w -pady 3
+ grid [label $frame.val_lbl_$row \
+ -text $value -anchor w \
+ ] -column 1 -row $row -sticky w -pady 3
+ incr row
+ }
+ grid columnconfigure $frame 0 -minsize 100
+
+ ## Create GUI elements for tag "Permissions"
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set frame [$nb getframe permission]
+ set ap_frame [ttk::labelframe $frame.ap_frame \
+ -text "Access permissions" \
+ ]
+ set i 0
+ foreach text {Class Read Write Exec Owner Group Others} \
+ row {0 0 0 0 1 2 3} \
+ col {0 1 2 3 0 0 0} \
+ {
+ grid [label $ap_frame.lbl_$i \
+ -text $text -justify center \
+ ] -row $row -column $col -sticky w -padx 4 -pady 4
+ incr i
+ }
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ row {1 1 1 2 2 2 3 3 3} \
+ col {1 2 3 1 2 3 1 2 3} \
+ {
+ grid [checkbutton $ap_frame.check_$i \
+ -variable ::KIFSD::FSD::item_properties($var)
+ ] -row $row -column $col
+ incr i
+ }
+
+ grid columnconfigure $ap_frame 0 -minsize 70
+ grid columnconfigure $ap_frame 0 -weight 1
+ pack $ap_frame -side top -fill x -expand 1 -padx 5 -pady 5 -anchor nw
+
+ set own_frame [ttk::labelframe $frame.own_frame \
+ -text "Ownership" \
+ ]
+ grid [label $own_frame.owner_lbl \
+ -text "Owner" -font $listbox_font_short \
+ ] -row 0 -column 0 -padx 10 -pady 3 -sticky w
+ grid [label $own_frame.owner_val_lbl \
+ -text $owner -anchor w \
+ ] -row 0 -column 1 -padx 10 -pady 3 -sticky we
+ grid [label $own_frame.group_lbl \
+ -text "Group" -font $listbox_font_short \
+ ] -row 1 -column 0 -padx 10 -pady 3 -sticky w
+ grid [label $own_frame.group_val_lbl \
+ -text $group -anchor w \
+ ] -row 1 -column 1 -padx 10 -pady 3 -sticky we
+ grid columnconfigure $own_frame 0 -minsize 70
+ grid columnconfigure $own_frame 1 -weight 1
+ pack $own_frame -side top -fill x -expand 1 -padx 5 -pady 5
+ }
+
+ # Create bottom frame (buttons: "Ok" and "Cancel")
+ set bottom_frame [frame $dialog.bottom_frame]
+ pack [ttk::button $bottom_frame.ok \
+ -text "Ok" \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "$this properties_ok $dialog $fullname" \
+ ] -side left
+ pack [ttk::button $bottom_frame.cancel \
+ -text "Cancel" \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ]
+
+ # Pack notebook and bottom frame
+ pack $nb -fill both -expand 1 -padx 10 -pady 5
+ pack $bottom_frame -anchor e -after $nb -padx 10 -pady 5
+
+ # Configure dialog window
+ wm title $dialog "Item properties"
+ wm minsize $dialog 280 320
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog"
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ ## Confirm item properties dialog
+ # @parm Widget dialog - Dialog window
+ # @parm String file - File URL
+ # @return void
+ public method properties_ok {dialog file} {
+ set error 0
+ set perm 0
+
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ val {256 128 64 32 16 8 4 2 1} {
+ if {$::KIFSD::FSD::item_properties($var)} {
+ incr perm $val
+ }
+ }
+ if {[catch {file attributes $file -permissions "0[format {%o} $perm]"}]} {
+ set error 1
+ tk_messageBox -type ok -icon warning -parent $dialog \
+ -title "Permission denied" \
+ -message "Unable to change permission for file:\n[file tail $file]"
+ }
+ }
+ set dir [file dirname $file]
+
+ if {${::KIFSD::FSD::item_properties(name)} != [file tail $file]} {
+ if {[catch {
+ file rename -force -- \
+ $file [file join $dir \
+ ${::KIFSD::FSD::item_properties(name)}]}]
+ } {
+ set error 1
+ tk_messageBox -type ok -icon warning -parent $dialog \
+ -title "Permission denied" \
+ -message "Unable to rename file:\n[file tail $file]\n\t=>\n${::KIFSD::FSD::item_properties(name)}"
+ }
+ reload
+ }
+
+ if {!$error} {
+ grab release $dialog
+ destroy $dialog
+ }
+ }
+
+ ## Validate EntryBox containing directory location (set background color: red/white)
+ # @parm widget combobox - ComboBox widget or {}
+ # @parm Widget widget - EntryBox widget
+ # @parm String content - EntryBox content
+ # @return Bool - Always 1
+ proc dir_validate {combobox widget content} {
+ if {![file exists $content] || ![file isdirectory $content]} {
+ if {$combobox != {}} {
+ $combobox configure -style FSD_RedBg.TCombobox
+ } {
+ $widget configure -bg {#FFDDDD}
+ }
+ } {
+ if {$combobox != {}} {
+ $combobox configure -style TCombobox
+ } {
+ $widget configure -bg {#DDFFDD}
+ }
+
+ # Fill directory location combobox
+ if {$combobox != {}} {
+ set folder $content
+ set values {}
+ while 1 {
+ lappend values $folder
+ if {$folder == [file separator]} {break}
+ if {$::MICROSOFT_WINDOWS} {
+ if {[regexp {^\w+:[\\\/]?$} $folder]} {break}
+ }
+ set folder [file normalize [file join $folder {..}]]
+ }
+ foreach folder [::KIFSD::FSD::dir_cmd $content 1] {
+ if {$folder == {..}} {continue}
+ lappend values [file join $content $folder]
+ }
+ if {$::MICROSOFT_WINDOWS} { ;# Include drive letters on Microsoft Windows
+ foreach drive_letter {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
+ if {[file exists "${drive_letter}:/"]} {
+ lappend values "${drive_letter}:/"
+ }
+ }
+ }
+ $combobox configure -values $values
+ }
+ }
+ return 1
+ }
+
+ ## Reload content of directories ListBox and files ListBox
+ # @return void
+ public method reload {} {
+ update idle
+ change_directory $current_directory
+ }
+
+ ## Modify command for directory ComboBox
+ # @return void
+ public method dir_cb_modify {} {
+ change_directory [$dir_combobox get]
+ }
+
+ ## Go to parrent folder
+ # @return void
+ public method up {} {
+ change_directory [file join $current_directory {..}]
+ }
+
+ ## Go back in history
+ # @return void
+ public method back {} {
+ # Determinate new folder
+ set folder [lindex $back_history end]
+ if {$folder == {}} {return}
+
+ # Adjust backward and forward history
+ set back_history [lreplace $back_history end end]
+ lappend forward_history $current_directory
+
+ # Make backup copy of backward and forward history
+ set tmp_forw_hist $forward_history
+ set tmp_back_hist $back_history
+
+ # Change current directory
+ change_directory $folder
+
+ # Restore backward and forward history
+ set forward_history $tmp_forw_hist
+ set back_history $tmp_back_hist
+
+ # Enable / Disable buttons "Back" and "Forward"
+ if {![llength $back_history]} {
+ $toolbar.back configure -state disabled
+ $win.listbox_menu entryconfigure [mc "Back"] -state disabled
+ } {
+ $toolbar.back configure -state normal
+ $win.listbox_menu entryconfigure [mc "Back"] -state normal
+ }
+ $win.listbox_menu entryconfigure [mc "Forward"] -state normal
+ $toolbar.forward configure -state normal
+ }
+
+ ## Go forward in history
+ # @return void
+ public method forward {} {
+ # Determinate new folder
+ set folder [lindex $forward_history end]
+ if {$folder == {}} {return}
+
+ # Adjust backward and forward history
+ set forward_history [lreplace $forward_history end end]
+ lappend back_history $current_directory
+
+ # Make backup copy of backward and forward history
+ set tmp_forw_hist $forward_history
+ set tmp_back_hist $back_history
+
+ # Change current directory
+ change_directory $folder
+
+ # Restore backward and forward history
+ set forward_history $tmp_forw_hist
+ set back_history $tmp_back_hist
+
+ # Enable / Disable buttons "Back" and "Forward"
+ if {![llength $forward_history]} {
+ $toolbar.forward configure -state disabled
+ $win.listbox_menu entryconfigure [mc "Forward"] -state disabled
+ } {
+ $toolbar.forward configure -state normal
+ $win.listbox_menu entryconfigure [mc "Forward"] -state normal
+ }
+ $toolbar.back configure -state normal
+ $win.listbox_menu entryconfigure [mc "Back"] -state normal
+ }
+
+ ## Invoke dialog to create a new directory
+ # @return void
+ public method newdir {} {
+ # Create dialog window
+ set dialog [toplevel ${win}_new_dir -class {New directory} -bg {#EEEEEE}]
+
+ # Create dialog header and EntryBox
+ pack [label $dialog.header -justify left -text [mc "Create new folder in:\n%s" $current_directory]] \
+ -side top -anchor w -padx 15 -pady 5
+ pack [ttk::entry $dialog.entry \
+ ] -side top -fill x -expand 1 -padx 5 -pady 5
+
+ # Bind button enter to confirmation action
+ bind $dialog.entry <Return> "[list $this create_new_folder]; break"
+ bind $dialog.entry <KP_Enter> "[list $this create_new_folder]; break"
+
+ # Create bottom frame (Buttons: "Clear", "Ok" and "Cancel")
+ set button_frame [frame $dialog.bottom]
+ pack [ttk::button $button_frame.clear \
+ -text [mc "Clear"] \
+ -compound left \
+ -image ::ICONS::16::clear_left \
+ -command "$dialog.entry delete 0 end" \
+ ] -side left -expand 0
+ pack [ttk::button $button_frame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command [list $this create_new_folder] \
+ ] -side left -expand 0
+ pack [ttk::button $button_frame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side left -expand 0
+ pack $button_frame -side bottom -anchor e -expand 0 -padx 5 -pady 5
+
+ # Configure dialog window
+ wm iconphoto $dialog ::ICONS::16::folder_new
+ wm title $dialog [mc "New folder"]
+ wm resizable $dialog 1 0
+ wm minsize $dialog 340 120
+ wm geometry $dialog 340x120
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ "
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ focus -force $dialog.entry
+ tkwait window $dialog
+ }
+
+ ## Confirm dialog "Create new folder"
+ # @return void
+ public method create_new_folder {} {
+ set dialog "${win}_new_dir"
+ set folder [$dialog.entry get]
+ set error 0
+
+ if {$folder == {}} {
+ set error 1
+ }
+ if {$error || [catch {file mkdir [file join $current_directory $folder]}]} {
+ tk_messageBox \
+ -parent $dialog \
+ -icon warning \
+ -type ok \
+ -title [mc "Unable to create folder"] \
+ -message [mc "Unable to create the specified folder"]
+ } {
+ grab release $dialog
+ destroy $dialog
+ reload
+ }
+ }
+
+ ## Sort the given list of strings
+ # This procedure is closely related to inner logic of this
+ #+ class and it is difficult to properly explain its function
+ # @parm List items - List to sort
+ # @return void
+ proc sort_items {items} {
+ # Determinate sorting order
+ if {${::KIFSD::FSD::config(reverse_sorting)}} {
+ set order "-decreasing"
+ } {
+ set order "-increasing"
+ }
+
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ if {${::KIFSD::FSD::config(case_insensitive)}} {
+ set method "-dictionary"
+ } {
+ set method "-ascii"
+ }
+ return [lsort $method $order $items]
+ } {
+ if {${::KIFSD::FSD::config(sorting)} == {size}} {
+ # Sort by size
+ set index 2
+ } {
+ # Sort by date
+ set index 1
+ }
+ set items [lsort -index $index $order $items]
+
+ set result {}
+ foreach file $items {
+ lappend result [lindex $file 0]
+ }
+ return $result
+ }
+ }
+
+ ## Get unsorted list of subdirectories in the given directory
+ # @parm String dir - Directory
+ # @return List - List of relative URLs
+ proc get_dirs_simple {dir} {
+ # Search for directories
+ set result [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [glob -nocomplain -tails -directory $dir -types d *]
+ }
+
+ # Include hidden directories
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [concat $result [glob -nocomplain -tails -directory $dir -types {d hidden} *]]
+ }
+
+ # Filter "." and ".."
+ set foo_idx [lsearch $result {..}]
+ if {$foo_idx != -1} {
+ set result [lreplace $result $foo_idx $foo_idx]
+ set foo_idx [lsearch $result {.}]
+ if {$foo_idx != -1} {
+ set result [lreplace $result $foo_idx $foo_idx]
+ }
+ }
+ }
+
+ return $result
+ }
+
+ ## Get unsorted list of subdirectories in the given directory
+ # @parm String dir - Directory
+ # @return List - {{relative_URL mtime size_in_B} ... }
+ proc get_dirs_extended {dir} {
+ set result {}
+
+ # Search for directories
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types d *] {
+ lappend result [list $file [file mtime [file join $dir $file]] 0]
+ }
+ }
+
+ # Include hidden directories
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types {d hidden} *] {
+ # Filter "." and ".."
+ if {$file == {.} || $file == {..}} {
+ continue
+ }
+ # Translate to full URL
+ lappend result [list $file [file mtime [file join $dir $file]] 0]
+ }
+ }
+ }
+
+ return $result
+ }
+
+ ## Get unsorted list of files in the given directory matching the given GLOB
+ # @parm String dir - Directory
+ # @parm GLOB mask - Glob expression
+ # @return List - List of relative URLs
+ proc get_files_simple {dir mask} {
+ set result [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [glob -nocomplain -tails -directory $dir -types f $mask]
+ }
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set result [concat $result \
+ [glob -nocomplain -tails -directory $dir -types {f hidden} $mask]]
+ }
+ }
+ return $result
+ }
+
+ ## Get unsorted list of files in the given directory matching the given GLOB
+ # @parm String dir - Directory
+ # @parm GLOB mask - Glob expression
+ # @return List - {{relative_URL mtime size_in_B} ... }
+ proc get_files_extended {dir mask} {
+ set result {}
+
+ # Search for files matching the given GLOB
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types f $mask] {
+ if {[catch {
+ lappend result [list \
+ $file \
+ [file mtime [file join $dir $file]] \
+ [file size [file join $dir $file]] \
+ ]
+ }]} {
+ lappend result [list $file 0 0]
+ }
+ }
+ }
+
+ # Include hidden files
+ if {${::KIFSD::FSD::config(show_hidden_files)}} {
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -nocomplain -tails -directory $dir -types {f hidden} $mask] {
+ if {[catch {
+ lappend result [list \
+ $file \
+ [file mtime [file join $dir $file]] \
+ [file size [file join $dir $file]] \
+ ]
+ }]} {
+ lappend result [list $file 0 0]
+ }
+ }
+ }
+ }
+ return $result
+ }
+
+ ## Get list of items to load to directories ListBox
+ # @parm String - Source directory
+ # @parm Bool = 0 - No details
+ # @return List - {text text ...}
+ proc dir_cmd args {
+ # Parse input arguments
+ set dir [lindex $args 0]
+ set no_detail [lindex $args 1]
+ if {$no_detail == {}} {
+ set no_detail 0
+ }
+
+ # Normalize directory and determinate its parent
+ set dir [file normalize $dir]
+ if {$dir != {/}} {
+ set parent {..}
+ } {
+ set parent {}
+ }
+
+
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ set result [sort_items [get_dirs_simple $dir]]
+ } {
+ set result [sort_items [get_dirs_extended $dir]]
+ }
+
+ if {!$no_detail && ${::KIFSD::FSD::config(detailed_view)}} {
+ return [concat $parent [add_details $result $dir]]
+ } {
+ return [concat $parent $result]
+ }
+ }
+
+ ## Get list of items to load to files ListBox
+ # @parm String - Source directory
+ # @parm GLOB - GLOB expression which must match each returned file
+ # @parm Bool = 0 - Detailed view
+ # @return List - {text text ...}
+ proc file_cmd args {
+ # Parse input arguments
+ set dir [lindex $args 0]
+ set mask [lindex $args 1]
+ set no_detail [lindex $args 2]
+ if {$no_detail == {}} {
+ set no_detail 0
+ }
+
+
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ set result [sort_items [get_files_simple $dir $mask]]
+ } {
+ set result [sort_items [get_files_extended $dir $mask]]
+ }
+ if {!$no_detail && ${::KIFSD::FSD::config(detailed_view)}} {
+ return [add_details $result $dir]
+ } {
+ return $result
+ }
+ }
+
+ ## Adjust list of files/directories returned by proc. file_cmd to
+ #+ format required to display in detailed view mode
+ # @parm List filelist - List returned by procedure file_cmd
+ # @parm String dir - Directory
+ # @return List - {{text text text ... } ... }
+ proc add_details {filelist dir} {
+ set result {}
+ foreach filename $filelist {
+ set line $filename
+ set fullfilename [file join $dir $filename]
+ if {[string length $line] > 31} {
+ set line [string range $line 0 27]
+ append line {...}
+ }
+ if {[catch {
+ append line [string repeat "\t" [expr {4 - ([string length $line] / 8)}]]
+ set size [file size $fullfilename]
+ if {$size < 1024} {
+ append size { B}
+ } elseif {$size < 1048576} {
+ set size [expr {($size * 10) / 1024}]
+ if {$size > 1023} {
+ set size [expr {$size / 10}]
+ } {
+ set size [string range $size 0 {end-1}].[string range $size end end]
+ }
+ append size { kB}
+ } elseif {$size < 1073741824} {
+ set size [expr {($size * 10) / 1048576}]
+ if {$size > 1023} {
+ set size [expr {$size / 10}]
+ } {
+ set size [string range $size 0 {end-1}].[string range $size end end]
+ }
+ append size { MB}
+ } elseif {$size < 1099511627776} {
+ set size [expr {($size * 10) / 1073741824}]
+ if {$size > 1023} {
+ set size [expr {$size / 10}]
+ } {
+ set size [string range $size 0 {end-1}].[string range $size end end]
+ }
+ append size { GB}
+ } else {
+ set size {>1TB}
+ }
+ }]} {
+ append line { - ---- -------- -----}
+ } else {
+ if {!$::MICROSOFT_WINDOWS} {
+ append line [string repeat { } [expr {8 - [string length $size]}]] $size " " \
+ [string range [lindex [file attributes $fullfilename] 5] {end-3} end] " " \
+ [clock format [file mtime $fullfilename] -format {%D %R}]
+ } {
+ append line [string repeat { } [expr {8 - [string length $size]}]] $size " " \
+ [clock format [file mtime $fullfilename] -format {%D %R}]
+ }
+ }
+ lappend result [list $line $filename]
+ }
+ return $result
+ }
+
+ ## Get list of items to load to files ListBox (mode "Separate folders" OFF)
+ # @parm String dir - Source directory
+ # @parm GLOB mask - GLOB expression which must match each returned file
+ # @return List - {text text ...}
+ proc dir_file_cmd {dir mask} {
+ set dir [file normalize $dir]
+ set result {}
+
+ # Determinate list of directories
+ if {${::KIFSD::FSD::config(sorting)} == {name}} {
+ set result [concat [get_dirs_simple $dir] [get_files_simple $dir $mask]]
+ } {
+ set result [concat [get_dirs_extended $dir] [get_files_extended $dir $mask]]
+ }
+ if {$dir != {/}} {
+ set parent [list [list {..} {u}]]
+ } {
+ set parent {}
+ }
+ set tmp_result {}
+
+ # Determinate list of files
+ if {${::KIFSD::FSD::config(detailed_view)}} {
+ foreach item [sort_items $result] {
+ if {![file exists [file join $dir $item]]} {continue}
+ if {[file isdirectory [file join $dir $item]]} {
+ lappend tmp_result [concat [add_details [list $item] $dir] d]
+ } {
+ lappend tmp_result [concat [add_details [list $item] $dir] f]
+ }
+ }
+ } {
+ foreach item [sort_items $result] {
+ if {![file exists [file join $dir $item]]} {continue}
+ if {[file isdirectory [file join $dir $item]]} {
+ lappend tmp_result [list $item d]
+ } {
+ lappend tmp_result [list $item f]
+ }
+ }
+ }
+ return [concat $parent $tmp_result]
+ }
+
+ ## Get configuration list for procedure load_config_array
+ # @return List - (List which specifies bookmarks, settings and such things)
+ proc get_config_array {} {
+ return [regsub -all "\n" [array get ::KIFSD::FSD::config] { }]
+ }
+
+ ## Load configuration list returned by procedure get_config_array
+ # @parm List config - (List which specifies bookmarks, settings and such things)
+ # @return void
+ proc load_config_array {config} {
+ if {$config == {}} {
+ return
+ }
+ if {[catch {
+ array set ::KIFSD::FSD::config $config
+ }]} {
+ puts stderr "KI File Selection Dialog: Unable to load the given configuration string -- using default"
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Get descriptor of dialog window
+ # @return Widget - Dialog window
+ public method get_window_name {} {
+ return $win
+ }
+}
+
+## Text variables for dialog "Edit entry in Quick access bar"
+set KIFSD::FSD::qa_panel_dialog_url_entry {} ;# Entry URL
+set KIFSD::FSD::qa_panel_dialog_name_entry {} ;# Entry name
+set KIFSD::FSD::qa_panel_dialog_icon {} ;# Icon number [0;3]
+
+## Dialog configuration array (these values are daults)
+ # Invalid configuration list may cause program error !
+
+array set KIFSD::FSD::config {
+ win_geometry {720x380}
+ detailed_view 0
+ separate_folders 1
+ quick_access_panel 1
+ sorting name
+ reverse_sorting 0
+ folders_first 1
+ case_insensitive 1
+ show_hidden_files 0
+ right_PW_size 200
+ main_PW_size 180
+ bookmarks {}
+ quick_access_bar_data {
+ {0 {/} {/}}
+ {1 {Home} {~}}
+ {2 {Desktop} {~/Desktop}}
+ }
+}
+
+if {$::MICROSOFT_WINDOWS} {
+ set KIFSD::FSD::config(quick_access_bar_data) [subst {
+ {0 {System Drive ${::env(SystemDrive)}} {${::env(SystemDrive)}}}
+ {1 {Documents and Settings} {${::env(USERPROFILE)}}}
+ }]
+}
diff --git a/lib/dialogs/my_tk_messageBox.tcl b/lib/dialogs/my_tk_messageBox.tcl
new file mode 100755
index 0000000..1a559fe
--- /dev/null
+++ b/lib/dialogs/my_tk_messageBox.tcl
@@ -0,0 +1,283 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Replacement for Tk's tk_messageBox. Usage is the same as tk_messageBox,
+# except for one thing, this one supports also "-icon ok".
+# --------------------------------------------------------------------------
+
+## This namespace implements dialog itself, but does not contain the
+ # "tk_messageBox" function to invoke it. This function is defined onwards, but
+ # still in this file.
+namespace eval my_tk_messageBox {
+ ## Namespace variables
+ variable return_value {} ;# String: Dialog return value (e.g. "abort")
+ variable dialog ;# Widget: Dialog toplevel window
+ # Buttons available in the dialog
+ variable available_buttons {
+ abort retry ignore
+ ok cancel yes
+ no
+ }
+ # Icons for available buttons
+ variable button_icons {
+ button_cancel reload forward
+ ok cancel ok
+ no
+ }
+
+ ## Invoke the dialog
+ # @parm Int arg_default - Number of default button (0..2)
+ # @parm String arg_icon - Dialog icon (one of values mentioned in variable button_icons)
+ # @parm String arg_message - Message to display to the user
+ # @parm Widget arg_parent - GUI parent
+ # @parm String arg_title - Dialog title
+ # @parm String arg_type - Name of big icon displyed beside the message (one of {error info question warning ok})
+ # @return String - Dialog return value, name of pressed button
+ proc create {arg_default arg_icon arg_message arg_parent arg_title arg_type} {
+ variable return_value {} ;# String: Dialog return value (e.g. "abort")
+ variable button_icons ;# Icons for available buttons
+ variable available_buttons ;# Buttons available in the dialog
+ variable dialog ;# Widget: Dialog toplevel window
+
+ set dialog [toplevel .my_tk_messageBox]
+ set buttons [list]
+
+ # Translate icon name
+ switch -- $arg_icon {
+ {error} {
+ set iconphoto {cancel}
+ set arg_icon {messagebox_critical}
+ }
+ {info} {
+ set iconphoto {info}
+ set arg_icon {messagebox_info}
+ }
+ {question} {
+ set iconphoto {help}
+ set arg_icon {help}
+ }
+ {warning} {
+ set iconphoto {status_unknown}
+ set arg_icon {messagebox_warning}
+ }
+ {ok} {
+ set iconphoto {ok}
+ set arg_icon {button_ok}
+ }
+ }
+
+ # Determinate list of buttons
+ switch -- $arg_type {
+ {abortretryignore} {
+ set buttons [list abort retry ignore]
+ }
+ {ok} {
+ set buttons [list ok]
+ }
+ {okcancel} {
+ set buttons [list ok cancel]
+ }
+ {retrycancel} {
+ set buttons [list retry cancel]
+ }
+ {yesno} {
+ set buttons [list yes no]
+ }
+ {yesnocancel} {
+ set buttons [list yes no cancel]
+ }
+ }
+
+ # Adjuts argument "default"
+ if {$arg_default == {}} {
+ set arg_default [lindex $buttons 0]
+ } elseif {[lsearch -ascii -exact $buttons $arg_default] == -1} {
+ error "my_tk_messageBox: Invalid value of agument -default, must be one of: $buttons"
+ }
+
+ # Create top frame (dialog icon and text of the message)
+ set top_frame [frame $dialog.top]
+ pack [label $top_frame.img -image ::ICONS::32::$arg_icon] -side left
+ pack [label $top_frame.txt -text $arg_message -wraplength 300] -side left -fill both
+
+ # Create bottom bar with dialog buttons
+ set bottom_frame [frame $dialog.bottom]
+ foreach button $buttons {
+ set button_icon [lindex $button_icons [ \
+ lsearch $available_buttons $button \
+ ]]
+
+ set text [string toupper [string index $button 0]]
+ append text [string range $button 1 end]
+
+ pack [ttk::button $bottom_frame.button_${button} \
+ -text [mc $text] -compound left \
+ -image ::ICONS::16::$button_icon \
+ -command "::my_tk_messageBox::button_press $button" \
+ ] -side left -padx 2
+ bind $bottom_frame.button_${button} <Return> "::my_tk_messageBox::button_press $button"
+ bind $bottom_frame.button_${button} <KP_Enter> "::my_tk_messageBox::button_press $button"
+ }
+
+ # Pack window frames
+ pack $top_frame -expand 1 -padx 10 -pady 10
+ pack $bottom_frame -padx 5 -pady 10
+
+ # Window manager options -- modal window
+ wm iconphoto $dialog ::ICONS::16::$iconphoto
+ wm title $dialog $arg_title
+ wm state $dialog normal
+ focus -force $bottom_frame.button_${arg_default}
+ if {$arg_parent != {}} {
+ wm transient $dialog $arg_parent
+ }
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ set ::my_tk_messageBox::return_value {}
+ "
+ update
+ grab $dialog
+
+ # Wait for user response
+ tkwait window $dialog
+
+ # Destroy dialog and return name of pressed button
+ catch {
+ grab release $dialog
+ destroy $dialog
+ }
+ return $return_value
+ }
+
+ ## Handles button press
+ # @parm String value - Name of pressed button
+ # @return void
+ proc button_press {value} {
+ variable return_value ;# String: Dialog return value (e.g. "abort")g
+ variable dialog ;# Widget: Dialog toplevel window
+
+ grab release $dialog
+ destroy $dialog
+ set return_value $value
+ }
+
+ ## Load needed images from the specified directory
+ # @parm String directory - Source directory
+ # @return void
+ proc load_images {directory} {
+ foreach subdir {16x16 32x32} ns {16 32} icons {
+ {cancel info help status_unknown ok button_cancel reload forward no}
+ {messagebox_critical messagebox_info help messagebox_warning button_ok}
+ } {
+ foreach icon $icons {
+ set filename [file join $directory {../icons} $subdir "${icon}.png"]
+
+ if {[catch {
+ image create photo ::ICONS::${ns}::${icon} -format png -file $filename
+ } result]} then {
+ puts stderr {}
+ puts -nonewline stderr $result
+ image create photo ::ICONS::${ns}::${icon}
+ }
+ }
+ }
+ }
+}
+
+## Replacement for Tk's command "tk_messageBox"
+ # Usage is the same as "tk_messageBox" ...
+proc my_tk_messageBox args {
+ set length [llength $args]
+ if {$length % 2} {
+ error "my_tk_messageBox: Odd number of arguments given"
+ }
+
+ set arg_default {}
+ set arg_icon {info}
+ set arg_message {}
+ set arg_parent {}
+ set arg_title {}
+ set arg_type {}
+
+ for {set i 0; set j 1} {$i < $length} {incr i 2; incr j 2} {
+ set attr [lindex $args $i]
+ set val [lindex $args $j]
+
+ switch -- $attr {
+ {-default} {
+ set arg_default $val
+ }
+ {-icon} {
+ if {[lsearch -ascii -exact {error info question warning ok} $val] == -1} {
+ error "my_tk_messageBox: Invalid message box icon: $val"
+ }
+ set arg_icon $val
+ }
+ {-message} {
+ set arg_message $val
+ }
+ {-parent} {
+ if {![winfo exists $val]} {
+ error "my_tk_messageBox: Window $val does not exist."
+ }
+ set arg_parent $val
+ }
+ {-title} {
+ set arg_title $val
+ }
+ {-type} {
+ if {[lsearch -ascii -exact {abortretryignore ok okcancel retrycancel yesno yesnocancel} $val] == -1} {
+ error "my_tk_messageBox: Invalid message box type: $val"
+ }
+ set arg_type $val
+ }
+ default {
+ error "my_tk_messageBox: Unknown argument: $attr"
+ }
+ }
+ }
+
+ if {![string length $arg_message]} {
+ error "my_tk_messageBox: No message box text specified"
+ }
+ if {![string length $arg_title]} {
+ if {![string length $arg_icon]} {
+ set arg_title {Message}
+ } {
+ set arg_title [string toupper [string index $arg_icon 0]]
+ append arg_title [string range $arg_icon 1 end]
+ }
+ }
+ if {![string length $arg_type]} {
+ set arg_type {ok}
+ }
+
+ return [my_tk_messageBox::create $arg_default $arg_icon $arg_message $arg_parent $arg_title $arg_type]
+}
+
+# Replace Tk's command "tk_messageBox"
+rename tk_messageBox old_tk_messageBox
+rename my_tk_messageBox tk_messageBox
diff --git a/lib/dialogs/selectmcu.tcl b/lib/dialogs/selectmcu.tcl
new file mode 100755
index 0000000..86d2fae
--- /dev/null
+++ b/lib/dialogs/selectmcu.tcl
@@ -0,0 +1,1537 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# This namespace implements "MCU selection" dialog.
+#
+# Usage:
+#
+# Invocation of MCU selection dialog
+# ==================================
+# SelectMCU::activate <parent> <initial_mcu_type xram_cap xcode_cap>
+# -> {mcu_type xdata xcode}
+#
+#
+# Other functions
+# ==================================
+#
+# SelectMCU::get_avaliable_processors
+# -> List of avaliable processors (e.g. {80C51 AT89C52 AT89C4051})
+#
+# SelectMCU::get_processor_details processor_type
+# -> List of MCU definition (see proc. xml_data_parser1)
+# --------------------------------------------------------------------------
+
+namespace eval SelectMCU {
+ # String: Path to MCUs definition file
+ variable definition_file "${::LIB_DIRNAME}/../data/mcus.xml"
+ # List: Avaliable MCU vendors
+ variable vendors {all Atmel Intel}
+ variable selected_mcu {} ;# List: Dialog return value {mcu_type xdata xcode}
+ variable definition_data {} ;# List: Values gained from $definition_file
+ variable mcu_names {} ;# List: Avaliable processors
+ variable maximum_xcode 0xFFFF ;# Int: Maximum external program memory (0xFFFF - internal)
+ variable vendor {all} ;# String: Selected vendor
+
+ ## Variables related to GUI
+ variable parent ;# Widget: Dialog parent (another window)
+ variable win ;# Widget: Dialog window
+ variable search_bar ;# Widget: Search bar entry box
+ variable search_bar_clear ;# Widget: Search bar clear button
+ variable listbox_widget ;# Widget: List box containing avaliable MCUs
+ variable value_lbl_uart ;# Widget: Label "UART:" - value
+ variable value_lbl_voltage ;# Widget: Label "Operating voltage:" - value
+ variable value_lbl_interrupts ;# Widget: Label "Interrupts:" - value
+ variable value_lbl_timers ;# Widget: Label "Timers:" - value
+ variable value_lbl_vendor ;# Widget: Label "Vendor" - value
+ variable more_details_text ;# Widget: TextWidget "More details:"
+ variable more_details_scrollbar ;# Widget: Scrollbar for $more_details_text
+ variable details_xdata_aval ;# Widget: Frame containing scale and spinbox for XDATA memory
+ variable details_xdata_note ;# Widget: Frame containing label "NOT AVALIABLE" for XDATA memory
+ variable details_xcode_aval ;# Widget: Frame containing scale and spinbox for XCODE memory
+ variable details_xcode_nota ;# Widget: Frame containing label "NOT AVALIABLE" for XCODE memory
+ variable name_label ;# Widget: Label containing name of selected MCU
+ variable image_label ;# Widget: Label with image for selected MCU
+ variable xdata_scale ;# Widget: Scale for XDATA memory
+ variable xdata_spinbox ;# Widget: SpinBox for XDATA memory
+ variable xcode_scale ;# Widget: Scale for XCODE memory
+ variable xcode_spinbox ;# Widget: SpinBox for XCODE memory
+
+ ## Variables related to XML parser
+ variable current_element ;# String: Current XML element
+ variable expected ;# String: Expected next XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable current_mcu ;# String: Name of MCU currently being parsed
+
+ ## Fonts used in the selection dialog
+ # ListBox containing avaliable fonts
+ variable listbox_widget_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ -weight bold \
+ ]
+ # ListBox header -- label widget above the ListBox
+ variable listbox_header_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ ]
+ # Label with the MCU name
+ variable name_font [font create \
+ -family {helvetica} -size -20 \
+ -weight bold \
+ ]
+ # Labels like "Vendor:", "UART:", "Timers:", etc.
+ variable normal_font [font create \
+ -family {helvetica} -size -12 \
+ ]
+ # Labels with values like for "Vendor:", "Timers:", etc.
+ variable bold_font [font create \
+ -family {helvetica} -size -12 \
+ -weight bold \
+ ]
+
+ ## Invoke MCU selection dialog
+ # @parm Widget Parent - Dialog parent (some window)
+ # @parm String initial - {Initial_MCU Initial_XDATA Initial_XCODE}
+ # @return List - {mcu_type xdata xcode} or {}
+ proc activate {Parent initial} {
+ variable parent ;# Widget: Dialog parent (another window)
+ variable selected_mcu ;# List: Dialog return value {mcu_type xdata xcode}
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable win ;# Widget: Dialog window
+ variable search_bar ;# Widget: Search bar entry box
+
+ # Initialize NS variables
+ set parent $Parent
+ set selected_mcu {}
+ set mcu_definition {}
+
+ # Load MCU definition file
+ if {![load_definition]} {return}
+ set mcu_definition {}
+
+ create_gui ;# Create dialog GUI elements
+ fill_gui ;# Initialize GUI elements
+
+ # Finalize window creation
+ wm iconphoto $win ::ICONS::16::kcmmemory
+ wm title $win [mc "Choose MCU - MCU 8051 IDE"]
+ wm minsize $win 720 500
+ wm protocol $win WM_DELETE_WINDOW {
+ ::SelectMCU::cancel
+ }
+ wm transient $win $parent
+ raise $win
+ catch {
+ grab $win
+ }
+
+ # Initialize XDATA & XCODE scales
+ $search_bar insert end [lindex $initial 0]
+ focus -force $search_bar
+ $search_bar selection range 0 end
+ if {[lindex $initial 1]} {
+ set ::SelectMCU::xdata_ena 1
+ set ::SelectMCU::xdata_value [lindex $initial 1]
+ } {
+ set ::SelectMCU::xdata_ena 0
+ set ::SelectMCU::xdata_value 0
+ xdata_disena
+ }
+ if {[lindex $initial 2]} {
+ set ::SelectMCU::xcode_ena 1
+ set ::SelectMCU::xcode_value [lindex $initial 2]
+ } {
+ set ::SelectMCU::xcode_ena 0
+ set ::SelectMCU::xcode_value 0
+ xcode_disena
+ }
+
+ # Diplay window
+ tkwait window $win
+
+ # Create resulting string
+ if {$selected_mcu == {}} {
+ set result {}
+ } {
+ if {${::SelectMCU::xdata_ena}} {
+ set xdata ${::SelectMCU::xdata_value}
+ } {
+ set xdata 0
+ }
+ if {${::SelectMCU::xcode_value}} {
+ set xcode ${::SelectMCU::xcode_value}
+ } {
+ set xcode 0
+ }
+
+ if {$xdata == {}} {
+ set xdata 0
+ }
+ if {$xcode == {}} {
+ set xcode 0
+ }
+ set result [list $selected_mcu $xdata $xcode]
+ }
+
+ return $result
+ }
+
+ ## Load MCU definitions into the ListBox
+ # @return void
+ proc fill_gui {} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable listbox_widget ;# Widget: List box containing avaliable MCUs
+ variable listbox_widget_font ;# ListBox containing avaliable fonts
+ variable mcu_names ;# List: Avaliable processors
+ variable vendor ;# String: Selected vendor
+
+ # Iterate over defined MCUs
+ foreach mcu $definition_data {
+ # Filter specific vendors
+ if {$vendor != {all} && [lindex $mcu 11] != $vendor} {
+ continue
+ }
+
+ # MCU type
+ set mcu_type [lindex $mcu 0]
+ lappend mcu_names $mcu_type
+ set text $mcu_type
+ set len [string length $mcu_type]
+ append text [string repeat { } [expr {24 - $len}]]
+
+ # Size of program memory
+ set str [lindex $mcu 3]
+ append str { KB}
+ set len [string length $str]
+ append text [string repeat { } [expr {8 - $len}]] $str
+
+ # Size of internal data memory
+ set str [expr {[lindex $mcu 5] + [lindex $mcu 10]}]
+ append str { B}
+ set len [string length $str]
+ append text [string repeat { } [expr {13 - $len}]] $str
+
+ # Number of IO lines + processor frequency
+ set str [lindex $mcu 6]
+ set len [string length $str]
+ append text [string repeat { } [expr {12 - $len}]] $str { } [lindex $mcu 4]
+
+ # Insert the text into the ListBox
+ $listbox_widget insert end #auto \
+ -text $text -data $mcu_type \
+ -font $listbox_widget_font \
+ -image ::ICONS::16::kcmmemory
+ }
+ }
+
+ ## Create GUI elements of the selection dialog window
+ # @return void
+ proc create_gui {} {
+ variable win ;# Widget: Dialog window
+ variable search_bar ;# Widget: Search bar entry box
+ variable search_bar_clear ;# Widget: Search bar clear button
+ variable listbox_widget ;# Widget: List box containing avaliable MCUs
+ variable value_lbl_uart ;# Widget: Label "UART:" - value
+ variable value_lbl_voltage ;# Widget: Label "Operating voltage:" - value
+ variable value_lbl_interrupts ;# Widget: Label "Interrupts:" - value
+ variable value_lbl_timers ;# Widget: Label "Timers:" - value
+ variable value_lbl_vendor ;# Widget: Label "Vendor" - value
+ variable more_details_text ;# Widget: TextWidget "More details:"
+ variable more_details_scrollbar ;# Widget: Scrollbar for $more_details_text
+ variable details_xdata_aval ;# Widget: Frame containing scale and spinbox for XDATA memory
+ variable details_xdata_note ;# Widget: Frame containing label "NOT AVALIABLE" for XDATA memory
+ variable details_xcode_aval ;# Widget: Frame containing scale and spinbox for XCODE memory
+ variable details_xcode_nota ;# Widget: Frame containing label "NOT AVALIABLE" for XCODE memory
+ variable listbox_widget_font ;# ListBox containing avaliable fonts
+ variable listbox_header_font ;# ListBox header -- label widget above the ListBox
+ variable bold_font ;# Labels with values like for "Vendor:", "Timers:", etc.
+ variable normal_font ;# Labels like "Vendor:", "UART:", "Timers:", etc.
+ variable name_font ;# Label with the MCU name
+ variable name_label ;# Widget: Label containing name of selected MCU
+ variable image_label ;# Widget: Label with image for selected MCU
+ variable xdata_scale ;# Widget: Scale for XDATA memory
+ variable xdata_spinbox ;# Widget: Scale for XDATA memory
+ variable xcode_spinbox ;# Widget: SpinBox for XCODE memory
+ variable xcode_scale ;# Widget: Scale for XCODE memory
+ variable vendors ;# List: Avaliable MCU vendors
+
+ # Create toplevel window
+ set win [toplevel .selectmcu_dialog -class {Select MCU} -bg {#EEEEEE}]
+
+ # Create search bar widgets (but don't pack them)
+ set search_bar_frame [frame $win.search_bar_frame]
+ set search_bar_clear [ttk::button $search_bar_frame.clear_but \
+ -image ::ICONS::16::clear_left \
+ -command ::SelectMCU::clear_search_bar \
+ -state disabled \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $search_bar_frame.clear_but \
+ -text [mc "Clear search bar"]
+ set search_bar [ttk::entry $search_bar_frame.search_bar \
+ -validate all \
+ -validatecommand {::SelectMCU::search %P} \
+ ]
+ DynamicHelp::add $search_bar \
+ -text [mc "Search bar, enter something like \"C4051\""]
+
+ # Create ListBox and its scrollbar
+ set top_frame [frame $win.top_frame]
+ set top_left_frame [frame $top_frame.left -bd 1 -relief sunken]
+ set top_left_top_frame [frame $top_left_frame.top]
+ set listbox_widget [ListBox $top_left_frame.listbox \
+ -selectfill 1 -bg {#FFFFFF} -bd 0 -height 0 \
+ -selectbackground {#CCCCFF} -selectmode single \
+ -selectforeground {#0000AA} \
+ -highlightcolor {#BBBBFF} \
+ -highlightthickness 0 -padx 20 -deltay 20 \
+ -yscrollcommand "$top_frame.scrollbar set" \
+ ]
+ if {[winfo exists $listbox_widget.c]} {
+ bind $listbox_widget.c <Button-5> {%W yview scroll +5 units; break}
+ bind $listbox_widget.c <Button-4> {%W yview scroll -5 units; break}
+ }
+ bind $listbox_widget <<ListboxSelect>> {::SelectMCU::select_item}
+ $listbox_widget bindImage <Double-1> {::SelectMCU::close_window;#}
+ $listbox_widget bindText <Double-1> {::SelectMCU::close_window;#}
+ set tree_scrollbar [ttk::scrollbar $top_frame.scrollbar \
+ -orient vertical \
+ -command [list $listbox_widget yview] \
+ ]
+ # Create ListBox header
+ pack [label $top_left_frame.header \
+ -font $listbox_header_font \
+ -bg {#DDDDDD} -bd 0 -padx 25 \
+ -justify left -anchor w \
+ -text [mc "Processor type\t\tCODE mem. IDATA mem. IO lines Frequency"] \
+ ] -fill x
+
+ # Create remaining parts of top frame and pack them
+ pack [label $search_bar_frame.search_label \
+ -text [mc "Search:"] \
+ ] -side left -padx 5
+ pack $search_bar -fill x -expand 1 -side left
+ pack $search_bar_clear -after $search_bar -side left
+ pack [label $search_bar_frame.vendor_label \
+ -text [mc " Vendor:"] \
+ ] -side left -padx 5 -after $search_bar_clear
+ pack [ttk::combobox $search_bar_frame.vendor_cb \
+ -state readonly \
+ -textvariable {::SelectMCU::vendor} \
+ -values $vendors \
+ ] -side left -padx 5 -after $search_bar_frame.vendor_label
+ bind $search_bar_frame.vendor_cb <<ComboboxSelected>> {::SelectMCU::change_vendor}
+ pack $search_bar_frame -fill x -pady 10 -padx 5
+
+ # Pack all frames except the bottom frame and the details frame
+ pack $top_left_top_frame -fill x
+ pack $listbox_widget -fill both -expand 1
+ pack $top_left_frame -fill both -expand 1 -side left
+ pack $tree_scrollbar -fill y -after $top_left_frame -side right
+ pack $top_frame -fill both -expand 1 -padx 5
+
+ # Create parts of details frame
+ set details_frame [frame $win.details_frame]
+ set details_left [frame $details_frame.left]
+ set details_middle [frame $details_frame.middle -width 300]
+ set details_right [frame $details_frame.right]
+ set details_middle_top [frame $details_middle.top]
+ set details_middle_bottom [frame $details_middle.bottom]
+
+ # Left side
+ set name_label [label $details_left.name \
+ -text "" -font $name_font \
+ ]
+ set image_label [label $details_left.image \
+ -image [image create photo] -text { } \
+ -width 200 -height 200 -compound left \
+ ]
+ DynamicHelp::add $image_label -text [mc "One of avaliable packages for selected microcontroller"]
+ pack $name_label -fill x
+ pack $image_label -padx 5
+
+ # General features
+ set i 0
+ foreach text {{Vendor:} {UART:} {Operating voltage:} {Interrupt sources:} {Timers:}} {
+ grid [label $details_middle_top.lbl_$i \
+ -text [mc $text] \
+ -justify left \
+ -font $normal_font \
+ ] -row $i -column 0 -sticky w
+ incr i
+ }
+ set value_lbl_vendor [label $details_middle_top.value_lbl_vendor \
+ -justify left -anchor w -font $bold_font \
+ ]
+ set value_lbl_uart [label $details_middle_top.value_lbl_uart \
+ -justify left -anchor w -font $bold_font \
+ ]
+ set value_lbl_voltage [label $details_middle_top.value_lbl_voltage \
+ -justify left -anchor w -font $bold_font \
+ ]
+ set value_lbl_interrupts [label $details_middle_top.value_lbl_interr \
+ -justify left -anchor w -font $bold_font \
+ ]
+ set value_lbl_timers [label $details_middle_top.value_lbl_timers \
+ -justify left -anchor w -font $bold_font \
+ ]
+ grid $value_lbl_vendor -row 0 -column 1 -sticky we
+ grid $value_lbl_uart -row 1 -column 1 -sticky we
+ grid $value_lbl_voltage -row 2 -column 1 -sticky we
+ grid $value_lbl_interrupts -row 3 -column 1 -sticky we
+ grid $value_lbl_timers -row 4 -column 1 -sticky we
+ grid columnconfigure $details_middle_top 0 -minsize 140
+ grid columnconfigure $details_middle_top 1 -weight 1
+
+ # Details
+ set more_details_text [text $details_middle_bottom.text \
+ -yscrollcommand ::SelectMCU::details_scrollbar_set \
+ -width 0 -heigh 0 -bd 0 -relief flat -font $bold_font \
+ -highlightthickness 0 -state disabled -bg {#EEEEEE} \
+ -cursor left_ptr -fg {#555555} -wrap word \
+ ]
+ set more_details_scrollbar [ttk::scrollbar \
+ $details_middle_bottom.scrollbar \
+ -command "$more_details_text yview" \
+ -orient vertical \
+ ]
+ pack $more_details_text -side left -fill both -expand 1
+
+ # Pack general & details frames
+ pack $details_middle_top -fill both -pady 10
+ pack $details_middle_bottom -fill both -expand 1
+
+ # Cretate XDATA and XCODE scales and such
+ set details_right_top [ttk::labelframe $details_right.top \
+ -text [mc "External RAM"] \
+ ]
+ set details_right_bottom [ttk::labelframe $details_right.bottom \
+ -text [mc "External Program Memory"] \
+ ]
+
+ set details_xdata_note [label $details_right_top.not_avaliable \
+ -text [mc "NOT AVALIABLE"] -fg {#FF8888} \
+ ]
+ set details_xdata_aval [frame $details_right_top.avaliable]
+ pack [checkbutton $details_xdata_aval.checkbutton \
+ -variable ::SelectMCU::xdata_ena \
+ -text [mc "Enable"] \
+ -command ::SelectMCU::xdata_disena \
+ ] -anchor w
+ DynamicHelp::add $details_xdata_aval.checkbutton \
+ -text [mc "Connect external data memory"]
+ set details_right_top_btm [frame $details_xdata_aval.btm]
+ set xdata_scale [ttk::scale $details_right_top_btm.scale \
+ -orient horizontal \
+ -variable ::SelectMCU::xdata_value \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::SelectMCU::xdata_value \[expr {int(\${::SelectMCU::xdata_value})}\]
+ $details_right_top_btm.spinbox selection range 0 end
+ #" \
+ ]
+ DynamicHelp::add $details_right_top_btm.scale \
+ -text [mc "Amount of external data memory"]
+ pack $xdata_scale -fill x -side left -expand 1 -padx 2
+ set xdata_spinbox [spinbox $details_right_top_btm.spinbox \
+ -textvariable ::SelectMCU::xdata_value \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::SelectMCU::validate_xdata %P} \
+ -command "$details_right_top_btm.spinbox selection range 0 end ;#" \
+ ]
+ DynamicHelp::add $details_right_top_btm.spinbox \
+ -text [mc "Amount of external data memory"]
+ pack $xdata_spinbox -side right -after $details_right_top_btm.scale
+ pack $details_right_top_btm -fill both -expand 1
+
+ set details_xcode_nota [label $details_right_bottom.not_avaliable \
+ -text [mc "NOT AVALIABLE"] -fg {#FF8888} \
+ ]
+ set details_xcode_aval [frame $details_right_bottom.avaliable]
+ pack [checkbutton $details_xcode_aval.checkbutton \
+ -variable ::SelectMCU::xcode_ena \
+ -text [mc "Enable"] \
+ -command ::SelectMCU::xcode_disena \
+ ] -anchor w
+ DynamicHelp::add $details_xcode_aval.checkbutton \
+ -text [mc "Connect external program memory"]
+ set details_right_bottom_btm [frame $details_xcode_aval.btm]
+ set xcode_scale [ttk::scale $details_right_bottom_btm.scale \
+ -orient horizontal \
+ -variable ::SelectMCU::xcode_value \
+ -from 0 -to 0xFFFF \
+ -command "
+ set ::SelectMCU::xcode_value \[expr {int(\${::SelectMCU::xcode_value})}\]
+ #" \
+ ]
+ DynamicHelp::add $details_right_bottom_btm.scale \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $xcode_scale -fill x -side left -expand 1 -padx 2
+ set xcode_spinbox [spinbox $details_right_bottom_btm.spinbox \
+ -textvariable ::SelectMCU::xcode_value \
+ -width 5 -from 0 -to 0xFFFF \
+ -bg white -validate all \
+ -vcmd {::SelectMCU::validate_xcode %P} \
+ ]
+ DynamicHelp::add $details_right_bottom_btm.spinbox \
+ -text [mc "Amount of total program memory minus internal program memory"]
+ pack $xcode_spinbox -side right -after $details_right_bottom_btm.scale
+ pack $details_right_bottom_btm -fill both -expand 1
+
+ grid $details_right_top -row 0 -column 0 -sticky wens -padx 5 -pady 10
+ grid $details_right_bottom -row 1 -column 0 -sticky wens -padx 5 -pady 10
+ grid rowconfigure $details_right 0 -minsize 100
+ grid rowconfigure $details_right 1 -minsize 100
+ grid columnconfigure $details_right 0 -weight 1 -minsize 180
+
+ # Pack parts of details frame
+ pack $details_left -side left
+ pack $details_middle -side left -fill both -expand 1 -padx 15 -pady 10
+ pack $details_right -side right -fill y -after $details_middle -padx 5
+ pack $details_frame -fill x -padx 5 -pady 10
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $win.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command {::SelectMCU::close_window} \
+ ] -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {::SelectMCU::cancel} \
+ ] -side left
+ pack [ttk::separator $win.sep -orient horizontal] -fill x
+ pack $buttonFrame -side bottom -after $details_frame -anchor e -padx 10 -pady 5
+ }
+
+ ## Close MCU selection dialog and force its return value to an empty string
+ # @return void
+ proc close_window {} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable mcu_names ;# List: Avaliable processors
+ variable win ;# Widget: Dialog window
+
+ set definition_data {}
+ set mcu_names {}
+ grab release $win
+ destroy $win
+ }
+
+ ## Load MCU database
+ # @return void
+ proc load_definition {} {
+ variable parent ;# Widget: Dialog parent (another window)
+ variable definition_file ;# String: Path to MCUs definition file
+ variable definition_data ;# List: Values gained from $definition_file
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable expected ;# String: Expected next XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+
+ # Initialize NS variables
+ set definition_data {}
+ set mcu_definition {}
+ set expected {mcus}
+ set current_element {}
+ set take_data 0
+
+ # Open definition file
+ if {[catch {
+ set file [open $definition_file {r}]
+ }]} {
+ tk_messageBox \
+ -parent $parent \
+ -type ok \
+ -icon warning \
+ -title mcus.xml \
+ -message [mc "Unable to open file containing supported MCUs,\nplease check your installation"]
+ return 0
+ }
+
+ # Create XML parser
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand {::SelectMCU::xml_data_parser0_element} \
+ -characterdatacommand {::SelectMCU::xml_data_parser0_data} \
+ ]
+
+ # Start XML parser
+ if {[catch {
+ $parser parse [read $file]
+ if {$mcu_definition != {}} {
+ foreach val $mcu_definition {
+ if {$val == {}} {
+ error "Incomplite definition for [lindex $mcu_definition 0]"
+ }
+ }
+ lappend definition_data $mcu_definition
+ }
+ } result]} {
+ set definition_data {}
+ tk_messageBox \
+ -parent $parent \
+ -icon warning \
+ -type ok \
+ -title [mc "Error"] \
+ -message [mc "MCUs database file is currupted,\nplease check your installation"]
+ puts stderr $result
+ close $file
+ return 0
+ }
+
+ # Close file and free parser
+ close $file
+ $parser free
+ return 1
+ }
+
+ ## Get list of MCUs defined in the database
+ # @return List - Defined processors (e.g. {8051 AT89C2051 ...})
+ proc get_avaliable_processors {} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable definition_file ;# String: Path to MCUs definition file
+ variable expected ;# String: Expected next XML element
+
+ # Initialize NS variables
+ set expected {mcus}
+ set definition_data {} ;# <-- Result will be stored here
+
+ # Open database file
+ if {[catch {
+ set file [open $definition_file {r}]
+ }]} {
+ puts stderr "Unable to open file containing supported MCUs, please check your installation"
+ return {}
+ }
+
+ # Create XML parser
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand {::SelectMCU::xml_data_parser2_element} \
+ ]
+
+ # Start XML parser
+ if {[catch {
+ $parser parse [read $file]
+ } result]} {
+ set definition_data {}
+ puts stderr "MCUs database file is currupted,\nplease check your installation"
+ puts stderr $result
+ }
+
+ # Close file and free parser
+ close $file
+ $parser free
+ return $definition_data
+ }
+
+ ## Gain detail description for the given processor
+ # @parm String mcu_name - Processor type (e.g. AT89C51RC)
+ # @return List - (see proc. xml_data_parser1)
+ proc get_processor_details {mcu_name} {
+ variable definition_file ;# String: Path to MCUs definition file
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable current_mcu ;# String: Name of MCU currently being parsed
+
+ # Initialize NS variables
+ set mcu_definition $mcu_name
+ set expected {mcus}
+ set definition_data {} ;# <-- Result will be stored here
+ set take_data 0
+ set current_mcu {}
+
+ # Open database file
+ if {[catch {
+ set file [open $definition_file {r}]
+ }]} {
+ puts stderr "Unable to open file containing supported MCUs, please check your installation"
+ return {}
+ }
+
+ # Create XML parser
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand {::SelectMCU::xml_data_parser1_element} \
+ -characterdatacommand {::SelectMCU::xml_data_parser1_data} \
+ ]
+
+ # Start XML parser
+ if {[catch {
+ $parser parse [read $file]
+ } result]} {
+ set definition_data {}
+ puts stderr "MCUs database file is currupted,\nplease check your installation"
+ puts stderr $result
+ }
+
+ # Close file and free parser
+ close $file
+ $parser free
+ return $definition_data
+ }
+
+ ## XML parser handler for procedure get_avaliable_processors -- Takes XML tags
+ # @parm String arg1 - name of the element
+ # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ proc xml_data_parser2_element {arg1 attrs} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+
+ # Check for consistent formating
+ if {$arg1 != $expected} {
+ error "Bad element `$arg1'"
+ }
+
+ switch -- $arg1 {
+ {mcus} {
+ set expected {mcu}
+ }
+ {mcu} {
+ set expected {timers}
+ set len [llength $attrs]
+
+ # Search for attribute "name"
+ for {set i 0} {$i < $len} {incr i 2} {
+ set val [lindex $attrs $i]
+ if {$val == {name}} {
+ # Append MCU name to result
+ incr i
+ lappend definition_data [lindex $attrs $i]
+ break
+ }
+ }
+ }
+ {timers} {set expected {more}}
+ {more} {set expected {bits}}
+ {bits} {set expected {writeonly}}
+ {writeonly} {set expected {sfr}}
+ {sfr} {set expected {mcu}}
+ }
+ }
+
+
+ ## XML parser handler for procedure get_processor_details -- Takes XML data
+ # @parm String arg1 - content of the element
+ # @return void
+ proc xml_data_parser1_data {arg1} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable current_element ;# String: Current XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+
+ # Take data only if they were expected
+ if {!$take_data} {return}
+ set take_data 0
+
+ # Take data section only for 1 processor
+ if {$mcu_definition == {} || ![llength $definition_data]} {
+ return
+ }
+
+ # Adjust data string
+ set arg1 [string trim $arg1]
+ regsub {\s+} $arg1 { } arg1
+
+ # Validate and store data
+ switch -- $current_element {
+ {bits} { ;# Incomplite registers
+ if {![regexp {([0-9A-Fa-f]{4})?(\s+[0-9A-Fa-f]{4})*} $arg1]} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 18 $arg1
+ }
+ {writeonly} { ;# Write only registers
+ if {![regexp {([0-9A-Fa-f]{2})?(\s+[0-9A-Fa-f]{2})*} $arg1]} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 19 $arg1
+ }
+ {sfr} { ;# Avaliable special function registers and bit addressable bits in SFR
+ lset definition_data 43 $arg1
+
+ set mcu_definition {} ;# This is the last tag
+ }
+ }
+ }
+
+ ## XML parser handler for procedure get_processor_details -- Takes XML tags
+ # @parm String arg1 - name of the element
+ # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ proc xml_data_parser1_element {arg1 attrs} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable current_mcu ;# String: Name of MCU currently being parsed
+ variable current_element ;# String: Current XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+
+ set take_data 0
+
+ ## Take tag attributes
+ set current_element $arg1
+ if {$arg1 != $expected} {
+ error "Bad element `$arg1'"
+ }
+ switch -- $arg1 {
+ {mcus} {
+ set expected {mcu}
+ }
+ {mcu} {
+ set expected {timers}
+ set len [llength $attrs]
+
+ for {set i 0} {$i < $len} {incr i 2} {
+ set val [lindex $attrs $i]
+ if {$val == {name}} {
+ incr i
+ set current_mcu [lindex $attrs $i]
+ if {$mcu_definition != $current_mcu} {
+ return
+ }
+ }
+ }
+
+ set definition_data [list \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} {} {} {} {} \
+ {} {} {} {} \
+ ]
+
+ for {set i 0} {$i < $len} {incr i} {
+ switch -- [lindex $attrs $i] {
+ {xdata} {
+ incr i
+ xml_dp1_attr_yes_no 0 [lindex $attrs $i]
+ }
+ {xcode} {
+ incr i
+ xml_dp1_attr_yes_no 1 [lindex $attrs $i]
+ }
+ {code} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 0xFFFF} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 2 $val
+ }
+ {ram} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 256} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 3 $val
+ }
+ {portbits} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 256} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 4 $val
+ }
+ {uart} {
+ incr i
+ xml_dp1_attr_yes_no 5 [lindex $attrs $i]
+ }
+ {timer2} {
+ incr i
+ xml_dp1_attr_yes_no 6 [lindex $attrs $i]
+ }
+ {watchdog} {
+ incr i
+ xml_dp1_attr_yes_no 7 [lindex $attrs $i]
+ }
+ {eram} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 0xFFFF} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 8 $val
+ }
+ {dualdtpr} {
+ incr i
+ xml_dp1_attr_yes_no 9 [lindex $attrs $i]
+ }
+ {auxr} {
+ incr i
+ xml_dp1_attr_yes_no 10 [lindex $attrs $i]
+ }
+ {t2mod} {
+ incr i
+ xml_dp1_attr_yes_no 11 [lindex $attrs $i]
+ }
+ {port0} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 12 $val
+ }
+ {port1} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 13 $val
+ }
+ {port2} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 14 $val
+ }
+ {port3} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 15 $val
+ }
+ {port4} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {} && ![regexp {^[01]{8}$} $val]} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 16 $val
+ }
+ {pof} {
+ incr i
+ xml_dp1_attr_yes_no 17 [lindex $attrs $i]
+ }
+ {gf0} {
+ incr i
+ xml_dp1_attr_yes_no 20 [lindex $attrs $i]
+ }
+ {gf1} {
+ incr i
+ xml_dp1_attr_yes_no 21 [lindex $attrs $i]
+ }
+ {pd} {
+ incr i
+ xml_dp1_attr_yes_no 22 [lindex $attrs $i]
+ }
+ {idl} {
+ incr i
+ xml_dp1_attr_yes_no 23 [lindex $attrs $i]
+ }
+ {smod0} {
+ incr i
+ xml_dp1_attr_yes_no 24 [lindex $attrs $i]
+ }
+ {iph} {
+ incr i
+ xml_dp1_attr_yes_no 25 [lindex $attrs $i]
+ }
+ {acomparator} {
+ incr i
+ xml_dp1_attr_yes_no 26 [lindex $attrs $i]
+ }
+ {euart} {
+ incr i
+ xml_dp1_attr_yes_no 27 [lindex $attrs $i]
+ }
+ {clkreg} {
+ incr i
+ xml_dp1_attr_yes_no 28 [lindex $attrs $i]
+ }
+ {pwdex} {
+ incr i
+ xml_dp1_attr_yes_no 29 [lindex $attrs $i]
+ }
+ {spi} {
+ incr i
+ xml_dp1_attr_yes_no 30 [lindex $attrs $i]
+ }
+ {wdtcon} {
+ incr i
+ xml_dp1_attr_yes_no 31 [lindex $attrs $i]
+ }
+ {eeprom} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val]} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data 32 $val
+ }
+ {intelpe} {
+ incr i
+ xml_dp1_attr_yes_no 33 [lindex $attrs $i]
+ }
+ {pwm} {
+ incr i
+ xml_dp1_attr_yes_no 34 [lindex $attrs $i]
+ }
+ {x2reset} {
+ incr i
+ xml_dp1_attr_yes_no 35 [lindex $attrs $i]
+ }
+ {ckcon} {
+ incr i
+ xml_dp1_attr_yes_no 36 [lindex $attrs $i]
+ }
+ {auxr1gf3} {
+ incr i
+ xml_dp1_attr_yes_no 37 [lindex $attrs $i]
+ }
+ {ao} {
+ incr i
+ xml_dp1_attr_yes_no 38 [lindex $attrs $i]
+ }
+ {wdtprg} {
+ incr i
+ xml_dp1_attr_yes_no 39 [lindex $attrs $i]
+ }
+ {hddptr} {
+ incr i
+ xml_dp1_attr_yes_no 40 [lindex $attrs $i]
+ }
+ {auxrwdidle} {
+ incr i
+ xml_dp1_attr_yes_no 41 [lindex $attrs $i]
+ }
+ {auxrdisrto} {
+ incr i
+ xml_dp1_attr_yes_no 42 [lindex $attrs $i]
+ }
+ default {
+ incr i
+ }
+ }
+ }
+ }
+ {timers} {
+ set expected {more}
+ }
+ {more} {
+ set expected {bits}
+ }
+ {bits} {
+ if {$mcu_definition == $current_mcu} {
+ set take_data 1
+ }
+ set expected {writeonly}
+ }
+ {writeonly} {
+ if {$mcu_definition == $current_mcu} {
+ set take_data 1
+ }
+ set expected {sfr}
+ }
+ {sfr} {
+ if {$mcu_definition == $current_mcu} {
+ set take_data 1
+ }
+ set expected {mcu}
+ }
+ }
+ }
+
+ ## Auxiliary procedure for xml_data_parser1
+ # Invoke error if the given value was neither "yes" nor "no"
+ # @parm Int index - Index in list $definition_data
+ # @parm String value - Value to set in $definition_data
+ # @return void
+ proc xml_dp1_attr_yes_no {index value} {
+ variable definition_data ;# List: Values gained from $definition_file
+
+ if {$value != {yes} && $value != {no}} {
+ error "MCUs database file currupted"
+ }
+ lset definition_data $index $value
+ }
+
+ ## XML parser handler for procedure load_definition -- takes XML tags
+ # @parm String arg1 - name of the element
+ # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ proc xml_data_parser0_element {arg1 attrs} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable current_element ;# String: Current XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable vendors ;# List: Avaliable MCU vendors
+
+ if {$arg1 != $expected} {
+ error "Bad element `$arg1'"
+ }
+ set current_element $arg1
+ switch -- $arg1 {
+ {mcus} {
+ set expected {mcu}
+ }
+ {mcu} {
+ if {$mcu_definition != {}} {
+ foreach val $mcu_definition {
+ if {$val == {}} {
+ error "Incomplite definition for [lindex $mcu_definition 0]"
+ }
+ }
+ lappend definition_data $mcu_definition
+ }
+ set expected {timers}
+ set mcu_definition [list {} {} {} {} {} {} {} {} {} {} {} {}]
+ for {set i 0} {$i < [llength $attrs]} {incr i} {
+ switch -- [lindex $attrs $i] {
+ {name} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is alnum -strict $val]} {
+ error "MCU name must match ^[\w\d]+$"
+ }
+ lset mcu_definition 0 $val
+ }
+ {xdata} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {yes} && $val != {no}} {
+ error "Attribute XDATA must have value \"yes\" or \"no\""
+ }
+ lset mcu_definition 1 $val
+ }
+ {xcode} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {yes} && $val != {no}} {
+ error "Attribute XCODE must have value \"yes\" or \"no\""
+ }
+ lset mcu_definition 2 $val
+ }
+ {code} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 65536} {
+ error "CODE memory capacity must be an integer value \[0;65536\]"
+ }
+ lset mcu_definition 3 $val
+ }
+ {frequency} {
+ incr i
+ set val [lindex $attrs $i]
+ if {[string length $val] > 16 || ![string is print $val]} {
+ error "Attribute FREQUENCY must be printable string (max. 16 characters)"
+ }
+ lset mcu_definition 4 $val
+ }
+ {ram} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 256} {
+ error "RAM capacity must be an integer value \[0;256\]"
+ }
+ lset mcu_definition 5 $val
+ }
+ {portbits} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 256} {
+ error "Attribute PORTBITS must be an integer value \[0;256\]"
+ }
+ lset mcu_definition 6 $val
+ }
+ {uart} {
+ incr i
+ set val [lindex $attrs $i]
+ if {$val != {yes} && $val != {no}} {
+ error "Attribute UART must be eighter \"yes\" or \"no\""
+ }
+ lset mcu_definition 7 $val
+ }
+ {interrupts} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 99} {
+ error "Attribute INTERRUPTS must be an integer value \[0;99\]"
+ }
+ lset mcu_definition 8 $val
+ }
+ {voltage} {
+ incr i
+ set val [lindex $attrs $i]
+ if {[string length $val] > 11 || ![string is print $val]} {
+ error "Attribute VOLTAGE must be printable string (max. 11 characters)"
+ }
+ lset mcu_definition 9 $val
+ }
+ {eram} {
+ incr i
+ set val [lindex $attrs $i]
+ if {![string is digit -strict $val] || $val < 0 || $val > 65536} {
+ error "ERAM capacity must be an integer value \[0;65536\]"
+ }
+ lset mcu_definition 10 $val
+ }
+ {vendor} {
+ incr i
+ set val [lindex $attrs $i]
+ if {[lsearch $vendors $val] == -1} {
+ error "Undefined vendor \"$val\""
+ }
+ lset mcu_definition 11 $val
+ }
+ default {
+ incr i
+ }
+ }
+ }
+ }
+ {timers} {
+ set expected {more}
+ set take_data 1
+ }
+ {more} {
+ set expected {bits}
+ set take_data 1
+ }
+ {bits} {
+ set expected {writeonly}
+ set take_data 0
+ }
+ {writeonly} {
+ set expected {sfr}
+ set take_data 0
+ }
+ {sfr} {
+ set expected {mcu}
+ set take_data 0
+ }
+ }
+ }
+
+ ## XML parser handler for procedure load_definition -- takes data section
+ # @parm String arg1 - content of the element
+ # @return void
+ proc xml_data_parser0_data {arg1} {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable expected ;# String: Expected next XML element
+ variable current_element ;# String: Current XML element
+ variable take_data ;# Bool: Take element data on next parsing cycle
+ variable mcu_definition ;# List: Definition of MCU currently being parsed
+ variable vendors ;# List: Avaliable MCU vendors
+
+ if {!$take_data} {
+ return
+ }
+
+ set take_data 0
+
+ regsub -all {^\s+} $arg1 {} arg1
+ regsub -all {\s+$} $arg1 {} arg1
+ regsub -all -line {^\t+} $arg1 {} arg1
+
+ switch -- $current_element {
+ {timers} {
+ lappend mcu_definition $arg1
+ }
+ {more} {
+ lappend mcu_definition $arg1
+ }
+ }
+ }
+
+ ## Event handler for ListBox with list of processors
+ # Handles <<ListboxSelect>> -- Change contents of details frame
+ # @parm String - "noclear" == do not clear search EntryBox
+ # @return void
+ proc select_item args {
+ variable definition_data ;# List: Values gained from $definition_file
+ variable selected_mcu ;# List: Dialog return value {mcu_type xdata xcode}
+ variable listbox_widget ;# Widget: List box containing avaliable MCUs
+ variable value_lbl_uart ;# Widget: Label "UART:" - value
+ variable value_lbl_voltage ;# Widget: Label "Operating voltage:" - value
+ variable value_lbl_interrupts ;# Widget: Label "Interrupts:" - value
+ variable value_lbl_timers ;# Widget: Label "Timers:" - value
+ variable value_lbl_vendor ;# Widget: Label "Vendor" - value
+ variable more_details_text ;# Widget: TextWidget "More details:"
+ variable details_xdata_aval ;# Widget: Frame containing scale and spinbox for XDATA memory
+ variable details_xdata_note ;# Widget: Frame containing label "NOT AVALIABLE" for XDATA memory
+ variable details_xcode_aval ;# Widget: Frame containing scale and spinbox for XCODE memory
+ variable details_xcode_nota ;# Widget: Frame containing label "NOT AVALIABLE" for XCODE memory
+ variable name_label ;# Widget: Label containing name of selected MCU
+ variable image_label ;# Widget: Label with image for selected MCU
+ variable xcode_spinbox ;# Widget: SpinBox for XCODE memory
+ variable xcode_scale ;# Widget: Scale for XCODE memory
+ variable maximum_xcode ;# Int: Maximum external program memory (0xFFFF - internal)
+
+ # Get MCU definition for the selected processor
+ set mcu [lindex $definition_data \
+ [$listbox_widget index [$listbox_widget selection get]] \
+ ]
+ set mcu_name [lindex $mcu 0]
+ if {$selected_mcu == $mcu_name} {
+ return
+ }
+ set selected_mcu $mcu_name
+ set maximum_xcode [expr {0xFFFF - ([lindex $mcu 3] * 1024)}]
+
+ # Configure detail labels
+ $name_label configure -text $mcu_name
+ $value_lbl_vendor configure -text [lindex $mcu 11]
+ $value_lbl_uart configure -text [lindex $mcu 7]
+ $value_lbl_voltage configure -text [lindex $mcu 9]
+ $value_lbl_interrupts configure -text [lindex $mcu 8]
+ $value_lbl_timers configure -text [lindex $mcu 12]
+
+ # Configure details text
+ $more_details_text configure -state normal
+ $more_details_text delete 1.0 end
+ foreach line [split [lindex $mcu 13] "\n"] {
+ $more_details_text image create end -image ::ICONS::16::bookmark -padx 2 -pady 2
+ $more_details_text insert end $line
+ $more_details_text insert end "\n"
+ }
+ $more_details_text configure -state disabled
+
+ # Configure XDATA scale
+ if {[lindex $mcu 1] != {yes}} {
+ if {[winfo ismapped $details_xdata_aval]} {
+ pack forget $details_xdata_aval
+ }
+ pack $details_xdata_note -fill both -expand 1
+ } {
+ if {[winfo ismapped $details_xdata_note]} {
+ pack forget $details_xdata_note
+ }
+ pack $details_xdata_aval -fill both -expand 1 -padx 2
+ }
+ # Configure XCODE scale
+ if {[lindex $mcu 2] != {yes}} {
+ if {[winfo ismapped $details_xcode_aval]} {
+ pack forget $details_xcode_aval
+ }
+ pack $details_xcode_nota -fill both -expand 1
+ } {
+ $xcode_spinbox configure -to $maximum_xcode
+ $xcode_scale configure -to $maximum_xcode
+ if {[winfo ismapped $details_xcode_nota]} {
+ pack forget $details_xcode_nota
+ }
+ pack $details_xcode_aval -fill both -expand 1 -padx 2
+ }
+
+ # Clear search bar
+ if {$args != {noclear}} {
+ clear_search_bar
+ }
+
+ # Load image
+ set image [$image_label cget -image]
+ $image_label configure \
+ -fg {#888888} \
+ -text [mc "Loading image ..."] \
+ -image ::ICONS::16::exec
+ if {$image != {} && $image != {::ICONS::16::no} && $image != {::ICONS::16::exec}} {
+ image delete $image
+ }
+ update
+ if {[catch {
+ $image_label configure -text { } -image [image create photo \
+ -format png -file "${::LIB_DIRNAME}/../icons/mcu/$mcu_name.png"
+ ]
+ }]} {
+ $image_label configure \
+ -fg {#DD0000} \
+ -text [mc " Image not found"] \
+ -image ::ICONS::16::no
+ }
+ }
+
+ ## Set scrollbar for details text
+ # If frac0 == 0 && frac1 == 1 -> hide scrollbar
+ # @parm Float frac0 - Fraction of the topmost visible area
+ # @parm Float frac1 - Fraction of the bottommost visible area
+ # @return void
+ proc details_scrollbar_set {frac0 frac1} {
+ variable more_details_scrollbar ;# Widget: Scrollbar for $more_details_text
+ variable more_details_text ;# Widget: TextWidget "More details:"
+
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $more_details_scrollbar]} {
+ pack forget $more_details_scrollbar
+ }
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $more_details_scrollbar]} {
+ pack $more_details_scrollbar \
+ -side right -fill y \
+ -after $more_details_text
+ }
+ $more_details_scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Clear search entry box
+ # @return void
+ proc clear_search_bar {} {
+ variable search_bar ;# Widget: Search bar entry box
+ $search_bar delete 0 end
+ }
+
+ ## Search for the give string in the listbox of avaliable processors
+ # Primary purpose is validator for search entry box, it also
+ #+ ajusts search entry box background color
+ # @parm String string - Part of MCU name
+ # @return Bool - allways 1
+ proc search {string} {
+ variable search_bar ;# Widget: Search bar entry box
+ variable search_bar_clear ;# Widget: Search bar clear button
+ variable listbox_widget ;# Widget: List box containing avaliable MCUs
+ variable mcu_names ;# List: Avaliable processors
+
+ # Search for empty string -> abort
+ if {![string length $string]} {
+ $search_bar_clear configure -state disabled
+ $search_bar configure -style TEntry
+ return 1
+ }
+
+ $search_bar_clear configure -state normal
+
+ # Do a case-insensitive search
+ set string [string toupper $string]
+
+ set i 0
+ foreach mcu $mcu_names {
+ if {[string first $string [string toupper $mcu]] != -1} {
+ $search_bar configure -style StringFound.TEntry
+ set item [$listbox_widget items $i]
+ $listbox_widget selection set $item
+ $listbox_widget see $item
+ select_item noclear
+ return 1
+ }
+ incr i
+ }
+
+ $search_bar configure -style StringNotFound.TEntry
+ return 1
+ }
+
+ ## Close MCU selection dialog and discart its result
+ # @return void
+ proc cancel {} {
+ variable selected_mcu ;# List: Dialog return value {mcu_type xdata xcode}
+ set selected_mcu {}
+ close_window
+ }
+
+ ## Disable/Enable XDATA memory
+ # @return void
+ proc xdata_disena {} {
+ variable xdata_scale ;# Widget: Scale for XDATA memory
+ variable xdata_spinbox ;# Widget: Scale for XDATA memory
+
+ if {${::SelectMCU::xdata_ena}} {
+ $xdata_scale state !disabled
+ $xdata_spinbox configure -state normal
+ } {
+ $xdata_scale state disabled
+ $xdata_spinbox configure -state disabled
+ }
+ }
+
+ ## Disable/Enable XCODE memory
+ # @return void
+ proc xcode_disena {} {
+ variable xcode_spinbox ;# Widget: SpinBox for XCODE memory
+ variable xcode_scale ;# Widget: Scale for XCODE memory
+
+ if {${::SelectMCU::xcode_ena}} {
+ $xcode_scale state !disabled
+ $xcode_spinbox configure -state normal
+ } {
+ $xcode_scale state disabled
+ $xcode_spinbox configure -state disabled
+ }
+ }
+
+ ## Validate XDATA memory spinbox
+ # @parm String string - String to validate
+ # @return Bool - Validation result
+ proc validate_xdata {string} {
+ if {![string is digit $string]} {
+ return 0
+ }
+ if {$string == {}} {
+ return 1
+ }
+ if {$string < 0 || $string > 0xFFFF} {
+ return 0
+ }
+
+ return 1
+ }
+
+ ## Validate XCODE memory spinbox
+ # @parm String string - String to validate
+ # @return Bool - Validation result
+ proc validate_xcode {string} {
+ variable maximum_xcode ;# Int: Maximum external program memory (0xFFFF - internal)
+
+ if {![string is digit $string]} {
+ return 0
+ }
+ if {$string == {}} {
+ return 1
+ }
+ if {$string < 0 || $string > $maximum_xcode} {
+ return 0
+ }
+
+ return 1
+ }
+
+ ## This functionshould be changecmd for vendor comboBox
+ # @return void
+ proc change_vendor {} {
+ variable listbox_widget ;# Widget: List box containing avaliable MCUs
+
+ clear_search_bar
+ $listbox_widget delete [$listbox_widget items]
+ fill_gui
+ }
+}
diff --git a/lib/dialogs/tips.tcl b/lib/dialogs/tips.tcl
new file mode 100755
index 0000000..1c8b988
--- /dev/null
+++ b/lib/dialogs/tips.tcl
@@ -0,0 +1,375 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides facility to show tips on startup
+# * Tips are readed from file deindef in NS variable "tips_file"
+# * Format of definition file is XML and it supports mutiple languages
+# * Usage is simple: execute procedure "::Tips::show_tip_of_the_day_win"
+# * It requires NS ConfigDialogs (see ${::GLOBAL_CONFIG(tips)})
+# --------------------------------------------------------------------------
+
+namespace eval Tips {
+ variable tip_of_the_day_win ;# ID of window "Tip of the day"
+ variable tip_of_the_day_text ;# ID of text widget in "Tip of the day"
+ variable tip_of_the_day_show_again ;# Bool: Show "Tip of the day"
+
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips avaliable
+ variable current_tip ;# Number of the currently displayed tip
+ variable expected ;# Expeceted element
+ variable take_data ;# Bool: Append data section to $tips_data
+ # File containing tips data
+ variable tips_file "${::LIB_DIRNAME}/../data/tips.xml"
+
+ ## Invoke dialog "Tip on startup"
+ # @return void
+ proc show_tip_of_the_day_win {} {
+ variable tip_of_the_day_win ;# ID of window "Tip of the day"
+ variable tip_of_the_day_text ;# ID of text widget in "Tip of the day"
+ variable tip_of_the_day_show_again ;# Bool: Show "Tip of the day"
+ variable number_of_tips ;# Number of tips avaliable
+ variable tip_of_the_day_show_again ;# Bool: Show "Tip of the day"
+
+ # Set value of checkbox "Show again"
+ set tip_of_the_day_show_again ${::GLOBAL_CONFIG(tips)}
+ # Load tips definition file
+ load_tips_file
+
+ # Create toplevel window
+ set win [toplevel .tip_of_the_day -class {Tip of the day} -bg {#EEEEEE}]
+ set tip_of_the_day_win $win
+
+ # Create window header
+ pack [label $win.header \
+ -text [mc "Did you know ... "] \
+ -font [font create \
+ -family {times} \
+ -size -25 \
+ -weight bold \
+ ] \
+ -compound right \
+ -image ::ICONS::32::help \
+ ] -pady 5
+
+ # Create middle frame (text windget and scrollbar)
+ set middle_frame [frame $win.middle_frame]
+ set text [text $middle_frame.text \
+ -width 0 -height 0 -bg white \
+ -wrap word \
+ -yscrollcommand "$middle_frame.scrollbar set" \
+ -font [font create \
+ -family {helvetica} \
+ -size -17 \
+ -weight normal \
+ ] \
+ ]
+ pack $text -side left -fill both -expand 1
+ pack [ttk::scrollbar $middle_frame.scrollbar \
+ -orient vertical \
+ -command [list $text yview] \
+ ] -side left -fill y -after $text
+ set tip_of_the_day_text $text
+
+ ## Create bottom frame
+ set bottom_frame [frame $win.bottom_frame]
+ # - CheckButton "Show tips on startup"
+ pack [checkbutton $bottom_frame.chbutton \
+ -variable ::Tips::tip_of_the_day_show_again \
+ -command {::Tips::tip_otd_show_again} \
+ -text [mc "Show tips on startup"] \
+ ] -side left -anchor e
+ # - Button "Close"
+ pack [ttk::button $bottom_frame.close_but \
+ -compound left \
+ -text [mc "Close"] \
+ -image ::ICONS::16::button_cancel \
+ -command {::Tips::tip_otd_CLOSE} \
+ -width 8 \
+ ] -side right -anchor w
+ # - Button "Next"
+ pack [ttk::button $bottom_frame.next_but \
+ -compound left \
+ -text [mc "Next"] \
+ -image ::ICONS::16::right \
+ -command {::Tips::tip_otd_NEXT} \
+ -width 8 \
+ ] -side right -anchor w
+ # - Button "Previous"
+ pack [ttk::button $bottom_frame.prev_but \
+ -compound left \
+ -text [mc "Previous"] \
+ -image ::ICONS::16::left \
+ -command {::Tips::tip_otd_PREV} \
+ -width 8 \
+ ] -side right -anchor w
+
+ # Pack window frames
+ pack $middle_frame -side top -fill both -expand 1 -padx 10 -pady 5
+ pack $bottom_frame -side bottom -fill x -after $middle_frame -padx 10 -pady 5
+
+ # Configure text tags
+ $text tag configure tag_bold -font [font create \
+ -family {helvetica} \
+ -size -17 \
+ -weight bold \
+ ]
+
+ # Determinate random number of tip to show
+ expr {srand([clock seconds])}
+ display_tip [expr {int(rand() * $number_of_tips)}]
+
+ # Configure dialog window
+ wm iconphoto $win ::ICONS::16::info
+ wm title $win [mc "Tip of the day - MCU 8051 IDE"]
+ wm minsize $win 520 250
+ wm protocol $win WM_DELETE_WINDOW {
+ ::Tips::tip_otd_CLOSE
+ }
+ wm transient $win .
+ raise $win
+ catch {
+ grab $win
+ }
+ }
+
+ ## Load definition of tips
+ # @return void
+ proc load_tips_file {} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips avaliable
+ variable tips_file ;# File containing tips data
+ variable expected ;# Expeceted element
+ variable take_data ;# Bool: Append data section to $tips_data
+
+ # Initialize NS variables
+ set take_data 0
+ set number_of_tips 0
+ set expected {tips}
+ set tips_data {}
+
+ # Open file
+ if {[catch {
+ set file [open $tips_file {r}]
+ }]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title "tips.xml" \
+ -message [mc "Unable to open file containing tips,\nplease check your installation"]
+ return
+ }
+
+ # Create XML parser
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand ::Tips::xml_data_parser_element \
+ -characterdatacommand ::Tips::xml_data_parser_data \
+ ]
+
+ # Start XML parser
+ if {[catch {
+ $parser parse [read $file]
+ } result]} {
+ set number_of_tips 0
+ set tips_data {}
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unable to parse tips.xml"] \
+ -message [mc "File tips.xml is corrupted,\nplease check your installation"]
+ puts stderr $result
+ return
+ }
+
+ # Close file and free parser
+ close $file
+ $parser free
+ }
+
+ ## Universal parser handler - handles XML tags and data
+ # @parm String arg1 - content of the element
+ # @return void
+ proc xml_data_parser_data {arg1} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips avaliable
+ variable current_tip ;# Number of the currently displayed tip
+ variable expected ;# Expeceted element
+ variable take_data ;# Bool: Append data section to $tips_data
+
+ if {!$take_data} {
+ return
+ }
+
+ set take_data 0
+ incr number_of_tips
+
+ regsub -all {^\s+} $arg1 {} arg1
+ regsub -all {\s+$} $arg1 {} arg1
+ lappend tips_data [regsub -all -line {^\t+} $arg1 {}]
+ }
+
+ ## XML parser handler - handles XML tags
+ # @parm String arg1 - name of the element
+ # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ proc xml_data_parser_element {arg1 attrs} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips avaliable
+ variable current_tip ;# Number of the currently displayed tip
+ variable expected ;# Expeceted element
+ variable take_data ;# Bool: Append data section to $tips_data
+
+ if {$arg1 != $expected} {
+ error "Bad element `$arg1'"
+ }
+ if {$arg1 == {tips}} {
+ set expected {tip}
+ }
+
+ # Iterate over element attributes
+ for {set i 0} {$i < [llength $attrs]} {incr i} {
+ if {[lindex $attrs $i] != {lang}} {
+ incr i
+ continue
+ }
+ incr i
+
+ ## Take data if ...
+ # No translation has been loaded and current text is in English
+ if {!${::TRANSLATION_LOADED} || [lindex $attrs $i] == {en}} {
+ set take_data 1
+ # Or if some translation has been loaded and it conforms with the text
+ } elseif {[lindex $attrs $i] == ${::GLOBAL_CONFIG(language)}} {
+ set take_data 1
+ }
+ }
+ }
+
+ ## Close dialog
+ # @return void
+ proc tip_otd_CLOSE {} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips avaliable
+ variable current_tip ;# Number of the currently displayed tip
+ variable tip_of_the_day_win ;# ID of window "Tip of the day"
+
+ # Remove dialog
+ grab release $tip_of_the_day_win
+ destroy $tip_of_the_day_win
+
+ # Free dialog resources
+ set tips_data {}
+ set number_of_tips {}
+ set current_tip {}
+ }
+
+ ## Display tip with the given number in the window
+ # @parm Int tip_number - number of the tip to show (can overlap allowed range)
+ # @return void
+ proc display_tip {tip_number} {
+ variable tips_data ;# List containing tips data
+ variable number_of_tips ;# Number of tips avaliable
+ variable current_tip ;# Number of the currently displayed tip
+ variable tip_of_the_day_text ;# ID of text widget in "Tip of the day"
+
+ set current_tip $tip_number
+
+ # Clear text widget
+ $tip_of_the_day_text configure -state normal
+ $tip_of_the_day_text delete 1.0 end
+
+ # Validate tip number
+ if {!$number_of_tips} {
+ $tip_of_the_day_text configure -state disabled
+ return
+ }
+ if {$tip_number >= $number_of_tips} {
+ set current_tip $number_of_tips
+ incr current_tip -1
+ }
+
+ # Create map of bold font tags
+ set bold_tag_map {}
+ set content [lindex $tips_data $current_tip]
+ while 1 {
+ set tag_pair {}
+
+ set idx [string first {<b>} $content]
+ if {$idx == -1} {break}
+ regsub {<b>} $content {} content
+ lappend tag_pair $idx
+
+ set idx [string first {</b>} $content]
+ if {$idx == -1} {break}
+ regsub {</b>} $content {} content
+ lappend tag_pair $idx
+
+ lappend bold_tag_map $tag_pair
+ }
+
+ # Fill text widget
+ set start [$tip_of_the_day_text index insert]
+ $tip_of_the_day_text insert end $content
+ foreach pair $bold_tag_map {
+ $tip_of_the_day_text tag add tag_bold $start+[lindex $pair 0]c $start+[lindex $pair 1]c
+ }
+ $tip_of_the_day_text configure -state disabled
+ }
+
+ ## Show next tip
+ # @return void
+ proc tip_otd_NEXT {} {
+ variable number_of_tips ;# Number of tips avaliable
+ variable current_tip ;# Number of the currently displayed tip
+
+ incr current_tip
+ if {$current_tip >= $number_of_tips} {
+ set current_tip 0
+ }
+ display_tip $current_tip
+ }
+
+ ## Show previous tip
+ # @return void
+ proc tip_otd_PREV {} {
+ variable number_of_tips ;# Number of tips avaliable
+ variable current_tip ;# Number of the currently displayed tip
+
+ incr current_tip -1
+ if {$current_tip < 0} {
+ set current_tip [expr {$number_of_tips - 1}]
+ }
+ display_tip $current_tip
+ }
+
+ ## Adjust base configuration file to variable "tip_of_the_day_show_again"
+ # @return void
+ proc tip_otd_show_again {} {
+ variable tip_of_the_day_show_again ;# Bool: Show "Tip of the day"
+
+ ::configDialogs::global::set_variable tips $tip_of_the_day_show_again
+ }
+}
diff --git a/lib/editor/ASMsyntaxhighlight.tcl b/lib/editor/ASMsyntaxhighlight.tcl
new file mode 100755
index 0000000..fe364d5
--- /dev/null
+++ b/lib/editor/ASMsyntaxhighlight.tcl
@@ -0,0 +1,1675 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements syntax highlighting interface for assembly language
+# --------------------------------------------------------------------------
+
+namespace eval ASMsyntaxHighlight {
+ ## Highlight colors and font styles - highlight tags definition
+ # {
+ # {tag_name ?foreground? ?overstrike? ?italic? ?bold?}
+ # }
+ variable hightlight_tags {
+ {tag_char #880066 0 0 0}
+ {tag_hex #8800BB 0 0 0}
+ {tag_oct #880000 0 0 0}
+ {tag_dec #0055AA 0 0 0}
+ {tag_bin #333355 0 0 0}
+ {tag_constant #55AA00 0 0 0}
+ {tag_unknown_base #882222 0 0 0}
+
+ {tag_string #888800 0 0 0}
+ {tag_comment #888888 0 1 0}
+ {tag_control #FF0000 0 0 1}
+ {tag_symbol #AA00FF 0 0 1}
+ {tag_oper_sep #DD8800 0 0 1}
+ {tag_directive #8888FF 0 0 1}
+ {tag_label #885500 0 0 0}
+ {tag_instruction #0000FF 0 0 1}
+ {tag_sfr #0000DD 0 0 0}
+ {tag_indirect #DD0000 0 0 0}
+
+ {tag_imm_char #DD00AA 0 0 0}
+ {tag_imm_hex #AA00DD 0 0 0}
+ {tag_imm_oct #AA0000 0 0 0}
+ {tag_imm_dec #0088DD 0 0 0}
+ {tag_imm_bin #5555AA 0 0 0}
+ {tag_imm_constant #EFBC2B 0 0 0}
+ {tag_imm_unknown #AA3333 0 0 0}
+
+ {tag_macro #CC00DD 0 0 1}
+ }
+ # Instructions keywords
+ variable instructions {
+ ACALL ADD ADDC AJMP ANL CJNE CLR CPL DA DEC DIV DJNZ INC JB JBC JC JMP JNB JNZ SJMP JNC CALL
+ JZ LCALL LJMP MOV MOVC MOVX MUL NOP ORL POP PUSH RET RETI RL RLC RR RRC SETB SUBB SWAP XCH XCHD XRL
+ }
+ # SFR bits
+ variable spec_bits {
+ C Z P OV RS0 RS1 F0 AC CY PX0 PT0 PX1 PT1 PS RXD TXD INT0 INT1 T0 T1 WR RD
+ EX0 ET0 EX1 ET1 ES EA RI TI RB8 TB8 REN SM2 SM1 SM0 IT0 IE0 IT1 IE1 TR0 TF0 TR1 TF1
+ TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2 EC PC ET2 PT2 FE
+ CR CCF4 CCF3 CCF2 CCF1 CCF0 PPCL PT2L PSL PT1L PX1L PT0L PX0L
+ }
+ # SFR registers and bits
+ variable spec_registers [concat {
+ A ACC B AB P0 P1 P2 P3 TL0 TL1 TH0 TH1 TMOD TCON SCON DPL PCON PSW SP DPH SBUF IE IP
+ R0 R1 R2 R3 R4 R5 R6 R7 DPTR DP0L DP0H
+ T2CON T2MOD RCAP2L RCAP2H TL2 TH2 AUXR1 WDTRST AUXR P4 DPH DPL DP1H DP1L
+ WDTCON EECON CLKREG ACSR IPH SADDR SADEN SPCR SPSR SPDR CKCON WDTPRG
+
+ CH CCAP0H CCAP1H CCAPL2H CCAPL3H CCAPL4H ADCLK ADCON ADDL ADDH ADCF
+ CL CCAP0L CCAP1L CCAPL2L CCAPL3L CCAPL4L P1M2 P3M2 P4M2
+ P1M1 P3M1 P4M1 SPCON SPSTA SPDAT CMOD CCAPM0 CCAPM1 CCAPM2 CCAPM3 CCAPM4
+ IPL1 IPH1 IPH0 BRL BDRCON KBLS KBE KBF WDTRST WDTPRG CKRL CKCON0 IPL0 CCON
+ } $spec_bits]
+
+ ## COMPILER DIRECTIVES
+ # directives without arguments
+ variable directive_type0 {
+ ENDIF ENDM END ELSE EXITM LIST NOLIST
+ }
+
+ # directives with argument(s) but without any label
+ variable directive_type1 {
+ DSEG ISEG BSEG XSEG CSEG SKIP NAME
+ }
+ # directives for constants definitions
+ variable directive_type2 {
+ EQU BIT SET CODE DATA IDATA XDATA MACRO FLAG
+ }
+ # directives with argument and optional label
+ variable directive_type3 {
+ DS DW DB DBIT INCLUDE ORG IF USING BYTE NAME REPT TIMES
+ ELSEIF IFN ELSEIFN IFDEF ELSEIFDEF IFNDEF ELSEIFNDEF IFB ELSEIFB IFNB ELSEIFNB
+ }
+ # all known directives
+ variable all_directives [concat $directive_type0 $directive_type1 $directive_type2 $directive_type3]
+ # word operators
+ variable expr_instructions {
+ MOD SHR SHL NOT AND OR LE XOR EQ NE GT GE LT HIGH LOW
+ }
+ # symbol operators
+ variable expr_symbols {
+ = + - * / > < %
+ }
+
+ # control sequencies without any argument
+ variable controls_type0 {
+ NOLIST NOMOD NOOBJECT NOPAGING NOPRINT
+ NOSYMBOLS EJECT LIST PAGING SYMBOLS NOMACROSFIRST
+
+ NOXR NOXREF XR XREF NOSB SB RESTORE RS SA SAVE PHILIPS
+ NOPI PI NOTABS NOMOD51 NOBUILTIN NOMO MO MOD51 NOMACRO
+ NOMR LI NOLI GENONLY GO NOGEN NOGE GEN GE EJ NODB
+ NODEBUG DB DEBUG CONDONLY NOCOND COND
+ }
+ # control sequencies with exactly 1 argument
+ variable controls_type1 {
+ PAGEWIDTH PAGELENGTH PRINT TITLE OBJECT DATE INCLUDE
+
+ TT PW PL MR MACRO INC WARNING ERROR DA
+ }
+ # all known control sequencies
+ variable all_controls [concat $controls_type0 $controls_type1]
+ # all known control sequencies with preceeding dolar character
+ variable all_controls__with_dolar
+ # all known directives and control sequencies
+ variable all_directives_and_controls [concat $all_directives $all_controls]
+ # list of all reserved keywords
+ variable keyword_lists [list \
+ $instructions \
+ $directive_type0 \
+ $directive_type1 \
+ $directive_type2 \
+ $directive_type3 \
+ ]
+
+ variable inline_asm ;# Is inline assembler
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable lineStart ;# Index of line start
+ variable lineEnd ;# Index of line end
+ variable data ;# Content of the line
+ variable data_backup ;# Original content of the line
+ variable last_index ;# Last parse index
+ variable last_index_backup ;# Auxiliary variable (some index)
+
+ variable seg_0 ;# 1st field of the line
+ variable seg_1 ;# 2nd field of the line
+ variable seg_2 ;# 3rd field of the line
+ variable seg_0_start ;# Start index of seg_0
+ variable seg_1_start ;# Start index of seg_1
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_0_end ;# End index of seg_0
+ variable seg_1_end ;# End index of seg_1
+ variable seg_2_end ;# End index of seg_2
+
+ variable operands_count 0 ;# Number of operands at the line
+ variable operand ;# Data of the current operand
+ variable opr_end ;# End index of the current operand
+ variable opr_start ;# Start index of the current operand
+
+ ## List of operand types on the line (eg. '{D # DPTR}')
+ # Possible values are:
+ # - '#' : Immediate addressing
+ # - @$x : Indirect addressing (one of {@R0 @R1 @DPTR @A+DPTR @A+PC})
+ # - '/' : Inverted bit
+ # - 'D' : Direct addressing
+ # - $sfr : One of {R0 R1 R2 R3 R4 R5 R6 R7 DPTR A AB C}
+ variable opr_types
+
+ variable validation_L0 1 ;# Bool: Basic validation enabled
+ variable validation_L1 1 ;# Bool: Advancet validation enabled
+
+ ## Define highlighting text tags in the given text widget
+ # @parm Widget - ID of the target text widget
+ # @parm Int - font size
+ # @parm String - font family
+ # @parm List = default - Highlighting tags definition
+ # @return void
+ proc create_tags args {
+ variable hightlight_tags ;# Highlight tags definition
+
+ # Handle arguments
+ set text_widget [lindex $args 0] ;# text widget
+ set fontSize [lindex $args 1] ;# font size
+ set fontFamily [lindex $args 2] ;# font family
+ if {[llength $args] > 3} { ;# highlighting definition
+ set hightlight [lindex $args 3]
+ } {
+ set hightlight $hightlight_tags
+ }
+
+ # Iterate over highlighting tags definition
+ foreach item $hightlight {
+ # Create array of tag attributes
+ for {set i 0} {$i < 5} {incr i} {
+ set tag($i) [lindex $item $i]
+ }
+
+ # Foreground color
+ if {$tag(1) == {}} {
+ set tag(1) black
+ }
+ # Fonr slant
+ if {$tag(3) == 1} {
+ set tag(3) italic
+ } {
+ set tag(3) roman
+ }
+ # Font weight
+ if {$tag(4) == 1} {
+ set tag(4) bold
+ } {
+ set tag(4) normal
+ }
+
+ # Tag "tag_constant" is copied as "tag_constant_def"
+ #+ and "tag_macro" as "tag_macro_def"
+ if {$tag(0) == {tag_constant}} {
+ lappend tag(0) {tag_constant_def}
+ } elseif {$tag(0) == {tag_macro}} {
+ lappend tag(0) {tag_macro_def}
+ }
+
+ # Create the tag in the target text widget
+ foreach tag_name $tag(0) {
+ $text_widget tag configure $tag_name \
+ -foreground $tag(1) \
+ -font [font create \
+ -overstrike $tag(2) \
+ -slant $tag(3) \
+ -weight $tag(4) \
+ -size -$fontSize \
+ -family $fontFamily \
+ ]
+ }
+ }
+ # Add tag error
+ $text_widget tag configure tag_error -underline 1
+ }
+
+ ## Perform syntax highlight on the given line in the given widget
+ # @parm Widget Editor - Text widget
+ # @parm Int LineNumber - Number of line to highlight
+ # @parm Bool inline_asm - Inline assembler
+ # @parm Int boundary_0 = 0 - Start index
+ # @parm Int boundary_1 = end - End index
+ # @return Bool - result
+ proc highlight args {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable lineStart ;# Index of line start
+ variable lineEnd ;# Index of line end
+ variable inline_asm ;# Is inline assembler
+
+ variable seg_0 {} ;# 1st field of the line
+ variable seg_1 {} ;# 2nd field of the line
+ variable seg_2 {} ;# 3rd field of the line
+ variable seg_0_start ;# Start index of seg_0
+ variable seg_1_start ;# Start index of seg_1
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_0_end ;# End index of seg_0
+ variable seg_1_end ;# End index of seg_1
+ variable seg_2_end ;# End index of seg_2
+
+ variable last_index ;# Last parse index
+ variable data ;# Content of the line
+ variable operands_count ;# Number of operand in the line
+ variable validation_L0 ;# Bool: Basic validation enabled
+
+ # Parse input arguments
+ set editor [lindex $args 0]
+ set lineNumber [lindex $args 1]
+ set inline_asm [lindex $args 2]
+ set lineStart [lindex $args 3]
+ set lineEnd [lindex $args 4]
+ if {$inline_asm == {}} {
+ set inline_asm 0
+ }
+ if {$lineStart == {}} {
+ set lineStart $lineNumber.0
+ } {
+ set lineStart $lineNumber.$lineStart
+ }
+ if {$lineEnd == {}} {
+ set lineEnd [$editor index "$lineStart lineend"]
+ } {
+ set lineEnd $lineNumber.$lineEnd
+ }
+ if {[lindex $args 3] != {}} {
+ set start_offset [lindex $args 3]
+ } {
+ set start_offset 0
+ }
+
+ set data [$editor get $lineStart $lineEnd]
+ set operands_count 0
+ set opr_types {}
+
+ if {$inline_asm} {
+ delete_tags
+ }
+
+ # check if the line is not empty
+ if {[regexp {^\s*$} $data]} {
+ return 0
+ }
+ set line_length [string length $data]
+ if {$line_length == 0} {
+ return 0
+ }
+
+ # determinate comment field and highlight it (the last field)
+ set comment_start {}
+ if {[regexp {;} $data]} {
+
+ # remove 'string' from the line
+ set comment_data [hide_strings $data]
+
+ if {[regexp {;.*$} $comment_data comment_start]} {
+
+ set comment_start [string length $comment_start]
+ set comment_start [expr {$line_length - $comment_start}]
+
+ # remove comment and trailing space from the line
+ if {$comment_start == 0} {
+ set data {}
+ delete_tags
+ } {
+ set data [string range $data 0 [expr {$comment_start - 1}]]
+ regsub {\s+$} $data {} data
+ }
+
+ incr comment_start $start_offset
+ }
+ }
+
+ # Handle line containing only comment
+ if {![string length $data]} {
+ if {!$inline_asm} {
+ delete_tags
+ }
+ $editor tag add tag_comment $lineNumber.$comment_start $lineEnd
+ return 1
+ }
+
+ # Determinate 1st segment of the line
+ regexp {^\s*[^\s:\(]+:?} $data seg_0
+ set seg_0_end [string length $seg_0]
+ regsub {^\s+} $seg_0 {} seg_0
+
+ set seg_0_start [string length $seg_0]
+ set seg_0_start [expr {$seg_0_end - $seg_0_start}]
+
+ set data [string replace $data 0 [expr {$seg_0_end - 1}]]
+ incr seg_0_end $start_offset
+ incr seg_0_start $start_offset
+ set last_index $seg_0_end
+
+ #
+ # SYNTAX HIGHLIGHT
+ #
+
+ # delete existing tags within the line
+ if {!$inline_asm} {
+ delete_tags
+ }
+
+ # highlight comment
+ if {$comment_start != {}} {
+ $editor tag add tag_comment $lineNumber.$comment_start $lineEnd
+ }
+ # highlight 1st and 2nd field
+ set seg_0_info [parse_segment $seg_0_start $seg_0_end $seg_0]
+
+ # Conditional parsing with validation
+ switch -- [lindex $seg_0_info 0] {
+ {control_0} {}
+ {control_1} {}
+ {control_incorrect} {}
+ {label} {
+ determinate_segment_1
+ set seg_1_info [parse_segment $seg_1_start $seg_1_end $seg_1]
+ switch -- [lindex $seg_1_info 0] {
+ {control_0} {
+ determinate_segment_2
+ put_error_on_segment 2
+ }
+ {control_1} {
+ determinate_segment_2
+ put_error_on_segment 2
+ }
+ {label} {
+ put_error_on_segment 1
+ }
+ {instruction} {
+ determinate_segment_2
+ parse_operands
+ }
+ {directive_3} {
+ determinate_segment_2
+ if {![string length $seg_2]} {
+ put_error_on_segment 1
+ }
+
+ set seg_1 [string tolower $seg_1]
+ if {$seg_1 == {db} || $seg_1 == {.db} || $seg_1 == {byte} || $seg_1 == {.byte}} {
+ parse_operands
+ } elseif {$seg_1 == {include} || $seg_1 == {.include}} {
+ $editor tag add tag_string \
+ $lineNumber.$seg_2_start \
+ [list $lineNumber.0 lineend]
+ } {
+ parse_expressions
+ }
+ }
+ {directive_2} {
+ put_error_on_segment 0
+ }
+ {directive_1} {}
+ {directive_0} {
+ determinate_segment_2
+ if {[string length $seg_2]} {
+ incr seg_2_end
+ put_error_on_segment 2
+ }
+ }
+ {unknown} {
+ $editor tag add tag_macro \
+ $lineNumber.$seg_1_start $lineNumber.$seg_1_end
+ if {
+ $validation_L0 &&
+ ([regexp {^\d} $seg_1] || ![regexp {^\w+$} $seg_1])
+ } {
+ put_error_on_segment 1
+ }
+ determinate_segment_2
+ parse_operands
+ }
+ default {
+ put_error_on_segment 1
+ }
+ }
+ }
+ {instruction} {
+ determinate_segment_2
+ parse_operands
+ }
+ {directive_3} {
+ determinate_segment_2
+ if {![string length $seg_2]} {
+ put_error_on_segment 0
+ }
+
+ set seg_0 [string tolower $seg_0]
+ if {$seg_0 == {db} || $seg_0 == {.db} || $seg_0 == {byte} || $seg_0 == {.byte}} {
+ parse_operands
+ } elseif {$seg_0 == {include} || $seg_0 == {.include}} {
+ $editor tag add tag_string \
+ $lineNumber.$seg_2_start \
+ [list $lineNumber.0 lineend]
+ } {
+ parse_expressions
+ }
+ }
+ {directive_2} {
+ determinate_segment_2
+ parse_expressions
+ put_error_on_segment 0
+ }
+ {directive_1} {
+ determinate_segment_2
+ parse_expressions
+ }
+ {directive_0} {
+ determinate_segment_1
+ put_error_on_segment 1
+ determinate_segment_2
+ put_error_on_segment 2
+ }
+ {unknown} {
+ determinate_segment_1
+ set seg_1_info [parse_segment $seg_1_start $seg_1_end $seg_1]
+ switch -- [lindex $seg_1_info 0] {
+ {control_0} {
+ determinate_segment_2
+ put_error_on_segment 2
+ }
+ {control_1} {
+ determinate_segment_2
+ put_error_on_segment 2
+ }
+ {label} {
+ put_error_on_segment 0
+ }
+ {instruction} {
+ put_error_on_segment 0
+ determinate_segment_2
+ parse_operands
+ }
+ {directive_3} {
+ put_error_on_segment 0
+ determinate_segment_2
+ set seg_1 [string tolower $seg_1]
+ if {$seg_1 == {db} || $seg_1 == {.db} || $seg_1 == {byte} || $seg_1 == {.byte}} {
+ parse_operands
+ } elseif {$seg_1 == {include} || $seg_1 == {.include}} {
+ $editor tag add tag_string \
+ $lineNumber.$seg_2_start \
+ [list $lineNumber.0 lineend]
+ } {
+ parse_expressions
+ }
+ }
+ {directive_2} {
+ if {
+ $validation_L0 &&
+ ([regexp {^\d} $seg_0] || ![regexp {^\w+$} $seg_0])
+ } {
+ put_error_on_segment 0
+ }
+
+ set sg [string tolower $seg_1]
+ if {$sg == {macro} || $sg == {.macro}} {
+ $editor tag add tag_macro_def \
+ $lineNumber.$seg_0_start \
+ $lineNumber.$seg_0_end
+ determinate_segment_2
+ parse_arguments
+ } {
+ $editor tag add tag_constant_def \
+ $lineNumber.$seg_0_start \
+ $lineNumber.$seg_0_end
+
+ determinate_segment_2
+ parse_expressions
+ }
+ }
+ {directive_1} {
+ put_error_on_segment 0
+ determinate_segment_2
+ parse_expressions
+ }
+ {directive_0} {
+ put_error_on_segment 0
+ determinate_segment_2
+ put_error_on_segment 2
+ }
+ {unknown} {
+ $editor tag add tag_macro $lineNumber.$seg_0_start $lineNumber.$seg_0_end
+ if {
+ $validation_L0 &&
+ ([regexp {^\d} $seg_0] || ![regexp {^\w+$} $seg_0])
+ } {
+ put_error_on_segment 0
+ }
+ determinate_segment_1_take_back
+ determinate_segment_2
+ parse_operands
+ }
+ default {
+ $editor tag add tag_macro $lineNumber.$seg_0_start $lineNumber.$seg_0_end
+ if {
+ $validation_L0 &&
+ ([regexp {^\d} $seg_0] || ![regexp {^\w+$} $seg_0])
+ } {
+ put_error_on_segment 0
+ }
+ }
+ }
+ }
+ default {}
+ }
+
+ return 1
+ }
+
+ ## Remove previously defined syntax highlighting tags
+ # @return void
+ proc delete_tags {} {
+ variable editor ;# ID of the text widget
+ variable hightlight_tags ;# Highlight tags definition
+ variable lineStart ;# Index of line start
+ variable lineEnd ;# Index of line end
+
+ set lineStart_truestart [$editor index [list $lineStart linestart]]
+
+ # Remove tag error, tag_constant_def and tag_macro_def
+ foreach tag {tag_error tag_constant_def tag_macro_def} {
+ $editor tag remove $tag $lineStart_truestart $lineStart_truestart+1l
+ }
+
+ # Remove tags acording to pattern
+ foreach tag $hightlight_tags {
+ $editor tag remove [lindex $tag 0] $lineStart_truestart $lineEnd
+ }
+ }
+
+ ## Take back extraction of segment 1
+ # @return void
+ proc determinate_segment_1_take_back {} {
+ variable data ;# Content of the line
+ variable data_backup ;# Original content of the line
+ variable last_index ;# Last parse index
+ variable last_index_backup ;# Auxiliary variable (some index)
+
+ set data $data_backup
+ set last_index $last_index_backup
+ }
+
+ ## Extract segment 1 from the line
+ # @return void
+ proc determinate_segment_1 {} {
+ variable seg_1 ;# 2nd field of the line
+ variable seg_1_start ;# Start index of seg_1
+ variable seg_1_end ;# End index of seg_1
+ variable last_index ;# Last parse index
+ variable data ;# Content of the line
+ variable data_backup ;# Original content of the line
+ variable last_index_backup ;# Auxiliary variable (some index)
+
+ # Line is empty
+ if {![regexp {^\s*[^\s\(]+} $data seg_1]} {
+ set seg_1 {}
+ set seg_1_end $last_index
+ set seg_1_start $last_index
+
+ # Line is not empty
+ } {
+ set data_backup $data
+ set last_index_backup $last_index
+
+ set seg_1_end [string length $seg_1]
+ set data [string replace $data 0 [expr {$seg_1_end - 1}]]
+ incr seg_1_end $last_index
+
+ regsub {^\s+} $seg_1 {} seg_1
+ set seg_1_start [string length $seg_1]
+ set seg_1_start [expr {$seg_1_end - $seg_1_start}]
+
+ set last_index $seg_1_end
+ }
+ }
+
+ ## Extract segment 2 from the line
+ # @return void
+ proc determinate_segment_2 {} {
+ variable seg_2 ;# 3rd field of the line
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_2_end ;# End index of seg_2
+ variable last_index ;# Last parse index
+ variable data ;# Content of the line
+
+ # determinate the last segment of the line
+ set seg_2_start $last_index
+ if {[regexp {^\s+} $data space]} {
+ incr seg_2_start [string length $space]
+ }
+ regsub {^\s+} $data {} seg_2
+ regsub {\s+$} $seg_2 {} seg_2
+ set seg_2_end [string length $seg_2]
+ incr seg_2_end $last_index
+ set data {}
+ }
+
+ ## Shorthand for 'parse_expression $seg_2 $seg_2_start $seg_2_end'
+ # @return void
+ proc parse_expressions {} {
+ variable seg_2 ;# 3rd field of the line
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_2_end ;# End index of seg_2
+
+ parse_expression $seg_2 $seg_2_start $seg_2_end
+ }
+
+ ## Parse given segment, highlight it and determinate its type
+ # @parm Int start - start column
+ # @parm int end - end column
+ # @parm String segment_data - content of segment to parse
+ # @return List - {segment_type expression_length} or {segment_type {}} or {{} {}}
+ proc parse_segment {start end segment_data} {
+ variable controls_type0 ;# control sequencies without any argument
+ variable controls_type1 ;# control sequencies with exactly 1 argument
+
+ variable keyword_lists ;# list of all reserved keywords
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable lineStart ;# Index of line start
+ variable lineEnd ;# Index of line end
+ variable data ;# Content of the line
+ variable validation_L0 ;# Bool: Basic validation enabled
+
+ # Local variables
+ set seg_type {} ;# segment type
+ set expr_len 0 ;# length of expression
+
+ # Handle empty segments
+ if {$segment_data == {}} {
+ return [list $seg_type $expr_len]
+ }
+
+ # Convert segment data to uppre case (patterns are uppper-case)
+ set segment_data [string toupper $segment_data]
+
+ # Try to determinate segment type and perform highlight
+ set keyword $segment_data
+ if {[string index $keyword 0] == {.}} {
+ set keyword [string replace $keyword 0 0]
+ }
+ foreach keyword_list $keyword_lists \
+ tag {tag_instruction tag_directive tag_directive tag_directive tag_directive} \
+ type {instruction directive_0 directive_1 directive_2 directive_3} {
+ if {$type != {instruction}} {
+ if {[lsearch -ascii -exact $keyword_list $keyword] != -1} {
+ $editor tag add $tag $lineNumber.$start $lineNumber.$end
+ set seg_type $type
+ break
+ }
+ } {
+ if {[lsearch -ascii -exact $keyword_list $segment_data] != -1} {
+ $editor tag add $tag $lineNumber.$start $lineNumber.$end
+ set seg_type $type
+ break
+ }
+ }
+ }
+
+ # If segment type could not be recognized -> check for labels, macro's and controls
+ if {$seg_type == {}} {
+
+ # Handle compiler control sequences
+ if {[string index $segment_data 0] == {$}} {
+ set segment_data [string range $segment_data 1 end]
+ set expr_data {}
+
+ set segment_data "$segment_data $data"
+ set segment_data [string trimright $segment_data {  }]
+ set end [string length $segment_data]
+ incr end [expr {$start + 1}]
+ set ctrl_end $end
+ set data {}
+ if {[regexp {\(.*$} $segment_data expr_data]} {
+ set expr_len [string length $expr_data]
+ set expr_start [expr {$end - $expr_len - 1}]
+ set expr_end [expr {$expr_start + $expr_len}]
+ set end $expr_start
+ regsub {\(.*$} $segment_data {} segment_data
+ set segment_data [string trimright $segment_data]
+ }
+
+ # Control type 1
+ if {[lsearch -ascii -exact $controls_type1 $segment_data] != -1} {
+ set seg_type control_1
+ # Control type 0
+ } elseif {[lsearch -ascii -exact $controls_type0 $segment_data] != -1} {
+ set seg_type control_0
+ # Incorrect control sequence
+ } else {
+ set seg_type control_incorrect
+ if {$validation_L0} {
+ $editor tag add tag_error $lineNumber.$start $lineNumber.$end
+ }
+ }
+
+ # Puts tag "control"
+ $editor tag add tag_control $lineNumber.$start $lineNumber.$end
+
+ # Control sequence argument
+ if {$expr_data != {}} {
+ parse_argument $expr_start $expr_end $expr_data $start $end
+ if {$validation_L0 && $seg_type == {control_0}} {
+ $editor tag add tag_error $lineNumber.$expr_start $lineNumber.$expr_end
+ }
+ } elseif {$validation_L0 && $seg_type == {control_1}} {
+ $editor tag add tag_error $lineNumber.$start $lineNumber.$end
+ }
+
+ # Labels
+ } elseif {[regexp -nocase {^\w+:$} $segment_data]} {
+ $editor tag add tag_label $lineNumber.$start $lineNumber.$end
+ set seg_type label
+
+ # Unknown type - possibly macro instruction
+ } {
+ set seg_type unknown
+ }
+ }
+
+ # Return result
+ return [list $seg_type $expr_len]
+ }
+
+ ## Highlight argument (eg. '("some string")')
+ # @parm Int start_index - start column of the argument
+ # @parm Int end_index - end column of the argument
+ # @parm String data - argument data
+ # @return void
+ proc parse_argument {start_index end_index data control_start control_end} {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable validation_L0 ;# Bool: Basic validation enabled
+
+ if {[regexp {^\(.*\)$} $data]} {
+ $editor tag add tag_symbol $lineNumber.$start_index $lineNumber.[expr {$start_index + 1}]
+ set end [expr {$end_index - 1}]
+ $editor tag add tag_symbol $lineNumber.$end $lineNumber.$end_index
+
+ $editor tag add tag_string $lineNumber.[expr {$start_index + 1}] $lineNumber.$end
+ } {
+ if {$validation_L0} {
+ $editor tag add tag_error \
+ $lineNumber.$control_start $lineNumber.$control_end
+ }
+ }
+ }
+
+ ## Tag the given segment as error
+ # @parm Int segment_number - number of the target segment
+ # @return void
+ proc put_error_on_segment {segment_number} {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable seg_0_start ;# Start index of seg_0
+ variable seg_1_start ;# Start index of seg_1
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_0_end ;# End index of seg_0
+ variable seg_1_end ;# End index of seg_1
+ variable seg_2_end ;# End index of seg_2
+
+ if {!$validation_L0} {
+ return
+ }
+
+ # Determinate start and end index
+ switch -- $segment_number {
+ 0 {
+ set start $seg_0_start
+ set end $seg_0_end
+ }
+ 1 {
+ set start $seg_1_start
+ set end $seg_1_end
+ }
+ 2 {
+ set start $seg_2_start
+ set end $seg_2_end
+ }
+ }
+
+ # Add error tag
+ $editor tag add tag_error $lineNumber.$start $lineNumber.$end
+ }
+
+ ## Parse attributes in defintion of macro instruction
+ # @retunr void
+ proc parse_arguments {} {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_2 ;# 3rd field of the line
+ variable validation_L0 ;# Bool: Basic validation enabled
+
+ if {[regexp {^\s*$} $seg_2]} {return 0}
+
+ while 1 {
+ # Handle redutant commas
+ while 1 {
+ if {![regexp {^\s*\,} $seg_2]} {break}
+
+ set space_len 0
+ if {[regexp {^\s+} $seg_2 space_len]} {
+ set space_len [string length $space_len]
+ }
+
+ incr seg_2_start $space_len
+ set seg_2 [string range $seg_2 [expr {$space_len + 1}] end]
+
+ $editor tag add tag_oper_sep \
+ $lineNumber.$seg_2_start \
+ $lineNumber.[expr {$seg_2_start + 1}]
+
+ if {$validation_L0} {
+ $editor tag add tag_error \
+ $lineNumber.$seg_2_start \
+ $lineNumber.[expr {$seg_2_start + 1}]
+ }
+
+ incr seg_2_start
+ }
+
+ # Determinate argument
+ if {![regexp {^[^\,]+} $seg_2 argument]} {break}
+ set argument_len_org [string length $argument]
+ set seg_2 [string range $seg_2 $argument_len_org end]
+ set argument [string trimleft $argument]
+ set argument_len [string length $argument]
+ incr seg_2_start [expr {$argument_len_org - $argument_len}]
+
+ # Highlight argument
+ $editor tag add tag_constant \
+ $lineNumber.$seg_2_start \
+ $lineNumber.[expr {$seg_2_start + $argument_len}]
+ set argument [string trimright $argument]
+ if {$validation_L0 && ([regexp {^\d} $argument] || ![regexp {^\w+$} $argument])} {
+ $editor tag add tag_error \
+ $lineNumber.$seg_2_start \
+ $lineNumber.[expr {$seg_2_start + $argument_len}]
+ }
+
+ incr seg_2_start $argument_len
+
+ # highlight argument separator
+ if {[string index $seg_2 0] == {,}} {
+ set sep_end $seg_2_start
+ incr sep_end
+ $editor tag add tag_oper_sep $lineNumber.$seg_2_start $lineNumber.$sep_end
+ if {$validation_L0 && ![regexp {[\w$]} $seg_2]} {
+ $editor tag add tag_error $lineNumber.$seg_2_start $lineNumber.$sep_end
+ }
+ incr seg_2_start
+ set seg_2 [string range $seg_2 1 end]
+ }
+ }
+ }
+
+ ## Highlight all operands (segment 2) and their separators
+ # @return void
+ proc parse_operands {} {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_2 ;# 3rd field of the line
+
+ variable operands_count ;# Number of operands at the line
+ variable operand ;# Data of the current operand
+ variable opr_end ;# End index of the current operand
+ variable opr_start ;# Start index of the current operand
+
+ variable opr_types ;# List of operand types
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable validation_L1 ;# Bool: Advancet validation enabled
+
+ if {[regexp {^\s*$} $seg_2]} {return 0}
+ set operands_count 0
+ set opr_types {}
+
+ # split data into single operands
+ set i 0
+ set last_index $seg_2_start
+ set original_data $seg_2
+ set data [hide_strings $seg_2]
+
+ while 1 {
+ # Handle redutant commas
+ while 1 {
+ if {![regexp {^\s*\,} $data]} {break}
+
+ set space_len 0
+ if {[regexp {^\s+} $data space_len]} {
+ set space_len [string length $space_len]
+ }
+ incr last_index $space_len
+
+ set data [string range $data [expr {$space_len + 1}] end]
+ set original_data [string range $original_data [expr {$space_len + 1}] end]
+
+ $editor tag add tag_oper_sep \
+ $lineNumber.$last_index \
+ $lineNumber.[expr {$last_index + 1}]
+
+ if {$validation_L0} {
+ $editor tag add tag_error \
+ $lineNumber.$last_index \
+ $lineNumber.[expr {$last_index + 1}]
+ }
+
+ incr last_index
+ }
+
+ # gain operand data
+ if {![regexp {^[^\,]+} $data operand]} {break}
+ set operand_len [string length $operand]
+ set data [string range $data $operand_len end]
+ set operand [string range $original_data 0 [expr {$operand_len - 1}]]
+ set original_data [string range $original_data $operand_len end]
+
+ # determinate start index
+ if {[regexp {^\s+} $operand space]} {
+ set space_len [string length $space]
+ set opr_start [expr {$last_index + $space_len}]
+ set operand [string range $operand $space_len end]
+ } {
+ set opr_start $last_index
+ }
+
+ # determinate end index
+ if {[regexp {\s+$} $operand space]} {
+ set space_len [string length $space]
+ set opr_end [expr {$operand_len - $space_len}]
+ set operand [string range $operand 0 $opr_end]
+ } {
+ set opr_end $operand_len
+ }
+ incr opr_end $last_index
+ incr last_index $operand_len
+
+ set operand [string trimright $operand "\t "]
+ if {$validation_L1} {
+ add_aperand_to__opr_types
+ }
+ highlight_operand
+ incr operands_count
+
+ # highlight operand separator
+ if {[string index $data 0] == {,}} {
+ set sep_end $last_index
+ incr sep_end
+ $editor tag add tag_oper_sep $lineNumber.$last_index $lineNumber.$sep_end
+ if {$validation_L0 && ![regexp {[\w$]} $data]} {
+ $editor tag add tag_error $lineNumber.$last_index $lineNumber.$sep_end
+ }
+ incr last_index
+ set data [string range $data 1 end]
+ set original_data [string range $original_data 1 end]
+ }
+
+ incr i
+ }
+ }
+
+ ## Append current operand (var. operand) to list of operand types
+ #+ on current line
+ # @return void
+ proc add_aperand_to__opr_types {} {
+ variable opr_types ;# List of operand types
+ variable operand ;# Data of the current operand
+
+ set opr [string toupper $operand]
+
+ switch -- [string index $opr 0] {
+ {#} {lappend opr_types {#}}
+ {/} {lappend opr_types {/}}
+ {@} {lappend opr_types $opr}
+ default {
+ if {[lsearch -ascii -exact {R0 R1 R2 R3 R4 R5 R6 R7 DPTR A AB C} $opr] != -1} {
+ lappend opr_types $opr
+ } {
+ lappend opr_types {D}
+ }
+ }
+ }
+ }
+
+ ## Highlight current operand
+ # @return void
+ proc highlight_operand {} {
+ variable editor ;# ID of the text widget
+ variable operand ;# Data of the current operand
+ variable opr_end ;# End index of the current operand
+ variable opr_start ;# Start index of the current operand
+ variable spec_registers ;# SFR registers
+ variable spec_bits ;# SFR bits
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable inline_asm ;# Is inline assembler
+ variable lineNumber ;# Number of current line
+
+ ## Determinate addressing type
+ set addr_type [string index $operand 0]
+
+ # Immediate adresing
+ if {$addr_type == {#}} {
+ set operand [string range $operand 1 end]
+
+ # Immediate char value
+ if {[string index $operand 0] == {'} && [string index $operand end] == {'}} {
+ set len [string length $operand]
+ if {$validation_L0 && $len < 3} {
+ put_tag_on_operand tag_error
+ }
+ if {$len > 3} {
+ put_tag_on_operand tag_string
+ } {
+ put_tag_on_operand tag_imm_char
+ }
+
+ # Label in inline assembler
+ } elseif {[regexp {^\d+\$$} $operand]} {
+ put_tag_on_operand tag_imm_constant
+
+ # Operand has no value => incorrect operand
+ } elseif {[regexp { |\(|\)|\+|\-|\%|\=|\>|\<|\*|\/} $operand]} {
+ parse_expression $operand $opr_start $opr_end
+ $editor tag add tag_symbol \
+ $lineNumber.$opr_start $lineNumber.$opr_start+1c
+
+ } elseif {
+ $validation_L0 &&
+ ([string length $operand] == 0 || ![regexp {^[\w\$\.\\]+$} $operand])
+ } {
+ put_tag_on_operand tag_error
+
+ # Operand value determinated successfully
+ } else {
+ parse_operand_auxiliary2 {
+ tag_imm_unknown tag_imm_hex tag_imm_dec
+ tag_imm_oct tag_imm_bin tag_imm_char
+ tag_imm_constant tag_string
+ }
+ }
+
+ # Indirect adresing
+ } elseif {$addr_type == {@}} {
+ set operand [string range $operand 1 end]
+ put_tag_on_operand tag_indirect
+
+ # Check for operand validity
+ if {!$validation_L0} {return}
+ set operand [string toupper $operand]
+ if {
+ $operand != {R0} &&
+ $operand != {R1} &&
+ $operand != {DPTR} &&
+ $operand != {A+PC} &&
+ $operand != {A+DPTR}
+ } {
+ put_tag_on_operand tag_error
+ }
+
+ # Direct bit adresing
+ } elseif {$addr_type == {/}} {
+ set operand [string range $operand 1 end]
+
+ if {[regexp {\(|\)|\+|\-|\%|\=|\>|\<|\*|\/} $operand]} {
+ parse_expression $operand $opr_start $opr_end
+ $editor tag add tag_symbol \
+ $lineNumber.$opr_start $lineNumber.$opr_start+1c
+
+ } elseif {
+ $validation_L0 &&
+ ([string length $operand] == 0 || ![regexp {^'?[\w\.]+'?$} $operand])
+ } {
+
+ # Operand has no value => incorrect operand
+ put_tag_on_operand tag_error
+
+ } else {
+ parse_operand_auxiliary $spec_bits {
+ tag_unknown_base tag_hex tag_dec
+ tag_oct tag_bin tag_char
+ tag_constant tag_string
+ }
+ }
+
+ # Another kind of direct adresing
+ } else {
+ parse_operand_auxiliary $spec_registers {
+ tag_unknown_base tag_hex tag_dec
+ tag_oct tag_bin tag_char
+ tag_constant tag_string
+ }
+ }
+ }
+
+ ## Auxiliary procedure for procedure highlight_operand
+ # @parm List SFR_set - List of SFR keywords
+ # @parm List tag_list - List of tags for procedure parse_operand_auxiliary2
+ # @return void
+ proc parse_operand_auxiliary {SFR_set tag_list} {
+ variable operand ;# Data of the current operand
+
+ # SFR
+ if {[lsearch -ascii -exact $SFR_set [string toupper $operand]] != -1} {
+ put_tag_on_operand tag_sfr
+
+ # Something else than SFR
+ } {
+ parse_operand_auxiliary2 $tag_list
+ }
+ }
+
+ ## Auxiliary procedure for procedures highlight_operand and parse_operand_auxiliary
+ # @parm List tag_list - list of text tags (see code)
+ # @return void
+ proc parse_operand_auxiliary2 {tag_list} {
+ variable operand ;# Data of the current operand
+ variable opr_start ;# Start index of the current operand
+ variable opr_end ;# End index of the current operand
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable spec_registers ;# SFR registers
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable inline_asm ;# Is inline assembler
+
+ # Label in inline assembler
+ if {$inline_asm && [regexp {^\d+\$$} $operand]} {
+ put_tag_on_operand [lindex $tag_list 6]
+
+ # Expression
+ } elseif {[regexp {\(|\)|\+|\-|\%|\=|\>|\<|\*|\/} $operand]} {
+ parse_expression $operand $opr_start $opr_end
+
+ # Dot notation (bit addressing)
+ } elseif {[regexp {^\w+\.\w+$} $operand]} {
+ set opr [split $operand {.}]
+ set operand [lindex $opr 0]
+
+ set opr_true_end $opr_end
+ set opr_end $opr_start
+ incr opr_end [string length $operand]
+
+ parse_operand_auxiliary $spec_registers $tag_list
+
+ set opr_start [expr {$opr_end + 1}]
+ $editor tag add tag_symbol $lineNumber.$opr_end $lineNumber.$opr_start
+
+ set opr_end $opr_true_end
+ set operand [lindex $opr 1]
+
+ parse_operand_auxiliary2 $tag_list
+
+ # Direct value
+ } elseif {[regexp {^(\d|')} $operand]} {
+ # gain information about the openand (radix and decimal value)
+ set opr_info [which_radix 0 $operand]
+ set opr_base [lindex $opr_info 0]
+ set opr_in_dec [lindex $opr_info 1]
+
+ # Radix determinated incorrectly => unknown number
+ if {$opr_base == {}} {
+ put_tag_on_operand [lindex $tag_list 0]
+
+ if {$validation_L0 && ![regexp {^\d+$} $operand]} {
+ put_tag_on_operand tag_error
+ }
+
+ # Radix determinated correctly - continue normaly
+ } {
+ # check for allowed operand value range
+ if {$validation_L0 && $opr_in_dec == {error}} {
+
+ ## Operand value is invalid => incorrect operand
+ put_tag_on_operand tag_error
+
+ } {
+ if {$validation_L0 && ($opr_in_dec > 65535 || $opr_in_dec < 0)} {
+
+ ## Operand value is out of range => incorrect operand
+ put_tag_on_operand tag_error
+ }
+ }
+
+ # highlight acording to numeric base
+ switch -- $opr_base {
+ {hex} {put_tag_on_operand [lindex $tag_list 1]}
+ {dec} {put_tag_on_operand [lindex $tag_list 2]}
+ {oct} {put_tag_on_operand [lindex $tag_list 3]}
+ {bin} {put_tag_on_operand [lindex $tag_list 4]}
+ {ascii} {put_tag_on_operand [lindex $tag_list 5]}
+ {string} {put_tag_on_operand [lindex $tag_list 7]}
+ }
+ }
+
+ # defined by a symbolic name
+ } {
+ put_tag_on_operand [lindex $tag_list 6]
+ if {
+ $validation_L0 && ($operand != {$}) && ![regexp {^\w+$} $operand]
+ } {
+ put_tag_on_operand tag_error
+ }
+ }
+ }
+
+ ## Highlight current operand by the given tag
+ # @parm String tag_name - tag name
+ # @return void
+ proc put_tag_on_operand {tag_name} {
+ variable lineNumber ;# Number of current line
+ variable opr_end ;# End index of the current operand
+ variable opr_start ;# Start index of the current operand
+ variable editor ;# ID of the text widget
+
+ $editor tag add $tag_name $lineNumber.$opr_start $lineNumber.$opr_end
+ }
+
+ ## Determinate numeric base of the given number
+ # @parm Bool norange - 1 == determinate decimal value (sometimes...) and validate it (see code)
+ # @parm String number - number to analyze
+ # @return List - {base decimal_value} or {base "error"}
+ proc which_radix {norange number} {
+ set original_len [string length $number]
+ set len [string length [string trimleft $number {0}]]
+ if {$original_len > 1 && $len == 1} {
+ incr len
+ }
+ incr len -1
+ set radix [string index $number end]
+ set number [string range $number 0 {end-1}]
+ set dec_val error
+ set base {}
+
+ # Character or string
+ if {$radix == {'}} {
+ if {[string index $number 0] == {'}} {
+ set number [string range $number 1 end]
+
+ set base ascii
+ if {[string length $number] == 1} {
+ set dec_val 0
+
+ } elseif {[string length $number] > 1} {
+ set base string
+ set dec_val 0
+ }
+ }
+
+ # Regular numbers
+ } else {
+ set radix [string tolower $radix]
+ switch -- $radix {
+ {h} { ;# Hexadecimal
+ set base hex
+ if {$norange || ($len <= 4 && $len >= 1)} {
+ if {[regexp {^[A-Fa-f0-9]*$} $number]} {
+ set dec_val 0
+ }
+ }
+ }
+ {d} { ;# Decimal
+ set base dec
+ if {$norange || ($len <= 5 && $len >= 1)} {
+ if {[regexp {^[0-9]*$} $number]} {
+ set dec_val $number
+ }
+ }
+ }
+ {o} { ;# Octal
+ set base oct
+ if {$norange} {
+ if {[regexp {^[0-7]*$} $number]} {
+ set dec_val 0
+ }
+ } elseif {$len <= 6 && $len >= 1} {
+ if {[regexp {^[0-7]*$} $number]} {
+ if {$len != 3} {
+ set dec_val 0
+ } {
+ if {[string index $number 0] <= 3} {
+ set dec_val 0
+ }
+ }
+ }
+ }
+ }
+ {q} { ;# Octal
+ set base oct
+ if {$norange} {
+ if {[regexp {^[0-7]*$} $number]} {
+ set dec_val 0
+ }
+ } elseif {$len <= 6 && $len >= 1} {
+ if {[regexp {^[0-7]*$} $number]} {
+ if {$len != 3} {
+ set dec_val 0
+ } {
+ if {[string index $number 0] <= 3} {
+ set dec_val 0
+ }
+ }
+ }
+ }
+ }
+ {b} { ;# Binary
+ set base bin
+ if {$norange || ($len <= 16 && $len >= 1)} {
+ if {[regexp {^[01]*$} $number]} {
+ set dec_val 0
+ }
+ }
+ }
+ default { ;# Default
+ set dec_val {}
+ }
+ }
+ }
+
+ # done ...
+ return "$base $dec_val"
+ }
+
+ ## Highlight expressions (eg. '( 10d - X MOD 55h)')
+ # @parm String data - expression to highlight
+ # @parm Int start_index - expresssion start index
+ # @parm Int end_index - expresssion end index
+ # @return void
+ proc parse_expression {data start_index end_index} {
+
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable expr_symbols ;# symbol operators
+ variable expr_instructions ;# word operators
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable validation_L1 ;# Bool: Advancet validation enabled
+
+ # Adjust data to fit the given boundaries
+ set data_len [string length $data]
+ set dif [expr {$end_index - $start_index - $data_len}]
+ if {$dif != 0} {
+ set space [string repeat { } $dif]
+ set data $space$data
+ }
+
+ # Remove strings
+ set e_idx 0
+ while 1 {
+ if {![regexp -start $e_idx -- {'[^']*'} $data string_data]} {
+ break
+ }
+ set len [string length $string_data]
+ set s_idx [string first {'} $data $e_idx]
+ set e_idx [expr {$s_idx + $len}]
+
+ if {$len > 2} {
+ set data [string replace $data \
+ [expr {$s_idx + 1}] [expr {$e_idx - 2}] \
+ [string repeat { } [expr {$len - 2}]] \
+ ]
+ }
+ }
+
+ # remove and highlight '('
+ set opended_par 0
+ while 1 {
+ set symbol_idx [string first {(} $data]
+ if {$symbol_idx == -1} {break}
+
+ incr opended_par
+ set data [string replace $data $symbol_idx $symbol_idx { }]
+ incr symbol_idx $start_index
+ $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.[expr {$symbol_idx + 1}]
+ }
+ # remove and highlight ')'
+ while 1 {
+ set symbol_idx [string first {)} $data]
+ if {$symbol_idx == -1} {break}
+
+ incr opended_par -1
+ set data [string replace $data $symbol_idx $symbol_idx { }]
+ incr symbol_idx $start_index
+ $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.[expr {$symbol_idx + 1}]
+ }
+ # chcek if parenthesies are balanced
+ if {$validation_L0 && $opended_par != 0} {
+ $editor tag add tag_error $lineNumber.$start_index $lineNumber.$end_index
+ }
+
+ # Highlight exprression symbols (+1 chars) and remove them from the string
+ set adjusted_data [string toupper $data]
+ regsub -all {\t} $adjusted_data { } adjusted_data
+ append adjusted_data { }
+ foreach symbol $expr_instructions {
+ while 1 {
+ set symbol_idx [string first " $symbol " $adjusted_data]
+ if {$symbol_idx == -1} {break}
+ set original_symbol_idx $symbol_idx
+
+ set space_len [string length $symbol]
+ incr space_len 1
+ set symbol_end_index $symbol_idx
+ incr symbol_end_index $space_len
+ set symbol_end_index_org_1 [expr {$symbol_end_index + 1}]
+
+ incr space_len
+ set space [string repeat { } $space_len]
+ set adjusted_data [string replace $adjusted_data $symbol_idx $symbol_end_index $space]
+ set data [string replace $data $symbol_idx $symbol_end_index $space]
+
+ incr symbol_idx $start_index
+ incr symbol_end_index $start_index
+ $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.$symbol_end_index
+
+ if {$validation_L1} {
+ set tmp [string range $data $symbol_end_index_org_1 end]
+ set tmp [string toupper [string trim $tmp]]
+ if {![string length $tmp]} {
+ $editor tag add tag_error \
+ $lineNumber.[expr {$symbol_idx + 1}] \
+ $lineNumber.$symbol_end_index
+ } {
+ foreach smb $expr_instructions {
+ if {![string first $smb $tmp]} {
+ $editor tag add tag_error \
+ $lineNumber.[expr {$symbol_idx + 1}] \
+ $lineNumber.$symbol_end_index
+ break
+ }
+ }
+ }
+ }
+ }
+ }
+ # Highlight expression symbols (1 char) and remove them from the string
+ foreach symbol $expr_symbols {
+ while 1 {
+ set symbol_idx [string first $symbol $data]
+ if {$symbol_idx == -1} {break}
+ set original_symbol_idx $symbol_idx
+ set symbol_idx_org_1 [expr {$symbol_idx + 1}]
+
+ set data [string replace $data $symbol_idx $symbol_idx { }]
+ incr symbol_idx $start_index
+ set symbol_idx_1 [expr {$symbol_idx + 1}]
+ $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.$symbol_idx_1
+
+ if {
+ $validation_L0 && (
+ !$original_symbol_idx
+ ||
+ ![regexp {^\s*((\'\\?[^']\')|\w|\$)} [string range $data $symbol_idx_org_1 end]]
+ )
+ } {
+ $editor tag add tag_error \
+ $lineNumber.$symbol_idx \
+ $lineNumber.$symbol_idx_1
+ }
+ }
+ }
+
+ # Highlight other parts
+ set last_index $start_index
+ set original_data $data
+ set data [hide_strings $data]
+ while 1 {
+
+ if {![regexp {[^\s]+} $data value]} {break}
+
+ set value_S_idx [string first $value $data]
+ set value_len [string length $value]
+ set value_E_idx $value_len
+ incr value_E_idx $value_S_idx
+
+ set value [string range $original_data $value_S_idx $value_E_idx]
+
+ set data [string range $data $value_E_idx end]
+ set original_data [string range $original_data $value_E_idx end]
+
+ set tmp_idx $value_E_idx
+ incr value_S_idx $last_index
+ incr value_E_idx $last_index
+ incr last_index $tmp_idx
+
+ highlight_value [string trimright $value] $value_S_idx $value_E_idx
+ }
+ }
+
+ ## Highlight constant values
+ # @parm String data - string to highlight
+ # @parm Int start_index - start index
+ # @parm Int end_index - end index
+ # @return void
+ proc highlight_value {data start_index end_index} {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable spec_registers ;# SFR registers
+
+ # Dot notation -- bit addressing
+ if {[regexp {^\w+\.\w+$} $data]} {
+ set data [split $data {.}]
+
+ set end_index_org $end_index
+ set end_index $start_index
+ incr end_index [string length [lindex $data 0]]
+ highlight_value [lindex $data 0] $start_index $end_index
+
+ $editor tag add tag_symbol $lineNumber.$end_index $lineNumber.[expr {$end_index + 1}]
+
+ incr end_index
+ highlight_value [lindex $data 1] $end_index $end_index_org
+ return
+
+ } elseif {[regexp {^(\d|')} $data]} {
+ # Gain information about the value
+ set opr_info [which_radix 1 $data]
+ set opr_base [lindex $opr_info 0]
+ set opr_in_dec [lindex $opr_info 1]
+
+ # Highlight value acording to info
+ if {$opr_base == {}} {
+ $editor tag add tag_unknown_base $lineNumber.$start_index $lineNumber.$end_index
+ if {$validation_L0 && ![regexp {^[0-9A-Fa-f]+$} $data]} {
+ $editor tag add tag_error $lineNumber.$start_index $lineNumber.$end_index
+ }
+ return
+ }
+ if {$validation_L0 && $opr_in_dec == {error}} {
+ $editor tag add tag_error $lineNumber.$start_index $lineNumber.$end_index
+ }
+
+ # Highlight acording to numeric base
+ switch -- $opr_base {
+ {hex} { ;# Hexadecimal
+ $editor tag add tag_hex $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {dec} { ;# Decimal
+ $editor tag add tag_dec $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {oct} { ;# Octal
+ $editor tag add tag_oct $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {bin} { ;# Binary
+ $editor tag add tag_bin $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {ascii} { ;# Char
+ $editor tag add tag_char $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {string} { ;# String
+ $editor tag add tag_string $lineNumber.$start_index $lineNumber.$end_index
+ }
+ }
+ return
+ }
+
+ # Constant
+ if {[lsearch -ascii -exact $spec_registers [string toupper $data]] != -1} {
+ set tag tag_sfr
+ } {
+ set tag tag_constant
+ }
+ $editor tag add $tag $lineNumber.$start_index $lineNumber.$end_index
+ if {$validation_L0 && ![regexp {^((\w+)|\$)$} $data]} {
+ $editor tag add tag_error $lineNumber.$start_index $lineNumber.$end_index
+ }
+ }
+
+ ## Replace all single quoted string with underscores (''abc'' -> '_____')
+ # @parm String data - input data
+ # @return String - output data
+ proc hide_strings {data} {
+ # Return string which dowsn't contain '''
+ if {[string first {'} $data] == -1} {return $data}
+
+ # Perform replacement
+ while 1 {
+ if {![regexp {'[^']*'} $data string]} {
+ break
+ }
+ regsub {'[^']*'} $data [string repeat {_} \
+ [string length $string] \
+ ] data
+ }
+
+ # Return result
+ return $data
+ }
+}
+
+# Initialize some namespace variables
+foreach item ${::ASMsyntaxHighlight::all_controls} {
+ lappend ::ASMsyntaxHighlight::all_controls__with_dolar "\$$item"
+}
diff --git a/lib/editor/Csyntaxhighlight.tcl b/lib/editor/Csyntaxhighlight.tcl
new file mode 100755
index 0000000..8bdc913
--- /dev/null
+++ b/lib/editor/Csyntaxhighlight.tcl
@@ -0,0 +1,853 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements syntax highlighting interface for ISO C language
+# --------------------------------------------------------------------------
+
+namespace eval CsyntaxHighlight {
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+ variable line_start ;# Index of line start
+ variable line_end ;# Index of line end
+ variable validation_L0 1 ;# Bool: Basic validation enabled
+ variable validation_L1 1 ;# Bool: Advanced validation enabled
+ # List of compiler directives
+ variable directives {
+ #define #error #include
+ #if #ifdef #ifndef
+ #else #elif #endif
+ #line #pragma #undef
+ }
+ # List of data type specifiers
+ variable data_types {
+ void int float double char signed unsigned
+ long short uchar ushort uint ulong const
+ export extern static mutable volatile
+ }
+ # List of C keywords
+ variable keywords {
+ auto break case _endasm while union continue
+ default do else enum sizeof for namespace
+ if goto return struct switch typedef using
+ }
+ # List of doxygen tags -- No argument
+ variable doxy_tags_type0 {
+ @return @see @sa @arg
+ @li @nosubgrouping @subpage @f$
+ @f[ @f] @interface
+ }
+ # List of doxygen tags -- Word after tag
+ variable doxy_tags_type1 {
+ @param @defgroup @addtogroup @weakgroup
+ @ref @page @struct @union
+ @enum @def @file @namespace
+ @package
+ }
+ # List of doxygen tags -- Name after tag
+ variable doxy_tags_type2 {
+ @brief @ingroup @name @mainpage
+ @fn @var @typedef
+ }
+ # List of HTML tags (HTML 4.0 Strict)
+ variable html_tags {
+ a abbr acronym address
+ area b base bdo
+ big blockquote body br
+ button caption cite code
+ col colgroup dd del
+ dfn div dl dt
+ em fieldset form frame
+ frameset h1 h2 h3
+ h4 h5 h6 head
+ hr html i img
+ input ins kbd label
+ legend li link map
+ meta noscript object ol
+ optgroup option p param
+ pre q samp script
+ select small span strong
+ style sub sup table
+ tbody td textarea tfoot
+ th thead title tr
+ tt ul var
+ }
+
+ ## Highlight pattern - highlight tags definition
+ # {
+ # {tag_name ?foreground? ?overstrike? ?italic? ?bold?}
+ # }
+ variable hightlight_tags {
+ {tag_c_keyword #0000DD 0 0 1}
+ {tag_c_data_type #00CC00 0 0 1}
+ {tag_c_dec #0000FF 0 0 0}
+ {tag_c_hex #8800FF 0 0 0}
+ {tag_c_oct #883300 0 0 0}
+ {tag_c_char #DD00DD 0 0 0}
+ {tag_c_float #AA00AA 0 0 0}
+ {tag_c_string #BB0000 0 0 0}
+ {tag_c_string_char #DD00DD 0 0 0}
+ {tag_c_comment #888888 0 1 0}
+ {tag_c_symbol #FF0000 0 0 1}
+ {tag_c_bracket #EE6600 0 0 1}
+ {tag_c_preprocessor #008800 0 0 0}
+ {tag_c_directive #558800 0 0 0}
+ {tag_c_prep_lib #885500 0 0 0}
+ {tag_normal #000000 0 0 0}
+
+ {tag_c_dox_comment #4444FF 0 1 0}
+ {tag_c_dox_tag #AA00DD 0 0 1}
+ {tag_c_dox_word #0088FF 0 0 1}
+ {tag_c_dox_name #FF0000 0 0 0}
+ {tag_c_dox_html #000000 0 0 1}
+ {tag_c_dox_harg #008800 0 0 0}
+ {tag_c_dox_hargval #DD0000 0 0 0}
+ }
+
+ ## Define highlighting text tags in the given text widget
+ # @parm Widget - ID of the target text widget
+ # @parm Int - font size
+ # @parm String - font family
+ # @parm List = default - Highlighting tags definition
+ # @return void
+ proc create_tags args {
+ variable hightlight_tags ;# Highlight tags definition
+
+ # Handle arguments
+ set text_widget [lindex $args 0] ;# text widget
+ set fontSize [lindex $args 1] ;# font size
+ set fontFamily [lindex $args 2] ;# font family
+ if {[llength $args] > 3} { ;# highlighting definition
+ set hightlight [lindex $args 3]
+ } {
+ set hightlight $hightlight_tags
+ }
+
+ # Iterate over highlighting tags definition
+ foreach item $hightlight {
+ # Create array of tag attributes
+ for {set i 0} {$i < 5} {incr i} {
+ set tag($i) [lindex $item $i]
+ }
+
+ # Foreground color
+ if {$tag(1) == {}} {
+ set tag(1) black
+ }
+ # Fonr slant
+ if {$tag(3) == 1} {
+ set tag(3) italic
+ } {
+ set tag(3) roman
+ }
+ # Font weight
+ if {$tag(4) == 1} {
+ set tag(4) bold
+ } {
+ set tag(4) normal
+ }
+
+ # Create the tag in the target text widget
+ $text_widget tag configure $tag(0) \
+ -foreground $tag(1) \
+ -font [font create \
+ -overstrike $tag(2) \
+ -slant $tag(3) \
+ -weight $tag(4) \
+ -size -$fontSize \
+ -family $fontFamily \
+ ]
+ }
+
+ # Set tag priorities
+ $text_widget tag raise tag_c_dox_tag tag_c_dox_comment
+ $text_widget tag raise tag_c_dox_word tag_c_dox_comment
+ $text_widget tag raise tag_c_dox_html tag_c_dox_comment
+
+ foreach t {
+ tag_c_bracket tag_c_symbol tag_c_keyword
+ tag_c_data_type tag_c_char tag_c_dec
+ tag_c_oct tag_c_hex tag_c_float
+ } {
+ $text_widget tag raise $t tag_normal
+ }
+ }
+
+ ## Perform syntax highlight on the given line in the given widget
+ # @parm Widget Editor - Text widget
+ # @parm Int LineNumber - Number of line to highlight
+ # @parm Int status - Exit status of previous line
+ # @return Int - Exit status
+ # 1 - Normal
+ # 2 - Doxygen
+ # 3 - Comment
+ # 4 - String
+ # 5 - Assembly
+ # 6 - Assembly within
+ # 7 - Preprocessor
+ proc highlight {Editor LineNumber status} {
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+ variable line_start ;# Index of line start
+ variable line_end ;# Index of line end
+ variable directives ;# List of compiler directives
+
+ # Set NS variables
+ set editor $Editor
+ set line_number $LineNumber
+ set line_start $line_number.0
+ set line_end [$editor index [list $line_number.0 lineend]]
+ set line_content [$editor get $line_start $line_end]
+
+ # Validate input arguments
+ if {!$status} {
+ set status 1
+ }
+
+ # Local variables
+ set last_idx_s 0 ;# Int: Last search index
+ set incr_last_i 0 ;# Int: Increment last_idx by
+ set last_idx 0 ;# Int: Last index
+ set idx 0 ;# Int: Current index
+ set this_line_only 0 ;# Bool: Status is valid for this line only
+ set last_status $status ;# Int: Last highlight status
+
+ # Remove existing highlighting tags
+ delete_tags
+
+ # Handle status "preprocessor"
+ if {$status == 7} {
+ if {[string index $line_content end] == "\\"} {
+ $editor tag add tag_c_preprocessor $line_start $line_end-1c
+ $editor tag add tag_c_symbol $line_end-1c $line_end
+ return 7
+ } {
+ $editor tag add tag_c_preprocessor $line_start $line_end
+ return 1
+ }
+
+ # Search for preprocessor directive
+ } elseif {$status == 1} {
+ # Common directive
+ if {[regexp {^\s*#\w+} $line_content directive]} {
+ # Local variables
+ set dir_start [string first {#} $line_content] ;# Int: Directive start index
+ set dir_end [string length $directive] ;# Int: Directive end index
+ set directive [string trim $directive] ;# String: Directive itself
+
+ # Highlight directive
+ $editor tag add tag_c_directive \
+ $line_number.$dir_start $line_number.$dir_end
+
+ # Validate directive
+ if {$validation_L0} {
+ if {[lsearch -ascii -exact $directives $directive] == -1} {
+ $editor tag add tag_error \
+ $line_number.$dir_start $line_number.$dir_end
+ }
+ }
+
+ # Highlight directive argument
+ if {$directive == {#include}} {
+ set prep_tag {tag_c_prep_lib}
+ } {
+ set prep_tag {tag_c_preprocessor}
+ }
+
+ # Determinate start of comment
+ set com_start [string first {//} $line_content]
+ if {$com_start != -1} {
+ set cur_line_end $com_start
+ incr cur_line_end -1
+ set cur_line_end $line_number.$cur_line_end
+ } {
+ set cur_line_end $line_end
+ }
+
+ # Determinate whether the directive continue on the next line or not
+ if {[string index [regsub {\s+$} $line_content {}] end] == "\\"} {
+ $editor tag add $prep_tag $line_number.$dir_end $cur_line_end-1c
+ $editor tag add tag_c_symbol $cur_line_end-1c $cur_line_end
+ set cur_status 7
+ } else {
+ $editor tag add $prep_tag $line_number.$dir_end $cur_line_end
+ set cur_status 1
+ }
+
+ # There is a comment on the line
+ if {$com_start != -1} {
+ $editor tag add tag_c_comment \
+ $line_number.$com_start \
+ [list $line_number.0 lineend]
+ }
+
+ return $cur_status
+
+ # Inline assembler
+ } elseif {[regexp {^\s*_asm\s*$} $line_content]} {
+ $editor tag add tag_c_keyword $line_start $line_end
+ return 5
+ }
+ }
+
+ # Split line into fields with different highlight status
+ while 1 {
+ set incr_last_i 0
+ switch -- $status {
+ 1 { ;# Normal
+ set i 0
+ set idx [list {} {} {} {} {} {}]
+ foreach str {{/**} {///} {/*} {//} \"} {
+ lset idx $i [string first $str $line_content $last_idx_s]
+ incr i
+ }
+
+ set min_idx 0
+ set val 0
+ set min 0xFFFF
+ for {set i 0} {$i < 5} {incr i} {
+ set val [lindex $idx $i]
+ if {$val != -1 && $val < $min} {
+ set min_idx $i
+ set min $val
+ }
+ }
+
+ set idx [lindex $idx $min_idx]
+ if {$idx == -1} {break}
+ set last_status $status
+ switch -- $min_idx {
+ 0 {
+ set status 2
+ set incr_last_i 3
+ set this_line_only 0
+ }
+ 1 {
+ set status 2
+ set incr_last_i 3
+ set this_line_only 1
+ }
+ 2 {
+ set status 3
+ set incr_last_i 2
+ set this_line_only 0
+ }
+ 3 {
+ set status 3
+ set incr_last_i 2
+ set this_line_only 1
+ }
+ 4 {
+ set status 4
+ set incr_last_i 1
+ set this_line_only 0
+ }
+ }
+ }
+ 2 { ;# Doxygen
+ set idx [string first {*/} $line_content $last_idx_s]
+ if {$idx == -1} {break}
+ incr idx 2
+ set last_status $status
+ set status 1
+ }
+ 3 { ;# Comment
+ set idx [string first {*/} $line_content $last_idx_s]
+ if {$idx == -1} {break}
+ incr idx 2
+ set last_status $status
+ set status 1
+ }
+ 4 { ;# String
+ set l_idx $last_idx_s
+ while 1 {
+ set idx [string first "\"" $line_content $l_idx]
+ if {$idx < 1} {break}
+ if {[string index $line_content [expr {$idx - 1}]] == "\\"} {
+ incr l_idx
+ } {
+ break
+ }
+ }
+ if {$idx == -1} {break}
+ incr idx
+ set last_status $status
+ set status 1
+ }
+ 5 { ;# Inline assembler
+ if {[regexp {^\s*_endasm[^\w]*} $line_content]} {
+ mode_normal 0 [string length $line_content]
+ return 1
+ }
+ set idx 0
+ set last_status $status
+ set status 6
+ break
+ }
+ 6 { ;# Inline assembler -- within asm block
+ if {[regexp {^\s*_endasm[^\w]*} $line_content]} {
+ mode_normal 0 [string length $line_content]
+ return 1
+ } {
+ break
+ }
+ }
+ }
+
+ # Highliht this chunk
+ if {$last_idx != $idx} {
+ highlight_aux $last_status $last_idx $idx
+ }
+ set last_idx $idx
+ if {$this_line_only} {break}
+
+ set last_idx_s $last_idx
+ incr last_idx_s $incr_last_i
+ }
+
+ # Highlight last remaining chunk
+ if {$last_idx != [string length $line_content]} {
+ highlight_aux $status $last_idx [string length $line_content]
+ }
+
+ # Return final status
+ if {$this_line_only} {
+ return 1
+ } {
+ return $status
+ }
+ }
+
+ ## Auxiliary procedure for procedure highlight
+ # This procedure calls other procedures to perform syntax
+ #+ highlight acording to the given highlight status
+ # @parm Int status - Highlight status
+ # @parm Int idx0 - Start index
+ # @parm Int idx1 - End index
+ # @return void
+ proc highlight_aux {status idx0 idx1} {
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+
+ # Validate input arguments
+ if {$idx0 < 0} {
+ set idx0 0
+ }
+ if {$idx1 < 0} {
+ set idx1 0
+ }
+
+ # Determinate what to do
+ switch -- $status {
+ 1 { ;# Normal
+ mode_normal $idx0 $idx1
+ }
+ 2 { ;# Doxygen
+ mode_doxygen $idx0 $idx1
+ }
+ 3 { ;# Comment
+ $editor tag add tag_c_comment $line_number.$idx0 $line_number.$idx1
+ }
+ 4 { ;# String
+ mode_string $idx0 $idx1
+ }
+ 5 { ;# Inline assembly
+ mode_normal $idx0 $idx1
+ }
+ 6 { ;# Inline assembly -- within
+ ::ASMsyntaxHighlight::highlight $editor $line_number 1
+ }
+ }
+ }
+
+ ## Highlight text within specified indexes as string
+ # @parm Int idx0 - Start index
+ # @parm Int idx1 - End index
+ # @return void
+ proc mode_string {idx0 idx1} {
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+
+ # Local variables
+ set idx 0 ;# Int: Index of backslash in the string
+ set idx_idx0 0 ;# Int: ($idx0 + $idx)
+ set last_idx 0 ;# Int: Last value of $idx
+ # String to highlight
+ set string [string range $line_content $idx0 [expr {$idx1 - 1}]]
+
+ # Highlight escaped characters and character between them
+ while 1 {
+ # Search for backslash
+ set idx [string first "\\" $string $idx]
+ if {$idx == -1} {break}
+
+ # Highlight
+ set idx_idx0 [expr {$idx + $idx0}]
+ $editor tag add tag_c_string $line_number.[expr {$last_idx + $idx0}] $line_number.$idx_idx0
+ $editor tag add tag_c_string_char $line_number.$idx_idx0 $line_number.$idx_idx0+2c
+ incr idx 2
+ set last_idx $idx
+ }
+ # Highlight remaining chunk of the string
+ $editor tag add tag_c_string $line_number.[expr {$last_idx + $idx0}] $line_number.$idx1
+ }
+
+ ## Highlight text within specified indexes as doxygen document
+ # @parm Int idx0 - Start index
+ # @parm Int idx1 - End index
+ # @return void
+ proc mode_doxygen {idx0 idx1} {
+ variable validation_L1 ;# Bool: Advanced validation enabled
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+ variable doxy_tags_type0;# List of doxygen tags -- No argument
+ variable doxy_tags_type1;# List of doxygen tags -- Word after tag
+ variable doxy_tags_type2;# List of doxygen tags -- Name after tag
+ variable html_tags ;# List of HTML tags (HTML 4.0 Strict)
+
+ # Local variables
+ set tag_present 0 ;# Bool: Doxygen tag present on line
+ set asterix_p 0 ;# Bool: Leading asterix present on line
+ set i -1 ;# Int: Number of iteration
+ set idx -1 ;# Int: Word start index
+ set len 0 ;# Int: Word length
+ set tags {} ;# List: Highlight tags to put on current word
+ set is_word 0 ;# Bool: This word is doxygen tag word
+ # Determinate string to highlight
+ set string [string range $line_content $idx0 [expr {$idx1 - 1}]]
+ # Split line into words
+ set words [split [regsub -all {>} [regsub -all {<} $string { &}] {& }]]
+
+ # Adjust HTML tags with argument(s) (they must be represented as a single word)
+ set tag_opended 0
+ set result_words {}
+ foreach word $words {
+ if {!$tag_opended} {
+ append result_words { } ;# Insert a common space
+ } {
+ append result_words "\xA0" ;# Insert NBSP
+ }
+ if {!$tag_opended && [regexp {^<\w+$} $word]} {
+ set tag_opended 1
+ } elseif {$tag_opended && [string index $word end] == {>}} {
+ set tag_opended 0
+ }
+ append result_words [regsub -all {[\{\}]} $word {\\&}]
+ }
+ set words $result_words
+ set result_words {}
+
+ # Iterate over string words
+ foreach word $words {
+ # Skip empty words
+ if {$word == {}} {continue}
+
+ incr i
+ set idx [string first [regsub -all "\xA0" $word { }] $string [expr {$idx + $len}]]
+ set len [string length $word]
+
+ # Detect doxygen tag word
+ if {$is_word} {
+ set is_word 0
+ set tags {tag_c_dox_word}
+
+ # Detect dogygen tag
+ } elseif {[string index $word 0] == {@}} {
+ # Tags without argument
+ if {[lsearch $doxy_tags_type0 $word] != -1 || $word == {@f[}} {
+ set tags {tag_c_dox_tag}
+
+ # Tags with one argument
+ } elseif {[lsearch $doxy_tags_type1 $word] != -1} {
+ set tags {tag_c_dox_tag}
+ set is_word 1
+
+ # Tags witch has name after
+ } elseif {[lsearch $doxy_tags_type2 $word] != -1} {
+ $editor tag add tag_c_dox_tag \
+ $line_number.[expr {$idx0 + $idx}] \
+ $line_number.[expr {$idx0 + $idx + $len}]
+ $editor tag add tag_c_dox_name \
+ $line_number.[expr {$idx0 + $idx + $len}] \
+ $line_number.$idx1
+ break
+
+ # Invalid tag
+ } else {
+ set tags {tag_c_dox_tag}
+ if {$validation_L1} {
+ lappend tags {tag_error}
+ }
+ }
+
+ # Detect HTML tags
+ } elseif {[string index $word 0] == {<} && [string index $word end] == {>}} {
+ set tags {}
+
+ # Adjust word
+ set word [string replace $word 0 0 { }]
+ if {[string index $word 1] == {/}} {
+ set word [string replace $word 1 1 { }]
+ }
+ set word [string replace $word end end { }]
+ set word [regsub -all "\xA0" $word { }]
+
+ # Mark empty tags as errors
+ if {$validation_L1 && ![string length [string trim $word]]} {
+ $editor tag add tag_error \
+ $line_number.[expr {$idx0 + $idx}] \
+ $line_number.[expr {$idx0 + $idx + $len}]
+ $editor tag add tag_c_dox_html \
+ $line_number.[expr {$idx0 + $idx}] \
+ $line_number.[expr {$idx0 + $idx + $len}]
+ }
+
+ # Highlight each part of word separately (tag argument="value" ...)
+ set sub_len 0
+ set sub_idx -1
+ set w_idx -1
+ foreach w [split $word] {
+ if {$w == {}} {continue}
+ incr w_idx
+ set sub_len [string length $w]
+ incr sub_idx
+ set sub_idx [string first $w $word $sub_idx]
+
+ # Highlight and validate HTML tag
+ if {!$w_idx} {
+ # Highlight tagname
+ $editor tag add tag_c_dox_html \
+ $line_number.[expr {$idx0 + $idx}] \
+ $line_number.[expr {$idx0 + $idx + $sub_idx + $sub_len}]
+
+ # Check if HTML tag is valid HTML-4.0 Strict tag
+ if {$validation_L1 && [lsearch $html_tags [string tolower $w]] == -1} {
+ $editor tag add tag_error \
+ $line_number.[expr {$idx0 + $idx + $sub_idx}] \
+ $line_number.[expr {$idx0 + $idx + $sub_idx + $sub_len}]
+ }
+
+ # Highlight arguments
+ } else {
+ set first_equ_mark [string first {=} $w]
+ incr first_equ_mark
+
+ # Check if argument notation is valid
+ if {$validation_L1 && $first_equ_mark == $sub_len} {
+ $editor tag add tag_error \
+ $line_number.[expr {$idx0 + $idx + $sub_idx}] \
+ $line_number.[expr {$idx0 + $idx + $sub_idx + $sub_len}]
+ }
+
+ # Highlight argument value
+ if {$first_equ_mark} {
+ $editor tag add tag_c_dox_hargval \
+ $line_number.[expr {$idx0 + $idx + $sub_idx + $first_equ_mark}] \
+ $line_number.[expr {$idx0 + $idx + $sub_idx + $sub_len}]
+ } {
+ set first_equ_mark $sub_len
+ }
+
+ # Highlight argument name
+ $editor tag add tag_c_dox_harg \
+ $line_number.[expr {$idx0 + $idx + $sub_idx}] \
+ $line_number.[expr {$idx0 + $idx + $sub_idx + $first_equ_mark}]
+ }
+ }
+ # Highlight last ">"
+ $editor tag add tag_c_dox_html \
+ $line_number.[expr {$idx0 + $idx + $len - 1}] \
+ $line_number.[expr {$idx0 + $idx + $len}]
+
+ # Doxygen comment
+ } else {
+ set tags {tag_c_dox_comment}
+ }
+
+ # Create chosen highlighting tags
+ foreach tag $tags {
+ $editor tag add $tag \
+ $line_number.[expr {$idx0 + $idx}] \
+ $line_number.[expr {$idx0 + $idx + $len}]
+ }
+ }
+ }
+
+ ## Highlight text within specified indexes as normal text
+ # @parm Int idx0 - Start index
+ # @parm Int idx1 - End index
+ # @return void
+ proc mode_normal {idx0 idx1} {
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+ variable data_types ;# List of data type specifiers
+ variable keywords ;# List of C keywords
+
+ # Determinate string to highligh and its length
+ set string [string range $line_content $idx0 [expr {$idx1 - 1}]]
+ set len [string length $string]
+
+ # At first highlight all as a normal text
+ $editor tag add tag_normal $line_number.$idx0 $line_number.$idx1
+
+ # Highlight symbols
+ set char {}
+ for {set i 0; set j $idx0} {$i < $len} {incr i; incr j} {
+ set char [string index $string $i]
+
+ # Brackets
+ if {
+ $char == {(} || $char == {)} || $char == "\{" ||
+ $char == "\}" || $char == {[} || $char == {]}
+ } {
+ $editor tag add tag_c_bracket $line_number.$j $line_number.$j+1c
+
+ # Other symbols
+ } elseif {[lsearch {; = , + - < > ! | & * / ? : % ^} $char] != -1} {
+ $editor tag add tag_c_symbol $line_number.$j $line_number.$j+1c
+ }
+ }
+
+ # Highlight keywords and data types
+ set idx 0
+ foreach words [list $keywords $data_types] \
+ tag {tag_c_keyword tag_c_data_type} \
+ {
+ set idx -1
+ foreach word $words {
+ while 1 {
+ incr idx
+ set idx [string first $word $string $idx]
+ if {$idx == -1} {break}
+ set len [string length $word]
+ if {[string is wordchar -strict [string index $string [expr {$idx - 1}]]]} {
+ continue
+ }
+ if {[string is wordchar -strict [string index $string [expr {$idx + $len}]]]} {
+ continue
+ }
+ $editor tag add $tag \
+ $line_number.[expr {$idx0 + $idx}] \
+ $line_number.[expr {$idx0 + $idx + $len}]
+ }
+ }
+ }
+
+ # Highlight numbers
+ set idx -1
+ set len 0
+ set tags {}
+ foreach word [split $string {   ;=,+-<>!|&*/?:%^\{\}[]()}] {
+ if {$word == {}} {continue}
+
+ incr idx
+ set len [string length $word]
+ set idx [string first $word $string $idx]
+
+ # Char
+ if {![string is digit -strict [string index $word 0]]} {
+ if {[regexp {^'[^']*'$} $word]} {
+ set tags {tag_c_char}
+ } {
+ continue
+ }
+
+ # Oct | Dec
+ } elseif {[string is digit -strict $word]} {
+ if {[string index $word 0] == {0}} {
+ if {$len == 1} {
+ set tags {tag_c_dec}
+ } elseif {!$validation_L0 || [regexp {^0[0-7]+$} $word]} {
+ set tags {tag_c_oct}
+ } {
+ set tags {tag_c_oct tag_error}
+ }
+ } {
+ set tags {tag_c_dec}
+ }
+
+ # Hex
+ } elseif {
+ [string index $word 0] == {0} && (
+ [string index $word 1] == {x}
+ ||
+ [string index $word 1] == {X}
+ )
+ } {
+ if {!$validation_L0 || [string is xdigit -strict [string range $word 2 end]]} {
+ set tags {tag_c_hex}
+ } {
+ set tags {tag_c_hex tag_error}
+ }
+
+ # Float
+ } elseif {[regexp {^\d+\.\d+$} $word]} {
+ set tags {tag_c_float}
+
+ # Invalid number
+ } else {
+ if {$validation_L0} {
+ set tags {tag_error}
+ }
+ }
+
+ # Put tags on text widget
+ foreach tag $tags {
+ $editor tag add $tag \
+ $line_number.[expr {$idx0 + $idx}] \
+ $line_number.[expr {$idx0 + $idx + $len}]
+ }
+ }
+ }
+
+ ## Remove previously defined syntax highlighting tags
+ # @return void
+ proc delete_tags {} {
+ variable editor ;# Widget: Editor text widget
+ variable hightlight_tags ;# Highlight tags definition
+ variable line_start ;# Index of line start
+ variable line_end ;# Index of line end
+
+ # Remove tag error
+ $editor tag remove tag_error $line_start $line_end
+ $editor tag remove tag_error_line $line_start $line_start+1l
+ $editor tag remove c_lang_func $line_start $line_start+1l
+ $editor tag remove c_lang_var $line_start $line_start+1l
+
+ # Remove tags acording to pattern
+ foreach tag $hightlight_tags {
+ $editor tag remove [lindex $tag 0] $line_start $line_end
+ }
+ foreach tag $::ASMsyntaxHighlight::hightlight_tags {
+ $editor tag remove [lindex $tag 0] $line_start $line_end
+ }
+ }
+}
diff --git a/lib/editor/LSTsyntaxhighlight.tcl b/lib/editor/LSTsyntaxhighlight.tcl
new file mode 100755
index 0000000..c108de9
--- /dev/null
+++ b/lib/editor/LSTsyntaxhighlight.tcl
@@ -0,0 +1,443 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements syntax highlighting interface for code listing
+# --------------------------------------------------------------------------
+
+
+namespace eval LSTsyntaxHighlight {
+
+ ## Highlight pattern - highlight tags definition
+ # {
+ # {tag_name ?foreground? ?overstrike? ?italic? ?bold?}
+ # }
+ variable hightlight_tags {
+ {tag_lst_number #000000 0 0 1}
+ {tag_lst_code #000000 0 0 1}
+ {tag_lst_address #000000 0 0 1}
+ {tag_lst_line #000000 0 0 1}
+ {tag_lst_macro #888888 0 0 0}
+ {tag_lst_include #888888 0 0 0}
+ {tag_lst_error #FF0000 0 0 1}
+ {tag_lst_msg #000000 0 0 1}
+ }
+
+ # Fixed messages
+ variable const_messages {
+ {SYMBOL TYPE VALUE LINE}
+ {------------------------------------------------------------}
+ { Line I Addr Code Source}
+ { L I S T O F S Y M B O L S}
+ { =============================}
+ { =====================================================}
+ }
+ # Fixed messages with unknown end
+ variable half_cont_msg {
+ { MCS-51 Family Macro Assembler A S E M - 5 1}
+ { Source File:}
+ { Object File:}
+ { List File:}
+ { register banks used:}
+ {ASSEMBLY COMPLETE,}
+ {ERROR SUMMARY:}
+ {SYMBOL TABLE:}
+ {ASEM-51}
+ }
+
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+ variable line_start ;# Index of line start
+ variable line_end ;# Index of line end
+
+
+ ## Define highlighting text tags in the given text widget
+ # @parm Widget - ID of the target text widget
+ # @parm Int - font size
+ # @parm String - font family
+ # @parm List = default - Highlighting tags definition
+ # @return void
+ proc create_tags args {
+ variable hightlight_tags ;# Highlight tags definition
+
+ # Handle arguments
+ set text_widget [lindex $args 0] ;# text widget
+ set fontSize [lindex $args 1] ;# font size
+ set fontFamily [lindex $args 2] ;# font family
+ if {[llength $args] > 3} { ;# highlighting definition
+ set hightlight [lindex $args 3]
+ } {
+ set hightlight $hightlight_tags
+ }
+
+ # Iterate over highlighting tags definition
+ foreach item $hightlight {
+ # Create array of tag attributes
+ for {set i 0} {$i < 5} {incr i} {
+ set tag($i) [lindex $item $i]
+ }
+
+ # Foreground color
+ if {$tag(1) == {}} {
+ set tag(1) black
+ }
+ # Fonr slant
+ if {$tag(3) == 1} {
+ set tag(3) italic
+ } {
+ set tag(3) roman
+ }
+ # Font weight
+ if {$tag(4) == 1} {
+ set tag(4) bold
+ } {
+ set tag(4) normal
+ }
+
+ # Create the tag in the target text widget
+ $text_widget tag configure $tag(0) \
+ -foreground $tag(1) \
+ -font [ font create \
+ -overstrike $tag(2) \
+ -slant $tag(3) \
+ -weight $tag(4) \
+ -size -$fontSize \
+ -family $fontFamily \
+ ]
+ }
+ }
+
+ ## Perform syntax highlight on the given line in the given widget
+ # @parm Widget Editor - Text widget
+ # @parm Int LineNumber - Number of line to highlight
+ # @return Bool - result
+ proc highlight {Editor LineNumber} {
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+ variable line_start ;# Index of line start
+ variable line_end ;# Index of line end
+ variable const_messages ;# Fixed messages
+ variable half_cont_msg ;# Fixed messages with unknown end
+
+ # Set NS variables
+ set editor $Editor
+ set line_number $LineNumber
+ set line_start $line_number.0
+ set line_end [$editor index [list $line_number.0 lineend]]
+ set line_content [$editor get $line_start $line_end]
+
+ # Remove current highlighting tags
+ if {[string length [string trim $line_content]]} {
+ delete_tags
+ } {
+ return 0
+ }
+
+ # Search for constant messages
+ if {[lsearch -ascii -exact $const_messages $line_content] != -1} {
+ $editor tag add tag_lst_msg $line_start $line_end
+ return 1
+ }
+ foreach msg $half_cont_msg {
+ set idx [string first $msg $line_content]
+ set len [string length $msg]
+ if {!$idx} {
+ $editor tag add tag_lst_msg $line_start $line_number.$len
+ return 1
+ }
+ }
+
+ # Search for error/warning messages
+ if {[regexp {^(\s+@@@@@)|^(\*\*\*\*)|^(\s+\^)} $line_content]} {
+ $editor tag add tag_lst_error $line_start $line_end
+ }
+
+ # Apply some rules, except for AS31
+ if {${::ExternalCompiler::selected_assembler} != 3} {
+ # Line must start eiter with a digit or equation mark
+ if {![regexp {^\s*\=?[[:xdigit:]]} $line_content]} {
+ return 0
+ }
+ if {[regexp {^\s+\d+ error detected} $line_content]} {
+ return 0
+ }
+ # Don't highlight lines in symbol table
+ if {[regexp {^\w+\s?\.} $line_content] || [regexp {^[\w\?]+\t} $line_content]} {
+ return 0
+ }
+ }
+
+ # AS31
+ if {${::ExternalCompiler::selected_assembler} == 3} {
+ set asm_start_index 19
+ as31_highlight 19
+|
+ # ASEM-51
+ } elseif {
+ [regexp {^\s*\d+(\:|\+)} $line_content] ||
+ [regexp {^(\t )|( [\d ]\d )[[:xdigit:]]{4}} $line_content]
+ } then {
+ # Determinate ASM code start index
+ set lineText $line_content
+ set asm_start_index 33
+ set idx -1
+ set cor 0
+ while 1 {
+ set idx [string first "\t" $lineText [expr {$idx + 1}]]
+ if {$idx == -1} {break}
+
+ incr cor [expr {8 - (($idx + $cor) % 8)}]
+ if {$idx + $cor >= 32} {
+ break
+ }
+ }
+ incr asm_start_index -$cor
+
+ # Highlight
+ asem_51_highlight $asm_start_index
+
+ # SDCC assembler -- ASX8051
+ } elseif {[string is digit -strict [string index $line_content 30]]} {
+ sdcc_highlight 32
+ ::R_ASMsyntaxHighlight::highlight $editor $line_number 1 32
+ return 1
+
+ # MCU 8051 IDE Assembler
+ } else {
+ set asm_start_index 31
+ mcu8051ide_highlight $asm_start_index
+ }
+
+ # Highlight assembly code
+ ::ASMsyntaxHighlight::highlight $editor $line_number 1 $asm_start_index
+ return 1
+ }
+
+ ## Remove previously defined syntax highlighting tags
+ # @return void
+ proc delete_tags {} {
+ variable hightlight_tags ;# Highlight tags definition
+ variable editor ;# Widget: Editor text widget
+ variable line_start ;# Index of line start
+ variable line_end ;# Index of line end
+
+ # Remove tags acording to pattern
+ foreach tag $hightlight_tags {
+ $editor tag remove [lindex $tag 0] $line_start $line_end
+ }
+ }
+
+ ## Highlight AS31 code listing line
+ # @parm Int asm_start_index - Assembly code start index
+ # @return void
+ proc as31_highlight {asm_start_index} {
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+ variable line_start ;# Index of line start
+ variable line_end ;# Index of line end
+
+ set idx 0 ;# Regular expression match start index
+
+ # Alter line
+ set line_content [string range $line_content 0 [expr {$asm_start_index - 1}]]
+
+ # Address field present
+ if {[regexp -start $idx -- {\A[[:xdigit:]]{4}\:} $line_content substring]} {
+ # Highlight address
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_address $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+
+ # Highlight processor code
+ if {[regexp -start $idx -- {\A\s+([[:xdigit:]]{2} )*[[:xdigit:]]{2}} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_code $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+ }
+
+ ## Highlight ASEM-51 code listing line
+ # @parm Int asm_start_index - Assembly code start index
+ # @return void
+ proc asem_51_highlight {asm_start_index} {
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+ variable line_start ;# Index of line start
+ variable line_end ;# Index of line end
+
+ set idx 0 ;# Regular expression match start index
+ set foo 0 ;# Foo :)
+
+ # Alter line
+ set line_content [string range $line_content 0 [expr {$asm_start_index - 1}]]
+
+ # Highlight for LST line number
+ if {[regexp -start $idx -- {\A\s*\d+[\:\+]} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_line $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ } {
+ set idx 6
+ set foo 1
+ }
+
+ # Highlight for inclusion level
+ if {[regexp -start $idx -- {\A[ \d]\d} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_include $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+
+ } elseif {$idx == 6 && $foo} {
+ set idx 0
+ }
+
+ ## Address field present
+ if {[regexp -start $idx -- {\A\s*[[:xdigit:]]{2,4}} $line_content substring]} {
+ # Highlight address
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_address $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+
+ ## Constant definition
+ if {[regexp -start $idx -- {\A\s*[NBCDX]} $line_content substring]} {
+ # Highlight letter 'N', 'B', etc. as processor code
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_code $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+
+ # Highlight value of defined constant
+ if {[regexp -start $idx -- {\A\s+[[:xdigit:]]{2,4}} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_number $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+
+ # Highlight processor code
+ } elseif {[regexp -start $idx -- {\A\s+([[:xdigit:]]{2} )*[[:xdigit:]]{2}} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_code $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+ }
+
+ ## Highlight SDCC ASX8051 Assembler code listing line
+ # @parm Int asm_start_index - Assembly code start index
+ # @return void
+ proc sdcc_highlight {asm_start_index} {
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+
+ $editor tag add tag_lst_address $line_number.3 $line_number.7
+ $editor tag add tag_lst_code $line_number.8 $line_number.19
+ $editor tag add tag_lst_number $line_number.20 $line_number.24
+ $editor tag add tag_lst_line $line_number.25 $line_number.31
+ }
+
+ ## Highlight MCU 8051 IDE Assembler code listing line
+ # @parm Int asm_start_index - Assembly code start index
+ # @return void
+ proc mcu8051ide_highlight {asm_start_index} {
+ variable editor ;# Widget: Editor text widget
+ variable line_number ;# Int: Line number
+ variable line_content ;# String: Line content
+ variable line_start ;# Index of line start
+ variable line_end ;# Index of line end
+
+ set idx 0 ;# Regular expression match start index
+
+ # Alter line
+ set line_content [string range $line_content 0 [expr {$asm_start_index - 1}]]
+
+ # Highlight processor code
+ if {[regexp -start $idx -- {\A [[:xdigit:]]{2,}} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_code $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+
+ return
+ }
+
+ ## Address field present -> Address Code ...
+ if {[regexp -start $idx -- {\A[[:xdigit:]]{4}} $line_content substring]} {
+ # Highlight address field
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_address $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+
+ # Highlight processor code
+ if {[regexp -start $idx -- {\A\s+[[:xdigit:]]{2,}} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_code $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+
+ # Address field not present -> " Number"
+ } elseif {[regexp -start $idx -- {\A [[:xdigit:]]{4}} $line_content substring]} {
+ # Highlight number (value of defined constant)
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_number $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+
+ # Highlight inclusion level
+ if {[regexp -start $idx -- {\A\s+\=\d+} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_include $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+ # Highlight line number in code listing
+ if {[regexp -start $idx -- {\A\s*\d+} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_line $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+ # Highlight macro expansion level
+ if {[regexp -start $idx -- {\A\s*\+\d+} $line_content substring]} {
+ set substr_len [string length $substring]
+ set idx [string first $substring $line_content $idx]
+ $editor tag add tag_lst_macro $line_number.$idx $line_number.[expr {$idx + $substr_len}]
+ incr idx $substr_len
+ }
+ }
+}
diff --git a/lib/editor/R_ASMsyntaxhighlight.tcl b/lib/editor/R_ASMsyntaxhighlight.tcl
new file mode 100755
index 0000000..2408bff
--- /dev/null
+++ b/lib/editor/R_ASMsyntaxhighlight.tcl
@@ -0,0 +1,1232 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2008 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements syntax highlighting interface for reallocable assembly
+# --------------------------------------------------------------------------
+
+namespace eval R_ASMsyntaxHighlight {
+ ## COMPILER DIRECTIVES
+ # directives without arguments
+ variable directive_type0 {
+ .ELSE .ENDIF .PAGE .EVEN .ODD
+ }
+ # directives with argument(s) but without any label
+ variable directive_type1 {
+ .OPTSDCC .WORD .DW .INCLUDE .SETDP .GLOBL .IF .ORG .AREA .MODULE .TITLE
+ .SBTTL .ASCII .ASCIS .ASCIZ .RADIX .BYTE .DB .BLKB .BLKW .DS
+ }
+
+ # symbol operators
+ variable expr_symbols {
+ = + - * / > < % & | % ^
+ }
+
+ # control sequencies without any argument
+ variable controls_type0 {
+ NOLIST NOMOD NOOBJECT NOPAGING NOPRINT
+ NOSYMBOLS EJECT LIST PAGING SYMBOLS
+ }
+ # control sequencies with exactly 1 argument
+ variable controls_type1 {
+ PAGEWIDTH PAGELENGTH PRINT TITLE OBJECT DATE INCLUDE
+ }
+ # list of all reserved keywords
+ variable keyword_lists [list \
+ ${::ASMsyntaxHighlight::instructions} \
+ $directive_type0 $directive_type1 \
+ ]
+
+ variable inline_asm ;# Is inline assembler
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable lineStart ;# Index of line start
+ variable lineEnd ;# Index of line end
+ variable data ;# Content of the line
+ variable data_backup ;# Original content of the line
+ variable last_index ;# Last parse index
+ variable last_index_backup ;# Auxiliary variable (some index)
+
+ variable seg_0 ;# 1st field of the line
+ variable seg_1 ;# 2nd field of the line
+ variable seg_2 ;# 3rd field of the line
+ variable seg_0_start ;# Start index of seg_0
+ variable seg_1_start ;# Start index of seg_1
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_0_end ;# End index of seg_0
+ variable seg_1_end ;# End index of seg_1
+ variable seg_2_end ;# End index of seg_2
+
+ variable operand ;# Data of the current operand
+ variable opr_end ;# End index of the current operand
+ variable opr_start ;# Start index of the current operand
+
+ variable validation_L0 1 ;# Bool: Basic validation enabled
+ variable validation_L1 1 ;# Bool: Advancet validation enabled
+
+ ## Define highlighting text tags in the given text widget
+ # @parm Widget - ID of the target text widget
+ # @parm Int - font size
+ # @parm String - font family
+ # @parm List = default - Highlighting tags definition
+ # @return void
+ proc create_tags args {
+ # Handle arguments
+ set text_widget [lindex $args 0] ;# text widget
+ set fontSize [lindex $args 1] ;# font size
+ set fontFamily [lindex $args 2] ;# font family
+ if {[llength $args] > 3} { ;# highlighting definition
+ set hightlight [lindex $args 3]
+ } {
+ set hightlight $::ASMsyntaxHighlight::hightlight_tags
+ }
+
+ # Iterate over highlighting tags definition
+ foreach item $hightlight {
+ # Create array of tag attributes
+ for {set i 0} {$i < 5} {incr i} {
+ set tag($i) [lindex $item $i]
+ }
+
+ # Foreground color
+ if {$tag(1) == {}} {
+ set tag(1) black
+ }
+ # Fonr slant
+ if {$tag(3) == 1} {
+ set tag(3) italic
+ } {
+ set tag(3) roman
+ }
+ # Font weight
+ if {$tag(4) == 1} {
+ set tag(4) bold
+ } {
+ set tag(4) normal
+ }
+
+ # Create the tag in the target text widget
+ $text_widget tag configure $tag(0) \
+ -foreground $tag(1) \
+ -font [font create \
+ -overstrike $tag(2) \
+ -slant $tag(3) \
+ -weight $tag(4) \
+ -size -$fontSize \
+ -family $fontFamily \
+ ]
+ }
+ # Add tag error
+ $text_widget tag configure tag_error -underline 1
+ }
+
+ ## Perform syntax highlight on the given line in the given widget
+ # @parm Widget Editor - Text widget
+ # @parm Int LineNumber - Number of line to highlight
+ # @parm Bool inline_asm - Inline assembler
+ # @parm Int boundary_0 = 0 - Start index
+ # @parm Int boundary_1 = end - End index
+ # @return Bool - result
+ proc highlight args {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable lineStart ;# Index of line start
+ variable lineEnd ;# Index of line end
+ variable inline_asm ;# Is inline assembler
+
+ variable seg_0 {} ;# 1st field of the line
+ variable seg_1 {} ;# 2nd field of the line
+ variable seg_2 {} ;# 3rd field of the line
+ variable seg_0_start ;# Start index of seg_0
+ variable seg_1_start ;# Start index of seg_1
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_0_end ;# End index of seg_0
+ variable seg_1_end ;# End index of seg_1
+ variable seg_2_end ;# End index of seg_2
+
+ variable last_index ;# Last parse index
+ variable data ;# Content of the line
+ variable validation_L0 ;# Bool: Basic validation enabled
+
+ # Parse input arguments
+ set editor [lindex $args 0]
+ set lineNumber [lindex $args 1]
+ set inline_asm [lindex $args 2]
+ set lineStart [lindex $args 3]
+ set lineEnd [lindex $args 4]
+ if {$inline_asm == {}} {
+ set inline_asm 0
+ }
+ if {$lineStart == {}} {
+ set lineStart $lineNumber.0
+ } {
+ set lineStart $lineNumber.$lineStart
+ }
+ if {$lineEnd == {}} {
+ set lineEnd [$editor index "$lineStart lineend"]
+ } {
+ set lineEnd $lineNumber.$lineEnd
+ }
+ if {[lindex $args 3] != {}} {
+ set start_offset [lindex $args 3]
+ } {
+ set start_offset 0
+ }
+
+ set data [$editor get $lineStart $lineEnd]
+ set ::ASMsyntaxHighlight::operands_count 0
+ set ::ASMsyntaxHighlight::opr_types {}
+
+ if {$inline_asm} {
+ delete_tags
+ }
+
+ # check if the line is not empty
+ if {[regexp {^\s*$} $data]} {
+ return 0
+ }
+ set line_length [string length $data]
+ if {$line_length == 0} {
+ return 0
+ }
+
+ # determinate comment field and highlight it (the last field)
+ set comment_start {}
+ if {[regexp {;} $data]} {
+
+ # remove 'string' from the line
+ set comment_data [hide_strings $data]
+
+ if {[regexp {;.*$} $comment_data comment_start]} {
+
+ set comment_start [string length $comment_start]
+ set comment_start [expr {$line_length - $comment_start}]
+
+ # remove comment and trailing space from the line
+ if {$comment_start == 0} {
+ set data {}
+ delete_tags
+ } {
+ set data [string range $data 0 [expr {$comment_start - 1}]]
+ regsub {\s+$} $data {} data
+ }
+
+ incr comment_start $start_offset
+ }
+ }
+
+ # Handle line containing only comment
+ if {![string length $data]} {
+ if {!$inline_asm} {
+ delete_tags
+ }
+ $editor tag add tag_comment $lineNumber.$comment_start $lineEnd
+ return 1
+ }
+
+ # determinate 1st segment of the line
+ regexp {^\s*[^\s:\=]+:?:?} $data seg_0
+ set seg_0_end [string length $seg_0]
+ regsub {^\s+} $seg_0 {} seg_0
+
+ set seg_0_start [string length $seg_0]
+ set seg_0_start [expr {$seg_0_end - $seg_0_start}]
+
+ set data [string replace $data 0 [expr {$seg_0_end - 1}]]
+ incr seg_0_end $start_offset
+ incr seg_0_start $start_offset
+ set last_index $seg_0_end
+
+ #
+ # SYNTAX HIGHLIGHT
+ #
+
+ # delete existing tags within the line
+ if {!$inline_asm} {
+ delete_tags
+ }
+
+ # highlight comment
+ if {$comment_start != {}} {
+ $editor tag add tag_comment $lineNumber.$comment_start $lineEnd
+ }
+ # highlight 1st and 2nd field
+ set seg_0_info [parse_segment $seg_0_start $seg_0_end $seg_0]
+
+ # Conditional parsing with validation
+ switch -- [lindex $seg_0_info 0] {
+ {label} {
+ determinate_segment_1
+ set seg_1_info [parse_segment $seg_1_start $seg_1_end $seg_1]
+ switch -- [lindex $seg_1_info 0] {
+ {label} {
+ put_error_on_segment 1
+ }
+ {instruction} {
+ determinate_segment_2
+ parse_operands
+ }
+ {directive_1} {}
+ {directive_0} {}
+ {unknown} {
+ $editor tag add tag_macro \
+ $lineNumber.$seg_1_start $lineNumber.$seg_1_end
+ if {
+ $validation_L0 &&
+ ([regexp {^\d} $seg_1] || ![regexp {^\w+$} $seg_1])
+ } {
+ put_error_on_segment 1
+ }
+ determinate_segment_2
+ parse_operands
+ }
+ default {
+ put_error_on_segment 1
+ }
+ }
+ }
+ {instruction} {
+ determinate_segment_2
+ parse_operands
+ }
+ {directive_1} {
+ determinate_segment_2
+ if {[string tolower $seg_0] == {.optsdcc}} {
+ $editor tag add tag_string $lineNumber.$seg_0_end $lineEnd
+ } {
+ parse_expressions
+ }
+ }
+ {directive_0} {
+ determinate_segment_1
+ put_error_on_segment 1
+ determinate_segment_2
+ put_error_on_segment 2
+ }
+ {unknown} {
+ determinate_segment_1
+ set seg_1_info [parse_segment $seg_1_start $seg_1_end $seg_1]
+ switch -- [lindex $seg_1_info 0] {
+ {label} {
+ put_error_on_segment 0
+ }
+ {instruction} {
+ put_error_on_segment 0
+ determinate_segment_2
+ parse_operands
+ }
+ {directive_1} {
+ put_error_on_segment 0
+ determinate_segment_2
+ parse_expressions
+ }
+ {directive_0} {
+ put_error_on_segment 0
+ determinate_segment_2
+ put_error_on_segment 2
+ }
+ {unknown} {
+ }
+ {assignment} {
+ determinate_segment_2
+ incr seg_0_start -1
+ parse_expressions
+ $editor tag add tag_constant $lineNumber.$seg_0_start $lineNumber.$seg_0_end
+ }
+ default {
+ }
+ }
+ }
+ default {}
+ }
+
+ return 1
+ }
+
+ ## Remove previously defined syntax highlighting tags
+ # @return void
+ proc delete_tags {} {
+ variable editor ;# ID of the text widget
+ variable lineStart ;# Index of line start
+ variable lineEnd ;# Index of line end
+
+ set lineStart_truestart [$editor index [list $lineStart linestart]]
+
+ # Remove tag error
+ $editor tag remove tag_error $lineStart_truestart $lineEnd
+
+ # Remove tags acording to pattern
+ foreach tag $::ASMsyntaxHighlight::hightlight_tags {
+ $editor tag remove [lindex $tag 0] $lineStart_truestart $lineEnd
+ }
+ }
+
+ ## Take back extraction of segment 1
+ # @return void
+ proc determinate_segment_1_take_back {} {
+ variable data ;# Content of the line
+ variable data_backup ;# Original content of the line
+ variable last_index ;# Last parse index
+ variable last_index_backup ;# Auxiliary variable (some index)
+
+ set data $data_backup
+ set last_index $last_index_backup
+ }
+
+ ## Extract segment 1 from the line
+ # @return void
+ proc determinate_segment_1 {} {
+ variable seg_1 ;# 2nd field of the line
+ variable seg_1_start ;# Start index of seg_1
+ variable seg_1_end ;# End index of seg_1
+ variable last_index ;# Last parse index
+ variable data ;# Content of the line
+ variable data_backup ;# Original content of the line
+ variable last_index_backup ;# Auxiliary variable (some index)
+
+ # Line is empty
+ if {![regexp {^\s*[^\s\.]+} $data seg_1]} {
+ set seg_1 {}
+ set seg_1_end $last_index
+ set seg_1_start $last_index
+
+ # Line is not empty
+ } {
+ set data_backup $data
+ set last_index_backup $last_index
+
+ set seg_1_end [string length $seg_1]
+ set data [string replace $data 0 $seg_1_end]
+ incr seg_1_end $last_index
+
+ regsub {^\s+} $seg_1 {} seg_1
+ set seg_1_start [string length $seg_1]
+ set seg_1_start [expr {$seg_1_end - $seg_1_start}]
+
+ set last_index $seg_1_end
+ incr last_index
+ }
+ }
+
+ ## Extract segment 2 from the line
+ # @return void
+ proc determinate_segment_2 {} {
+ variable seg_2 ;# 3rd field of the line
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_2_end ;# End index of seg_2
+ variable last_index ;# Last parse index
+ variable data ;# Content of the line
+
+ # determinate the last segment of the line
+ set seg_2_start $last_index
+ if {[regexp {^\s+} $data space]} {
+ incr seg_2_start [string length $space]
+ }
+ regsub {^\s+} $data {} seg_2
+ regsub {\s+$} $seg_2 {} seg_2
+ set seg_2_end [string length $seg_2]
+ incr seg_2_end $last_index
+ set data {}
+ }
+
+ ## Shorthand for 'parse_expression $seg_2 $seg_2_start $seg_2_end'
+ # @return void
+ proc parse_expressions {} {
+ variable seg_2 ;# 3rd field of the line
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_2_end ;# End index of seg_2
+
+ parse_expression $seg_2 $seg_2_start $seg_2_end
+ }
+
+ ## Parse given segment, highlight it and determinate its type
+ # @parm Int start - start column
+ # @parm int end - end column
+ # @parm String segment_data - content of segment to parse
+ # @return List - {segment_type expression_length} or {segment_type {}} or {{} {}}
+ proc parse_segment {start end segment_data} {
+ variable controls_type0 ;# control sequencies without any argument
+ variable controls_type1 ;# control sequencies with exactly 1 argument
+
+ variable inline_asm ;# Is inline assembler
+ variable keyword_lists ;# list of all reserved keywords
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable lineStart ;# Index of line start
+ variable lineEnd ;# Index of line end
+ variable data ;# Content of the line
+ variable validation_L0 ;# Bool: Basic validation enabled
+
+ # Local variables
+ set seg_type {} ;# segment type
+ set expr_len 0 ;# length of expression
+
+ # Handle empty segments
+ if {$segment_data == {}} {
+ return "$seg_type $expr_len"
+ }
+
+ # Convert segment data to uppre case (patterns are uppper-case)
+ set segment_data [string toupper $segment_data]
+
+ # Try to determinate segment type and perform highlight
+ foreach keyword_list $keyword_lists \
+ tag {tag_instruction tag_directive tag_directive} \
+ type {instruction directive_0 directive_1} {
+ if {[lsearch -ascii -exact $keyword_list $segment_data] != -1} {
+ $editor tag add $tag $lineNumber.$start $lineNumber.$end
+ set seg_type $type
+ break
+ }
+ }
+
+ if {$seg_type == {}} {
+ if {[regexp -nocase {^[^\s]+\:\:?$} $segment_data]} {
+ $editor tag add tag_label $lineNumber.$start $lineNumber.$end
+ set seg_type label
+ } elseif {$segment_data == {=} || $segment_data == {==}} {
+ $editor tag add tag_symbol $lineNumber.$start $lineNumber.$end
+ set seg_type {assignment}
+ } {
+ set seg_type {unknown}
+ }
+ }
+
+ # Return result
+ return "$seg_type $expr_len"
+ }
+
+ ## Tag the given segment as error
+ # @parm Int segment_number - number of the target segment
+ # @return void
+ proc put_error_on_segment {segment_number} {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable seg_0_start ;# Start index of seg_0
+ variable seg_1_start ;# Start index of seg_1
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_0_end ;# End index of seg_0
+ variable seg_1_end ;# End index of seg_1
+ variable seg_2_end ;# End index of seg_2
+
+ return
+
+ if {!$validation_L0} {
+ return
+ }
+
+ # Determinate start and end index
+ switch -- $segment_number {
+ 0 {
+ set start $seg_0_start
+ set end $seg_0_end
+ }
+ 1 {
+ set start $seg_1_start
+ set end $seg_1_end
+ }
+ 2 {
+ set start $seg_2_start
+ set end $seg_2_end
+ }
+ }
+ }
+
+ ## Parse attributes in defintion of macro instruction
+ # @retunr void
+ proc parse_arguments {} {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_2 ;# 3rd field of the line
+ variable validation_L0 ;# Bool: Basic validation enabled
+
+ if {[regexp {^\s*$} $seg_2]} {return 0}
+
+ while 1 {
+ # Handle redutant commas
+ while 1 {
+ if {![regexp {^\s*\,} $seg_2]} {break}
+
+ set space_len 0
+ if {[regexp {^\s+} $seg_2 space_len]} {
+ set space_len [string length $space_len]
+ }
+
+ incr seg_2_start $space_len
+ set seg_2 [string range $seg_2 [expr {$space_len + 1}] end]
+
+ $editor tag add tag_oper_sep \
+ $lineNumber.$seg_2_start \
+ $lineNumber.[expr {$seg_2_start + 1}]
+
+ incr seg_2_start
+ }
+
+ # Determinate argument
+ if {![regexp {^[^\,]+} $seg_2 argument]} {break}
+ set argument_len_org [string length $argument]
+ set seg_2 [string range $seg_2 $argument_len_org end]
+ set argument [string trimleft $argument]
+ set argument_len [string length $argument]
+ incr seg_2_start [expr {$argument_len_org - $argument_len}]
+
+ # Highlight argument
+ $editor tag add tag_constant \
+ $lineNumber.$seg_2_start \
+ $lineNumber.[expr {$seg_2_start + $argument_len}]
+ set argument [string trimright $argument]
+
+ incr seg_2_start $argument_len
+
+ # highlight argument separator
+ if {[string index $seg_2 0] == {,}} {
+ set sep_end $seg_2_start
+ incr sep_end
+ $editor tag add tag_oper_sep $lineNumber.$seg_2_start $lineNumber.$sep_end
+
+ incr seg_2_start
+ set seg_2 [string range $seg_2 1 end]
+ }
+ }
+ }
+
+ ## Highlight all operands (segment 2) and their separators
+ # @return void
+ proc parse_operands {} {
+
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable seg_2_start ;# Start index of seg_2
+ variable seg_2 ;# 3rd field of the line
+
+ variable operand ;# Data of the current operand
+ variable opr_end ;# End index of the current operand
+ variable opr_start ;# Start index of the current operand
+
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable validation_L1 ;# Bool: Advancet validation enabled
+
+ if {[regexp {^\s*$} $seg_2]} {return 0}
+ set ::ASMsyntaxHighlight::operands_count 0
+ set ::ASMsyntaxHighlight::opr_types {}
+
+ # split data into single operands
+ set i 0
+ set last_index $seg_2_start
+ set original_data $seg_2
+ set data [hide_strings $seg_2]
+
+ while 1 {
+ # Handle redutant commas
+ while 1 {
+ if {![regexp {^\s*\,} $data]} {break}
+
+ set space_len 0
+ if {[regexp {^\s+} $data space_len]} {
+ set space_len [string length $space_len]
+ }
+ incr last_index $space_len
+
+ set data [string range $data [expr {$space_len + 1}] end]
+ set original_data [string range $original_data [expr {$space_len + 1}] end]
+
+ $editor tag add tag_oper_sep \
+ $lineNumber.$last_index \
+ $lineNumber.[expr {$last_index + 1}]
+
+ incr last_index
+ }
+
+ # gain operand data
+ if {![regexp {^[^\,]+} $data operand]} {break}
+ set operand_len [string length $operand]
+ set data [string range $data $operand_len end]
+ set operand [string range $original_data 0 [expr {$operand_len - 1}]]
+ set original_data [string range $original_data $operand_len end]
+
+ # determinate start index
+ if {[regexp {^\s+} $operand space]} {
+ set space_len [string length $space]
+ set opr_start [expr {$last_index + $space_len}]
+ set operand [string range $operand $space_len end]
+ } {
+ set opr_start $last_index
+ }
+
+ # determinate end index
+ if {[regexp {\s+$} $operand space]} {
+ set space_len [string length $space]
+ set opr_end [expr {$operand_len - $space_len}]
+ set operand [string range $operand 0 $opr_end]
+ } {
+ set opr_end $operand_len
+ }
+ incr opr_end $last_index
+ incr last_index $operand_len
+
+ set operand [string trimright $operand "\t "]
+ if {$validation_L1} {
+ add_aperand_to__opr_types
+ }
+ highlight_operand
+ incr ::ASMsyntaxHighlight::operands_count
+
+ # highlight operand separator
+ if {[string index $data 0] == {,}} {
+ set sep_end $last_index
+ incr sep_end
+ $editor tag add tag_oper_sep $lineNumber.$last_index $lineNumber.$sep_end
+
+ incr last_index
+ set data [string range $data 1 end]
+ set original_data [string range $original_data 1 end]
+ }
+
+ incr i
+ }
+ }
+
+ ## Append current operand (variable operand) to list of operand types in ::ASMsyntaxHighlight::opr_types
+ # Purpose of this function is to enable searching in instruction
+ #+ details panel while this syntaxt highlight pattern is used
+ # @return void
+ proc add_aperand_to__opr_types {} {
+ variable operand ;# Data of the current operand
+
+ set opr [string toupper $operand]
+
+ switch -- [string index $opr 0] {
+ {#} {lappend ::ASMsyntaxHighlight::opr_types {#}}
+ {/} {lappend ::ASMsyntaxHighlight::opr_types {/}}
+ {@} {lappend ::ASMsyntaxHighlight::opr_types $opr}
+ default {
+ if {[lsearch -ascii -exact {R0 R1 R2 R3 R4 R5 R6 R7 DPTR A AB C} $opr] != -1} {
+ lappend ::ASMsyntaxHighlight::opr_types $opr
+ } {
+ lappend ::ASMsyntaxHighlight::opr_types {D}
+ }
+ }
+ }
+ }
+
+ ## Highlight current operand
+ # @return void
+ proc highlight_operand {} {
+ variable editor ;# ID of the text widget
+ variable operand ;# Data of the current operand
+ variable opr_end ;# End index of the current operand
+ variable opr_start ;# Start index of the current operand
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable inline_asm ;# Is inline assembler
+ variable lineNumber ;# Number of current line
+
+ ## Determinate addressing type
+ set addr_type [string index $operand 0]
+
+ # Immediate adresing
+ if {$addr_type == {#}} {
+ set operand [string range $operand 1 end]
+
+ # Immediate char value
+ if {[string index $operand 0] == {'} && [string index $operand end] == {'}} {
+ set len [string length $operand]
+
+ if {$len > 3} {
+ put_tag_on_operand tag_string
+ } {
+ put_tag_on_operand tag_imm_char
+ }
+
+ # Label in inline assembler
+ } elseif {[regexp {^\d+\$$} $operand]} {
+ put_tag_on_operand tag_imm_constant
+
+ # Operand has no value => incorrect operand
+ } elseif {[regexp { |\(|\)|\+|\-|\%|\=|\>|\<|\*|\/} $operand]} {
+ parse_expression $operand $opr_start $opr_end
+ $editor tag add tag_symbol \
+ $lineNumber.$opr_start $lineNumber.$opr_start+1c
+
+ } elseif {
+ $validation_L0 &&
+ ([string length $operand] == 0 || ![regexp {^[\w\.\\]+$} $operand])
+ } {
+# put_tag_on_operand tag_error
+
+ # Operand value determinated successfully
+ } else {
+ parse_operand_auxiliary2 {
+ tag_imm_unknown tag_imm_hex tag_imm_dec
+ tag_imm_oct tag_imm_bin tag_imm_char
+ tag_imm_constant tag_string
+ }
+ }
+
+ # Indirect adresing
+ } elseif {$addr_type == {@}} {
+ set operand [string range $operand 1 end]
+ put_tag_on_operand tag_indirect
+
+ # Check for operand validity
+ if {!$validation_L0} {return}
+ set operand [string toupper $operand]
+
+ # Direct bit adresing
+ } elseif {$addr_type == {/}} {
+ set operand [string range $operand 1 end]
+
+ if {[regexp {\(|\)|\+|\-|\%|\=|\>|\<|\*|\/} $operand]} {
+ parse_expression $operand $opr_start $opr_end
+ $editor tag add tag_symbol \
+ $lineNumber.$opr_start $lineNumber.$opr_start+1c
+
+ } elseif {
+ $validation_L0 &&
+ ([string length $operand] == 0 || ![regexp {^'?[\w\.]+'?$} $operand])
+ } {
+
+ # Operand has no value => incorrect operand
+# put_tag_on_operand tag_error
+
+ } else {
+ parse_operand_auxiliary $::ASMsyntaxHighlight::spec_bits {
+ tag_unknown_base tag_hex tag_dec
+ tag_oct tag_bin tag_char
+ tag_constant tag_string
+ }
+ }
+
+ # Another kind of direct adresing
+ } else {
+ parse_operand_auxiliary $::ASMsyntaxHighlight::spec_registers {
+ tag_unknown_base tag_hex tag_dec
+ tag_oct tag_bin tag_char
+ tag_constant tag_string
+ }
+ }
+ }
+
+ ## Auxiliary procedure for procedure highlight_operand
+ # @parm List SFR_set - List of SFR keywords
+ # @parm List tag_list - List of tags for procedure parse_operand_auxiliary2
+ # @return void
+ proc parse_operand_auxiliary {SFR_set tag_list} {
+ variable operand ;# Data of the current operand
+
+ # SFR
+ if {[lsearch -ascii -exact $SFR_set [string toupper $operand]] != -1} {
+ put_tag_on_operand tag_sfr
+
+ # Something else than SFR
+ } {
+ parse_operand_auxiliary2 $tag_list
+ }
+ }
+
+ ## Auxiliary procedure for procedures highlight_operand and parse_operand_auxiliary
+ # @parm List tag_list - list of text tags (see code)
+ # @return void
+ proc parse_operand_auxiliary2 {tag_list} {
+ variable operand ;# Data of the current operand
+ variable opr_start ;# Start index of the current operand
+ variable opr_end ;# End index of the current operand
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable inline_asm ;# Is inline assembler
+
+ # Label
+ if {[regexp {^\d+\$$} $operand]} {
+ put_tag_on_operand [lindex $tag_list 6]
+
+ # Expression
+ } elseif {[regexp {\(|\)|\+|\-|\%|\=|\>|\<|\*|\/} $operand]} {
+ parse_expression $operand $opr_start $opr_end
+
+ # Dot notation (bit addressing)
+ } elseif {[regexp {^\w+\.\w+$} $operand]} {
+ set opr [split $operand {.}]
+ set operand [lindex $opr 0]
+
+ set opr_true_end $opr_end
+ set opr_end $opr_start
+ incr opr_end [string length $operand]
+
+ parse_operand_auxiliary $::ASMsyntaxHighlight::spec_registers $tag_list
+
+ set opr_start [expr {$opr_end + 1}]
+ $editor tag add tag_symbol $lineNumber.$opr_end $lineNumber.$opr_start
+
+ set opr_end $opr_true_end
+ set operand [lindex $opr 1]
+
+ parse_operand_auxiliary2 $tag_list
+
+ # Direct value
+ } elseif {[regexp {^(\d|')} $operand]} {
+ # gain information about the openand (radix and decimal value)
+ set opr_info [which_radix 0 $operand]
+ set opr_base [lindex $opr_info 0]
+ set opr_in_dec [lindex $opr_info 1]
+
+ # Radix determinated incorrectly => unknown number
+ if {$opr_base == {}} {
+ put_tag_on_operand [lindex $tag_list 0]
+
+ # Radix determinated correctly - continue normaly
+ } {
+ # highlight acording to numeric base
+ switch -- $opr_base {
+ {hex} {put_tag_on_operand [lindex $tag_list 1]}
+ {dec} {put_tag_on_operand [lindex $tag_list 2]}
+ {oct} {put_tag_on_operand [lindex $tag_list 3]}
+ {bin} {put_tag_on_operand [lindex $tag_list 4]}
+ {ascii} {put_tag_on_operand [lindex $tag_list 5]}
+ {string} {put_tag_on_operand [lindex $tag_list 7]}
+ }
+ }
+
+ # defined by a symbolic name
+ } {
+ put_tag_on_operand [lindex $tag_list 6]
+ }
+ }
+
+ ## Highlight current operand by the given tag
+ # @parm String tag_name - tag name
+ # @return void
+ proc put_tag_on_operand {tag_name} {
+ variable lineNumber ;# Number of current line
+ variable opr_end ;# End index of the current operand
+ variable opr_start ;# Start index of the current operand
+ variable editor ;# ID of the text widget
+
+ $editor tag add $tag_name $lineNumber.$opr_start $lineNumber.$opr_end
+ }
+
+ ## Determinate numeric base of the given number
+ # @parm Bool norange - 1 == determinate decimal value (sometimes...) and validate it (see code)
+ # @parm String number - number to analyze
+ # @return List - {base decimal_value} or {base "error"}
+ proc which_radix {norange number} {
+ set original_len [string length $number]
+ set len [string length [string trimleft $number {0}]]
+ if {$original_len > 1 && $len == 1} {
+ incr len
+ }
+ incr len -1
+ set radix [string index $number end]
+ set number [string range $number 0 {end-1}]
+ set dec_val error
+ set base {}
+
+ # Character or string
+ if {$radix == {'}} {
+ if {[string index $number 0] == {'}} {
+ set number [string range $number 1 end]
+
+ set base ascii
+ if {[string length $number] == 1} {
+ set dec_val 0
+
+ } elseif {[string length $number] > 1} {
+ set base string
+ set dec_val 0
+ }
+ }
+
+ # Prefix hexadecimal notation
+ } elseif {[string range $number 0 1] == {0x} || [string range $number 0 1] == {0X}} {
+ append number $radix
+ set base hex
+ if {[regexp {^0[Xx][A-Fa-f0-9]+$} $number]} {
+ set dec_val 0
+ }
+
+ # Regular numbers
+ } else {
+ set radix [string tolower $radix]
+ switch -- $radix {
+ {h} { ;# Hexadecimal
+ set base hex
+ if {$norange || ($len <= 4 && $len >= 1)} {
+ if {[regexp {^[A-Fa-f0-9]*$} $number]} {
+ set dec_val 0
+ }
+ }
+ }
+ {d} { ;# Decimal
+ set base dec
+ if {$norange || ($len <= 5 && $len >= 1)} {
+ if {[regexp {^[0-9]*$} $number]} {
+ set dec_val $number
+ }
+ }
+ }
+ {o} { ;# Octal
+ set base oct
+ if {$norange} {
+ if {[regexp {^[0-7]*$} $number]} {
+ set dec_val 0
+ }
+ } elseif {$len <= 6 && $len >= 1} {
+ if {[regexp {^[0-7]*$} $number]} {
+ if {$len != 3} {
+ set dec_val 0
+ } {
+ if {[string index $number 0] <= 3} {
+ set dec_val 0
+ }
+ }
+ }
+ }
+ }
+ {q} { ;# Octal
+ set base oct
+ if {$norange} {
+ if {[regexp {^[0-7]*$} $number]} {
+ set dec_val 0
+ }
+ } elseif {$len <= 6 && $len >= 1} {
+ if {[regexp {^[0-7]*$} $number]} {
+ if {$len != 3} {
+ set dec_val 0
+ } {
+ if {[string index $number 0] <= 3} {
+ set dec_val 0
+ }
+ }
+ }
+ }
+ }
+ {b} { ;# Binary
+ set base bin
+ if {$norange || ($len <= 16 && $len >= 1)} {
+ if {[regexp {^[01]*$} $number]} {
+ set dec_val 0
+ }
+ }
+ }
+ default { ;# Default
+ set dec_val {}
+ }
+ }
+ }
+
+ # done ...
+ return "$base $dec_val"
+ }
+
+ ## Highlight expressions (eg. '( 10d - X MOD 55h)')
+ # @parm String data - expression to highlight
+ # @parm Int start_index - expresssion start index
+ # @parm Int end_index - expresssion end index
+ # @return void
+ proc parse_expression {data start_index end_index} {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable expr_symbols ;# symbol operators
+ variable validation_L0 ;# Bool: Basic validation enabled
+ variable validation_L1 ;# Bool: Advancet validation enabled
+
+ # Adjust data to fit the given boundaries
+ set data_len [string length $data]
+ set dif [expr {$end_index - $start_index - $data_len}]
+ if {$dif != 0} {
+ set space [string repeat { } $dif]
+ set data $space$data
+ }
+
+ # Remove strings
+ set e_idx 0
+ while 1 {
+ if {![regexp -start $e_idx -- {'[^']*'} $data string_data]} {
+ break
+ }
+ set len [string length $string_data]
+ set s_idx [string first {'} $data $e_idx]
+ set e_idx [expr {$s_idx + $len}]
+
+ if {$len > 2} {
+ set data [string replace $data \
+ [expr {$s_idx + 1}] [expr {$e_idx - 2}] \
+ [string repeat { } [expr {$len - 2}]] \
+ ]
+ }
+ }
+
+ # remove and highlight '('
+ set opended_par 0
+ while 1 {
+ set symbol_idx [string first {(} $data]
+ if {$symbol_idx == -1} {break}
+
+ incr opended_par
+ set data [string replace $data $symbol_idx $symbol_idx { }]
+ incr symbol_idx $start_index
+ $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.[expr {$symbol_idx + 1}]
+ }
+ # remove and highlight ')'
+ while 1 {
+ set symbol_idx [string first {)} $data]
+ if {$symbol_idx == -1} {break}
+
+ incr opended_par -1
+ set data [string replace $data $symbol_idx $symbol_idx { }]
+ incr symbol_idx $start_index
+ $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.[expr {$symbol_idx + 1}]
+ }
+
+ # highlight expr. symbols (+1 chars) and remove them from the string
+ set adjusted_data [string toupper $data]
+ regsub {\t} $adjusted_data { } adjusted_data
+ # highlight expr. symbols (1 char) and remove them from the string
+ foreach symbol $expr_symbols {
+ while 1 {
+ set symbol_idx [string first $symbol $data]
+ if {$symbol_idx == -1} {break}
+ set original_symbol_idx $symbol_idx
+ set symbol_idx_org_1 [expr {$symbol_idx + 1}]
+
+ set data [string replace $data $symbol_idx $symbol_idx { }]
+ incr symbol_idx $start_index
+ set symbol_idx_1 [expr {$symbol_idx + 1}]
+ $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.$symbol_idx_1
+ }
+ }
+
+ # highlight other parts
+ set last_index $start_index
+ set original_data $data
+ set data [hide_strings $data]
+ while 1 {
+ if {![regexp {[^\s]+} $data value]} {break}
+
+ set value_S_idx [string first $value $data]
+ set value_len [string length $value]
+ set value_E_idx $value_len
+ incr value_E_idx $value_S_idx
+
+ set value [string range $original_data $value_S_idx $value_E_idx]
+
+ set data [string range $data $value_E_idx end]
+ set original_data [string range $original_data $value_E_idx end]
+
+ set tmp_idx $value_E_idx
+ incr value_S_idx $last_index
+ incr value_E_idx $last_index
+ incr last_index $tmp_idx
+
+ highlight_value [string trimright $value] $value_S_idx $value_E_idx
+ }
+ }
+
+ ## Highlight constant values
+ # @parm String data - string to highlight
+ # @parm Int start_index - start index
+ # @parm Int end_index - end index
+ # @return void
+ proc highlight_value {data start_index end_index} {
+ variable editor ;# ID of the text widget
+ variable lineNumber ;# Number of current line
+ variable validation_L0 ;# Bool: Basic validation enabled
+
+ # Dot notation -- bit addressing
+ if {[regexp {^\w+\.\w+$} $data]} {
+ set data [split $data {.}]
+
+ set end_index_org $end_index
+ set end_index $start_index
+ incr end_index [string length [lindex $data 0]]
+ highlight_value [lindex $data 0] $start_index $end_index
+
+ $editor tag add tag_symbol $lineNumber.$end_index $lineNumber.[expr {$end_index + 1}]
+
+ incr end_index
+ highlight_value [lindex $data 1] $end_index $end_index_org
+ return
+
+ } elseif {[regexp {^(\d|')} $data]} {
+ # Gain information about the value
+ set opr_info [which_radix 1 $data]
+ set opr_base [lindex $opr_info 0]
+ set opr_in_dec [lindex $opr_info 1]
+
+ # Highlight value acording to info
+ if {$opr_base == {}} {
+ $editor tag add tag_unknown_base $lineNumber.$start_index $lineNumber.$end_index
+ return
+ }
+
+ # Highlight acording to numeric base
+ switch -- $opr_base {
+ {hex} { ;# Hexadecimal
+ $editor tag add tag_hex $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {dec} { ;# Decimal
+ $editor tag add tag_dec $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {oct} { ;# Octal
+ $editor tag add tag_oct $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {bin} { ;# Binary
+ $editor tag add tag_bin $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {ascii} { ;# Char
+ $editor tag add tag_char $lineNumber.$start_index $lineNumber.$end_index
+ }
+ {string} { ;# String
+ $editor tag add tag_string $lineNumber.$start_index $lineNumber.$end_index
+ }
+ }
+ return
+ }
+
+ # Constant
+ $editor tag add tag_constant $lineNumber.$start_index $lineNumber.$end_index
+ }
+
+ ## Replace all single quoted string with underscores (''abc'' -> '_____')
+ # @parm String data - input data
+ # @return String - output data
+ proc hide_strings {data} {
+ # Return string which dowsn't contain '''
+ if {[string first {'} $data] == -1} {return $data}
+
+ # Perform replacement
+ while 1 {
+ if {![regexp {'[^']*'} $data string]} {
+ break
+ }
+ regsub {'[^']*'} $data [string repeat {_} \
+ [string length $string] \
+ ] data
+ }
+
+ # Return result
+ return $data
+ }
+}
diff --git a/lib/editor/autocompletion.tcl b/lib/editor/autocompletion.tcl
new file mode 100755
index 0000000..a5c9234
--- /dev/null
+++ b/lib/editor/autocompletion.tcl
@@ -0,0 +1,838 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements autocompletion related procedures
+# This file should be loaded into class Editor in file "editor.tcl"
+# --------------------------------------------------------------------------
+
+
+## Refresh list of avaliable SFR's and SFB's on the target uC
+ # @return void
+public method refresh_avaliable_SFR {} {
+ set autocompletion_list(4) [lsort -ascii [$parentObject cget -avaliable_SFR]]
+}
+
+
+## Clear list of words for autocompletion window
+ # @return void
+public method clear_autocompletion_list {} {
+ foreach i {0 1 2 3 7} {
+ set autocompletion_list($i) {}
+ }
+ $parentObject rightPanel_clear_symbol_list
+}
+
+## Delete some string in the editor
+ # It's important to delete strings in this way in order to keep
+ #+ autocompletion list up to date
+ # @parm TextIndex start_index - Start
+ # @parm TextIndex end_index - End
+ # @return void
+public method detete_text_in_editor {start_index end_index} {
+ autocompletion_maybe_important_change $start_index $end_index
+ $editor delete $start_index $end_index
+}
+
+## Inform autocompletion mechanism about possibly deleted symbol
+ # @parm TextIndex start_index - Begining on area to to analyze
+ # @parm TextIndex end_index - End on area to to analyze
+ # @return void
+public method autocompletion_maybe_important_change {start_index end_index} {
+ set start_index [$editor index $start_index]
+ set end_index [$editor index $end_index]
+
+ # Detect new symvol
+ foreach tag_name {tag_label tag_constant_def c_lang_var tag_macro_def c_lang_func} \
+ index {0 1 2 3 7} \
+ {
+ set linestart_tmp [list $start_index linestart]
+ while {1} {
+ # Detect ...
+ set range [$editor tag nextrange $tag_name \
+ $linestart_tmp [list $end_index lineend] \
+ ]
+ set linestart_tmp [lindex $range 1]
+
+ # Nothing detected ...
+ if {![llength $range]} {
+ break
+ }
+
+ # Get symbol name
+ set string [$editor get [lindex $range 0] [lindex $range 1]]
+
+ # Adjust case (all to uppercase except C lang. symbols)
+ if {$index != 2 && $index != 7} {
+ set string [string toupper $string]
+ }
+
+ # Remove semicolon from labels in assembly
+ if {!$index} {
+ set string [string replace $string end end]
+ }
+
+ # Adjust autocompletion list
+ set idx [lsearch -ascii -exact $autocompletion_list($index) $string]
+ if {$idx != -1} {
+ $parentObject rightPanel_adjust_symbol_list \
+ all $string $index 0
+
+ set autocompletion_list($index) \
+ [lreplace $autocompletion_list($index) $idx $idx]
+ }
+ }
+ }
+}
+
+## Significant part of autocompletion mechanism related to C language
+ # Creates tags "c_lang_var" and "c_lang_func" to mark C symbols
+ # @parm Int line_number - Line number
+ # @return void
+private method autocompletion_c_syntax_analyze {line_number} {
+ # Find word after data type specification
+ set prev_range {}
+ set range [list $line_number.0 $line_number.0]
+ while {1} {
+ set range [$editor tag nextrange tag_c_data_type \
+ [lindex $range 1] [list $line_number.0 lineend] \
+ ]
+ if {![llength $range]} {
+ break
+ }
+ set prev_range $range
+
+ # Nothing found -> abort
+ if {![llength $prev_range]} {
+ return
+ }
+
+ # Gain details about the word
+ set range $prev_range
+ set line [$editor get $line_number.0 [list $line_number.0 lineend]]
+ set start [lindex [split [lindex $range 1] {.}] 1]
+ set end 0
+ set string {}
+
+ # Find part which consist of alfanumeric characters
+ if {![regexp -start $start -- {\w+} $line string]} {
+ return
+ }
+ set start [string first $string $line $start]
+ set end [expr {$start + [string length $string]}]
+
+ # Mark the word
+ if {[regexp -start $end -- {\s*\(} $line]} {
+ $editor tag add c_lang_func $line_number.$start $line_number.$end
+ } {
+ $editor tag add c_lang_var $line_number.$start $line_number.$end
+ }
+ }
+}
+
+## Inform autocompletion mechanism about possibly newly defined symbol
+ # @parm Int line_number - Line number
+ # @return void
+public method manage_autocompletion_list {line_number} {
+ # Detect new symbol
+ foreach tag_name {tag_label tag_constant_def c_lang_var tag_macro_def c_lang_func} \
+ index {0 1 2 3 7} \
+ {
+ set linestart_tmp $line_number.0
+ while {1} {
+ # Detect ...
+ set range [$editor tag nextrange $tag_name \
+ $linestart_tmp [list $line_number.0 lineend] \
+ ]
+ set linestart_tmp [lindex $range 1]
+
+ # Nothing detected ...
+ if {![llength $range]} {
+ break
+ }
+
+ # Get symbol name
+ set string [$editor get [lindex $range 0] [lindex $range 1]]
+
+ # Check if it not already defined
+ if {$index != 2 && $index != 7} {
+ set string [string toupper $string]
+ } else {
+ if {
+ [lsearch -ascii -exact ${::CsyntaxHighlight::data_types} $string] != -1
+ ||
+ [lsearch -ascii -exact ${::CsyntaxHighlight::keywords} $string] != -1
+ } then {
+ return
+ }
+ }
+
+ # Remove semicolon from labels in assembly
+ if {!$index} {
+ set string [string replace $string end end]
+ }
+
+ # Append to the autocompletion list
+ if {[lsearch -ascii -exact $autocompletion_list($index) $string] == -1} {
+ lappend autocompletion_list($index) $string
+
+ $parentObject rightPanel_adjust_symbol_list \
+ $line_number $string $index 1
+ }
+ }
+ }
+
+ # Sort autocompletion list every 20nd iteration
+ incr macl_invocations
+ if {$macl_invocations > 20} {
+ set macl_invocations 0
+ foreach i {0 1 2 3 7} {
+ set autocompletion_list($i) [lsort -ascii $autocompletion_list($i)]
+ }
+ }
+}
+
+## Invoke popup menu completon window
+ # @parm Bool mode - Mode of autocompletion
+ # 0 - Instructions, directives and macro's
+ # 1 - Constants and labels
+ # 2 - C functions
+ # 3 - Indirect values
+ # 4 - Doxygen tags
+ # @parm String str - Incomplite instruction or directive
+ # @parm Int x - Relative X position of the popup window (relative to editor)
+ # @parm Int y - Relative Y position of the popup window (relative to editor)
+ # @return void
+private method invoke_completion_popup_window {mode start_idx end_idx} {
+ if {$invoke_com_win_in_p} {
+ update
+ return
+ }
+ set invoke_com_win_in_p 1
+
+ set bbox [$editor bbox $start_idx]
+ if {![llength $bbox]} {
+ set invoke_com_win_in_p 0
+ return
+ }
+ set x [lindex $bbox 0]
+ set y [expr {[lindex $bbox 1] + [lindex $bbox 3]}]
+ set str [$editor get $start_idx $end_idx]
+
+ if {![string length $str]} {
+ close_completion_popup_window
+ set invoke_com_win_in_p 0
+ return
+ }
+
+ set loading 0
+ if {!$comp_win_loading_in_p && [string first 0 $highlighted_lines 1] > 0} {
+ set loading 1
+ set ::X::compilation_progress 0
+ set comp_win_loading_max [highlight_all_count_of_iterations]
+ }
+
+ # Close current window if any
+ close_completion_popup_window
+
+ # Adjust arguments
+ set str_org $str
+
+ # Set opened flag
+ set completion_win_opened 1
+ set do_not_hide_comp_win 1
+
+ set completion_win_str_i $start_idx
+ set completion_win_end_i $end_idx
+ set completion_win_mode $mode
+
+ # Create window
+ if {![winfo exists .completion_win]} {
+ set win [frame .completion_win -background {#000000}]
+ bind $win <Button-1> "catch {$this completion_popup_window_but1 %X %Y}"
+ bind $win <FocusOut> "$this close_completion_popup_window"
+ bind $win <Destroy> "
+ catch {$this detete_text_in_editor sel.first sel.last}
+ $this parse \[expr {int(\[$editor index insert\])}\]"
+ bind $win <Key-Escape> "
+ catch {$this detete_text_in_editor sel.first sel.last}
+ $this close_completion_popup_window"
+
+ # Create lisbox and scrollbar
+ set frame [frame $win.frame]
+ set listbox [ListBox $frame.listbox \
+ -relief flat -bd 0 -selectfill 1 \
+ -selectbackground {#AAAAFF} \
+ -bg white -cursor left_ptr \
+ -yscrollcommand "$frame.scrollbar set" \
+ -selectmode single -width 0 -height 0 \
+ -highlightthickness 0 -padx 2 \
+ ]
+ set completion_listbox $listbox
+ pack $listbox -side left -fill both -expand 1
+ pack [ttk::scrollbar $frame.scrollbar \
+ -orient vertical \
+ -command "$listbox yview" \
+ ] -side right -after $listbox -fill y
+
+ ProgressBar .completion_win.progress_bar \
+ -troughcolor #DDDDDD \
+ -type normal -height 4 -bd 0 \
+ -variable {::X::compilation_progress} \
+
+ pack $frame -padx 1 -pady 1 -fill both -expand 1
+
+ $listbox bindText <Button-1> "$this completion_accept"
+ $listbox bindText <Escape> "$this close_completion_popup_window"
+ bind $listbox <Key-Return> "$this completion_accept \[$listbox selection get\]"
+ bind $listbox <KP_Enter> "$this completion_accept \[$listbox selection get\]"
+ bind $listbox <Escape> "$this close_completion_popup_window"
+ if {[winfo exists $listbox.c]} {
+ bind $listbox.c <Button-5> {%W yview scroll +1 units; break}
+ bind $listbox.c <Button-4> {%W yview scroll -1 units; break}
+ }
+ }
+ set listbox ".completion_win.frame.listbox"
+ $listbox selection clear
+ $listbox delete [$listbox items]
+ update idle
+
+ if {$loading || $comp_win_loading_in_p} {
+ if {!($comp_win_loading_max > 1)} {
+ set comp_win_loading_max 1
+ }
+ .completion_win.progress_bar configure -maximum $comp_win_loading_max
+ catch {
+ pack .completion_win.progress_bar -fill x -pady 0
+ }
+ }
+
+ # Fill up listbox
+ set end [string length $str]
+ incr end -1
+
+ set last_inserted {}
+ set string_width 0
+ set required_width 70
+ if {$mode != 2 && $mode != 4} {
+ set str [string toupper $str]
+ }
+ if {$mode == 3} {
+ foreach command {@R0 @R1 @DPTR @A+DPTR @A+PC} {
+ set shortcmd [string range $command 0 $end]
+ if {$shortcmd == $str} {
+ set last_inserted $command
+ $listbox insert end #auto \
+ -text $command \
+ -fg $indirect_fg \
+ -font $indirect_font
+
+ set string_width [font measure $defaultFont_bold $command]
+ if {$required_width < $string_width} {
+ set required_width $string_width
+ }
+ }
+ }
+ } else {
+ for {set i 0} {$i < 8} {incr i} {
+ switch -- $i {
+ 0 {
+ if {$mode != 1} {
+ continue
+ }
+ set color $label_fg
+ set font $label_font
+ }
+ 1 {
+ if {$mode != 1} {
+ continue
+ }
+ set color $const_fg
+ set font $const_font
+ }
+ 2 {
+ if {$mode != 2 || $prog_language != 1} {
+ continue
+ }
+ set color {black}
+ set font $defaultFont
+ }
+ 3 {
+ if {$mode != 0} {
+ continue
+ }
+ set color $macro_fg
+ set font $macro_font
+ }
+ 4 {
+ if {$mode != 1} {
+ continue
+ }
+ set color $sfr_fg
+ set font $sfr_font
+ }
+ 5 {
+ if {$mode != 1} {
+ continue
+ }
+ set color $symbol_fg
+ set font $symbol_font
+ }
+ 6 {
+ if {$mode != 4} {
+ continue
+ }
+ set color $doxytag_fg
+ set font $doxytag_font
+ }
+ 7 {
+ if {$mode != 2 || $prog_language != 1} {
+ continue
+ }
+ set color {#0000DD}
+ set font $defaultFont
+ }
+ }
+ foreach command $autocompletion_list($i) {
+ set shortcmd [string range $command 0 $end]
+ if {$shortcmd == $str} {
+ set last_inserted $command
+ $listbox insert end #auto \
+ -text $command \
+ -fg $color \
+ -font $font
+
+ set string_width [font measure $defaultFont_bold $command]
+ if {$required_width < $string_width} {
+ set required_width $string_width
+ }
+ }
+ }
+ }
+ }
+ if {$mode == 0} {
+ # Instructions and directives
+ if {[string index $str 0] != {$}} {
+ foreach command ${::ASMsyntaxHighlight::instructions} {
+ set shortcmd [string range $command 0 $end]
+ if {$shortcmd == $str} {
+ set last_inserted $command
+ $listbox insert end #auto \
+ -text $command \
+ -fg $ins_fg \
+ -font $ins_font
+ }
+ }
+ foreach command ${::ASMsyntaxHighlight::all_directives} {
+ set shortcmd [string range $command 0 $end]
+ if {$shortcmd == $str} {
+ set last_inserted $command
+ $listbox insert end #auto \
+ -text $command \
+ -fg $dir_fg \
+ -font $dir_font
+ }
+ }
+
+ # Control sequences
+ } {
+ foreach command ${::ASMsyntaxHighlight::all_controls__with_dolar} {
+ set shortcmd [string range $command 0 $end]
+ if {$shortcmd == $str} {
+ set last_inserted $command
+ $listbox insert end #auto \
+ -text $command \
+ -fg $cs_fg \
+ -font $cs_font
+ }
+ }
+ }
+ }
+
+ set num_of_items [llength [$listbox items]]
+
+ # If the listbox is empty -> delete window
+ set do_not_show 0
+ if {!$num_of_items} {
+ set do_not_show 1
+
+ } elseif {$num_of_items == 1 && $last_inserted == $str} {
+ set do_not_show 1
+
+ # Automaticaly complete the incomplete command
+ } else {
+ set command [$listbox itemcget [$listbox item 0] -text]
+ set insert [$editor index insert]
+ set cmd_len [string length $command]
+ set str_len [string length $str]
+
+ if {$mode != 2 && ![string is upper [regsub -all {[_\d@]} $str_org {}]]} {
+ set command [string tolower $command]
+ }
+
+ $editor configure -autoseparators 0
+ catch {$editor tag remove sel 1.0 end}
+ $editor insert insert [string range $command $str_len end]
+ $editor mark set insert $insert
+ $editor tag add sel insert insert+[expr {$cmd_len - $str_len}]c
+ $editor edit separator
+ $editor configure -autoseparators 1
+ parse [expr {int([$editor index insert])}]
+ }
+
+ # Do not display the window
+ if {$do_not_show} {
+ set invoke_com_win_in_p 0
+ close_completion_popup_window
+
+ # Display the window
+ } else {
+ place .completion_win -width [expr {$required_width + 30}] \
+ -height 105 -anchor nw -x $x -y $y -in $editor
+ raise .completion_win
+ update
+ catch {
+ grab -global .completion_win
+ }
+ }
+ set invoke_com_win_in_p 0
+
+ # Highlight all in background to gain autocompletion list
+ if {$loading && !$comp_win_loading_in_p} {
+ comp_win_highlight_all_in_background
+ }
+}
+
+## Auxiliary method for "comp_win_highlight_all_in_background"
+ #+ (Highlight all in background), part of autocompletion mechanism
+ # @return void
+public method comp_win_highlight_all_in_background_AUX {} {
+ if {!$comp_win_loading_in_p} {
+ set comp_win_loading_in_p 1
+ highlight_all
+ set comp_win_loading_in_p 0
+ catch {
+ pack forget .completion_win.progress_bar
+ }
+ }
+}
+
+## Highlight all in background
+ # @return void
+public method comp_win_highlight_all_in_background {} {
+ after idle "catch {$this comp_win_highlight_all_in_background_AUX}"
+}
+
+## Informs editor about that than autocompletion has been turned on
+ # @return void
+public method autocompletion_turned_on {} {
+ set highlighted_lines [string repeat 0 [string bytelength $highlighted_lines]]
+}
+
+## Completion -- accept selection
+ # @parm Sring item - Listbox item
+ # @return void
+public method completion_accept {item} {
+ if {$item == {}} {
+ return
+ }
+
+ if {[llength [$editor tag nextrange sel 1.0]]} {
+ $editor delete sel.first sel.last
+ }
+
+ set item [$completion_listbox itemcget $item -text]
+ set text_org [$editor get $completion_win_str_i $completion_win_end_i]
+
+ if {$completion_win_mode != 2 && ![string is upper [regsub -all {[_\d@]} $text_org {}]]} {
+ set item [string tolower $item]
+ }
+ $editor delete $completion_win_str_i $completion_win_end_i
+ $editor insert $completion_win_str_i $item
+
+ set line [expr {int([$editor index insert])}]
+ recalc_status_counter {} 0
+ parse $line
+
+ close_completion_popup_window
+}
+
+## Close completion popup window if user clicked out of it
+ # @parm Int X - absolute horizontal position of mouse pointer
+ # @parm Int Y - absolute vertical position of mouse pointer
+ # @retrun void
+public method completion_popup_window_but1 {X Y} {
+ set min_x [winfo rootx .completion_win]
+ set min_y [winfo rooty .completion_win]
+ set max_x [expr {$min_x + [winfo width .completion_win]}]
+ set max_y [expr {$min_y + [winfo height .completion_win]}]
+
+ if {$X > $max_x || $X < $min_x || $Y > $max_y || $Y < $min_y} {
+ close_completion_popup_window
+ }
+}
+
+## Unconditionaly safely close completion popup window
+ # @return void
+public method close_completion_popup_window {} {
+ if {$invoke_com_win_in_p} {return}
+ set invoke_com_win_in_p 1
+
+ if {$completion_win_opened} {
+ catch {$editor delete sel.first sel.last}
+ grab release .completion_win
+ place forget .completion_win
+ focus -force $editor
+ parse [expr {int([$editor index insert])}]
+ }
+
+ set completion_win_opened 0
+ set invoke_com_win_in_p 0
+}
+
+## Unconditionaly safely close completion popup window regardless
+ #+ state of this object
+ # @return void
+proc close_completion_popup_window_NOW {} {
+ if {$invoke_com_win_in_p} {return}
+ set invoke_com_win_in_p 1
+
+ if {$completion_win_opened} {
+ catch {
+ grab release .completion_win
+ }
+ catch {
+ place forget .completion_win
+ }
+ }
+
+ set completion_win_opened 0
+ set invoke_com_win_in_p 0
+}
+
+## Auxiliary method for method "Key"
+ # Invokes autocompletion menu
+ # @parm TextIndex wordstart - Index of {insert-1c wordstart}
+ # @parm TextIndex wordstart - Index of {insert-1c wordend}
+ # @return void
+private method aux_Key_autocompletion_0 {wordstart wordend} {
+ # Get range of tag MACRO (possibly incomplete instruction) on the curent line
+ set mc_range [$editor tag nextrange tag_macro $wordstart $wordend]
+ if {![llength $mc_range]} {
+ set mc_range [$editor tag nextrange tag_directive $wordstart $wordend]
+ }
+ if {![llength $mc_range]} {
+ set mc_range [$editor tag nextrange tag_instruction $wordstart $wordend]
+ }
+ if {![llength $mc_range]} {
+ set mc_range [$editor tag nextrange tag_control $wordstart $wordend]
+ }
+
+ # Open completion window
+ if {[llength $mc_range] && [$editor compare insert == [lindex $mc_range 1]]} {
+ invoke_completion_popup_window 0 \
+ [lindex $mc_range 0] [lindex $mc_range 1]
+
+ # Try comething else ...
+ } else {
+ aux_Key_autocompletion_1 $wordstart $wordend
+ }
+}
+
+## Auxiliary method for method "aux_Key_autocompletion_0"
+ # Invokes autocompletion menu
+ # @parm TextIndex wordstart - Index of {insert-1c wordstart}
+ # @parm TextIndex wordstart - Index of {insert-1c wordend}
+ # @return void
+private method aux_Key_autocompletion_1 {wordstart wordend} {
+ # Get range of tag CONSTANT or SFR on the curent line
+ set mc_range [$editor tag nextrange tag_constant $wordstart $wordend]
+ if {![llength $mc_range]} {
+ set mc_range [$editor tag nextrange tag_sfr $wordstart $wordend]
+ }
+
+ # Open completion window
+ if {[llength $mc_range] && [$editor compare insert == [lindex $mc_range 1]]} {
+ invoke_completion_popup_window 1 \
+ [lindex $mc_range 0] [lindex $mc_range 1]
+
+ # Try comething else ...
+ } else {
+ aux_Key_autocompletion_2 $wordstart $wordend
+ }
+}
+
+## Auxiliary method for method "aux_Key_autocompletion_1"
+ # Invokes autocompletion menu
+ # @parm TextIndex wordstart - Index of {insert-1c wordstart}
+ # @parm TextIndex wordstart - Index of {insert-1c wordend}
+ # @return void
+private method aux_Key_autocompletion_2 {wordstart wordend} {
+ # Get range of tag indirect on the curent line
+ set mc_range [$editor tag nextrange tag_indirect $wordstart-1c $wordend]
+
+ # Open completion window
+ if {[llength $mc_range] && [$editor compare insert == [lindex $mc_range 1]]} {
+ invoke_completion_popup_window 3 \
+ [lindex $mc_range 0] [lindex $mc_range 1]
+
+ # Try comething else ...
+ } else {
+ aux_Key_autocompletion_3 $wordstart $wordend
+ }
+}
+
+## Auxiliary method for method "aux_Key_autocompletion_2"
+ # Invokes autocompletion menu
+ # @parm TextIndex wordstart - Index of {insert-1c wordstart}
+ # @parm TextIndex wordstart - Index of {insert-1c wordend}
+ # @return void
+private method aux_Key_autocompletion_3 {wordstart wordend} {
+ # Get range of tag IMMEDIATE CONSTANT on the curent line
+ set mc_range [$editor tag nextrange tag_imm_constant $wordstart-1c $wordend]
+
+ # Open completion window
+ if {[llength $mc_range] && [$editor compare insert == [lindex $mc_range 1]]} {
+ invoke_completion_popup_window 1 \
+ [$editor index [list [lindex $mc_range 0] + 1c]] \
+ [lindex $mc_range 1]
+
+ # Try comething else ...
+ } else {
+ aux_Key_autocompletion_4 $wordstart $wordend
+ }
+}
+
+## Auxiliary method for method "aux_Key_autocompletion_3"
+ # Invokes autocompletion menu
+ # @parm TextIndex wordstart - Index of {insert-1c wordstart}
+ # @parm TextIndex wordstart - Index of {insert-1c wordend}
+ # @return void
+private method aux_Key_autocompletion_4 {wordstart wordend} {
+ # Get range of tag DOXYGEN TAG on the curent line
+ set mc_range [$editor tag nextrange tag_c_dox_tag $wordstart-1c $wordend]
+
+ # Open completion window
+ if {
+ $prog_language == 1
+ &&
+ [llength $mc_range]
+ &&
+ [$editor compare insert == [lindex $mc_range 1]]
+ } then {
+ invoke_completion_popup_window 4 \
+ [lindex $mc_range 0] [lindex $mc_range 1]
+
+ # Try comething else ...
+ } else {
+ aux_Key_autocompletion_5 $wordstart $wordend
+ }
+}
+
+## Auxiliary method for method "aux_Key_autocompletion_4"
+ # Invokes autocompletion menu
+ # @parm TextIndex wordstart - Index of {insert-1c wordstart}
+ # @parm TextIndex wordstart - Index of {insert-1c wordend}
+ # @return void
+private method aux_Key_autocompletion_5 {wordstart wordend} {
+ # Find word with no tags
+ if {
+ $prog_language == 1
+ &&
+ [$editor compare insert == $wordend]
+ } then {
+ set tags [$editor tag names insert-1c]
+
+ # Remove unimportant tags
+ if {[llength $tags]} {
+ foreach lm [concat $line_markers {tag_current_line}] {
+ set idx [lsearch -ascii -exact $tags $lm]
+ if {$idx != -1} {
+ set tags [lreplace $tags $idx $idx]
+ }
+ }
+ }
+
+ # Open auto-completion window
+ if {[llength $tags]} {
+ invoke_completion_popup_window 2 $wordstart $wordend
+ }
+
+ # Close completion window
+ } else {
+ close_completion_popup_window
+ }
+}
+
+## Determinate color for instructions, directives, etc.
+ # @return void
+private method refresh_highlighting_for_autocompletion {} {
+ foreach key ${::ASMsyntaxHighlight::hightlight_tags} {
+ if {[lindex $key 0] == {tag_instruction}} {
+ set ins_fg [lindex $key 1]
+ set ins_font [$editor tag cget tag_instruction -font]
+
+ } elseif {[lindex $key 0] == {tag_directive}} {
+ set dir_fg [lindex $key 1]
+ set dir_font [$editor tag cget tag_directive -font]
+
+ } elseif {[lindex $key 0] == {tag_constant}} {
+ set const_fg [lindex $key 1]
+ set const_font [$editor tag cget tag_constant -font]
+
+ } elseif {[lindex $key 0] == {tag_macro}} {
+ set macro_fg [lindex $key 1]
+ set macro_font [$editor tag cget tag_macro -font]
+
+ } elseif {[lindex $key 0] == {tag_label}} {
+ set label_fg [lindex $key 1]
+ set label_font [$editor tag cget tag_label -font]
+
+ } elseif {[lindex $key 0] == {tag_sfr}} {
+ set sfr_fg [lindex $key 1]
+ set sfr_font [$editor tag cget tag_sfr -font]
+
+ } elseif {[lindex $key 0] == {tag_symbol}} {
+ set symbol_fg [lindex $key 1]
+ set symbol_font [$editor tag cget tag_symbol -font]
+
+ } elseif {[lindex $key 0] == {tag_indirect}} {
+ set indirect_fg [lindex $key 1]
+ set indirect_font [$editor tag cget tag_indirect -font]
+
+ } elseif {[lindex $key 0] == {tag_control}} {
+ set cs_fg [lindex $key 1]
+ set cs_font [$editor tag cget tag_control -font]
+ }
+ }
+
+ if {$prog_language == 1} {
+ foreach key ${::CsyntaxHighlight::hightlight_tags} {
+ if {[lindex $key 0] == {tag_c_dox_tag}} {
+ set doxytag_fg [lindex $key 1]
+ set doxytag_font [$editor tag cget tag_c_dox_tag -font]
+ }
+ }
+ }
+}
diff --git a/lib/editor/commandline.tcl b/lib/editor/commandline.tcl
new file mode 100755
index 0000000..4fe39c3
--- /dev/null
+++ b/lib/editor/commandline.tcl
@@ -0,0 +1,1275 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements procedures related to editor command line
+# This file should be loaded into class Editor in file "editor.tcl"
+# --------------------------------------------------------------------------
+
+## Binding for command line event <KeyPress>
+ # @parm String key - text/binary code of pressed key
+ # @retrun void
+public method cmd_line_key_press {key} {
+ if {![string is print -strict $key]} {
+ return
+ }
+ catch {
+ $cmd_line delete sel.first sel.last
+ }
+ $cmd_line insert insert $key
+ cmd_line_highlight
+}
+
+## Binding for various KeyPress events on command line
+ # @parm key - ID of presses key
+ # @retrun Bool - event accepted
+public method cmd_line_key {key} {
+ set result 0
+ switch -- $key {
+ {Delete} {
+ if {[llength [$cmd_line tag nextrange sel 1.0]]} {
+ $cmd_line delete sel.first sel.last
+ } {
+ if {[$cmd_line index insert] != [$cmd_line index {insert lineend}]} {
+ $cmd_line delete insert {insert+1c}
+ }
+ }
+ }
+ {BackSpace} {
+ if {[llength [$cmd_line tag nextrange sel 1.0]]} {
+ $cmd_line delete sel.first sel.last
+ } {
+ if {[$cmd_line index insert] != [$cmd_line index {insert linestart}]} {
+ $cmd_line delete {insert-1c} insert
+ }
+ }
+ }
+ {Home} {
+ $cmd_line tag remove sel 1.0 end
+ $cmd_line mark set insert {insert linestart}
+ }
+ {End} {
+ $cmd_line tag remove sel 1.0 end
+ $cmd_line mark set insert {insert lineend}
+ }
+ {Left} {
+ $cmd_line tag remove sel 1.0 end
+ if {[$cmd_line index insert] != [$cmd_line index {insert linestart}]} {
+ $cmd_line mark set insert {insert-1c}
+ }
+ }
+ {Right} {
+ $cmd_line tag remove sel 1.0 end
+ if {[$cmd_line index insert] != [$cmd_line index {insert lineend}]} {
+ $cmd_line mark set insert {insert+1c}
+ }
+ }
+ {SLeft} {
+ if {[$cmd_line index insert] != [$cmd_line index {insert linestart}]} {
+ set result 1
+ }
+ }
+ {SRight} {
+ if {[$cmd_line index insert] != [$cmd_line index {insert lineend}]} {
+ set result 1
+ }
+ }
+ default {
+ error "Unrecognized key: $key"
+ return 0
+ }
+ }
+ cmd_line_highlight 1
+ return $result
+}
+
+## Get list of commands which starts with the given string
+ # @parm String cmd - (in)complite command
+ # @retrun List - possible command
+private method cmd_line_get_possible_cmds {cmd} {
+ set result {}
+ set end [string length $cmd]
+ incr end -1
+ foreach command $editor_commands {
+ set shortcmd [string range $command 0 $end]
+
+ if {$command == $cmd} {
+ return $cmd
+
+ } elseif {$shortcmd == $cmd} {
+ lappend result $command
+ }
+ }
+ return $result
+}
+
+## Binding for command line event <Key-Return> and <Key-KP_Enter>
+ # @return void
+public method cmd_line_enter {} {
+ if {[winfo exists .editor_cmd_help_widow]} {
+ grab release .editor_cmd_help_widow
+ destroy .editor_cmd_help_widow
+ }
+
+ set line [$cmd_line get {insert linestart} {insert lineend}]
+ if {$line == {}} {return}
+
+ if {[catch {
+ set command [string tolower [lindex $line 0]]
+ }]} then {
+ Sbar [mc "Invalid command"]
+ return
+ }
+ set options {}
+ if {[regexp {\:\w*$} $command options]} {
+ set options [string range $options 1 end]
+ set options [split $options {}]
+ regsub {\:\w*$} $command {} command
+ }
+ set command [cmd_line_get_possible_cmds $command]
+ if {$command == {}} {
+ Sbar [mc "EDITOR COMMAND LINE: invalid command, type `help list' to get list of avaliable commands"]
+ return
+ } elseif {[llength $command] > 1} {
+ Sbar [mc "Ambiguous command"]
+ return
+ }
+ regsub {^[\w\-:]+\s*} $line {} args
+ set args [string trim $args]
+
+ switch -- $command {
+ {help} {
+ if {[llength $args] > 1} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "char"]
+ }
+ if {![llength $args]} {
+ cmd_line_help_window {Help} [mc \
+ "This is MCU 8051 IDE command line\n\nusage: <b>command \[argumets\]</b>\n\nEnter <b>help list</b> for list of avaliable commands or\n<b>help <STRING command></b> for help for individual command"]
+ return
+ }
+ set command [lindex $args 0]
+ if {$command != {list}} {
+ set command [cmd_line_get_possible_cmds $command]
+ }
+ if {[llength $command] > 1} {
+ Sbar [mc "Ambiguous command"]
+ return
+ }
+
+ switch -- $command {
+ {list} {
+ cmd_line_help_window [mc "Avaliable commands"] \
+ "<b>d2h</b> [mc {DEC -> HEX}]
+ <b>d2o</b> [mc {DEC -> OCT}]
+ <b>d2b</b> [mc {DEC -> BIN}]
+ <b>h2d</b> [mc {HEX -> DEC}]
+ <b>h2o</b> [mc {HEX -> OCT}]
+ <b>h2b</b> [mc {HEX -> BIN}]
+ <b>o2h</b> [mc {OCT -> HEX}]
+ <b>o2d</b> [mc {OCT -> DEC}]
+ <b>o2b</b> [mc {OCT -> BIN}]
+ <b>b2h</b> [mc {BIN -> HEX}]
+ <b>b2d</b> [mc {BIN -> DEC}]
+ <b>b2o</b> [mc {BIN -> OCT}]
+ <b>animate</b> [mc {Animate program}]
+ <b>assemble</b> [mc {Compile current file}]
+ <b>auto-indent</b> [mc {Reformat code}]
+ <b>bookmark</b> [mc {Bookmark current line}]
+ <b>breakpoint</b> [mc {Add/Remove breakpoint}]
+ <b>capitalize</b> [mc {Capitalize selection}]
+ <b>clear</b> [mc {Clear history}]
+ <b>comment</b> [mc {Comment slected text}]
+ <b>copy</b> [mc {Copy selection}]
+ <b>custom</b> [mc {Custom command}]
+ <b>cut</b> [mc {Cut selection}]
+ <b>date</b> [mc {Insert date}]
+ <b>exit</b> [mc {Exit command line}]
+ <b>exit-program</b> [mc {Exit program}]
+ <b>find</b> [mc {Find string}]
+ <b>goto</b> [mc {Go to line}]
+ <b>help</b> [mc {Help}]
+ <b>char</b> [mc {Insert literal character}]
+ <b>indent</b> [mc {Indent selection}]
+ <b>kill-line</b> [mc {Remove current line}]
+ <b>open</b> [mc {Open file}]
+ <b>paste</b> [mc {Paste clipboard}]
+ <b>redo</b> [mc {Take back last undo}]
+ <b>reload</b> [mc {Reload current document}]
+ <b>replace</b> [mc {Replace strings}]
+ <b>run</b> [mc {Run simulation}]
+ <b>save</b> [mc {Save current line}]
+ <b>set-icon-border</b> [mc {Show/Hide icon border}]
+ <b>set-line-numbers</b> [mc {Show/Hide line n. bar}]
+ <b>sim</b> [mc {Start/Stop simulator}]
+ <b>step</b> [mc {Step program}]
+ <b>tolower</b> [mc {To lowercase}]
+ <b>toupper</b> [mc {To uppercase}]
+ <b>uncomment</b> [mc {Uncomment selection}]
+ <b>undo</b> [mc {Take back last operation}]
+ <b>unindent</b> [mc {Unindent selection}]
+ <b>hibernate</b> [mc {Hibernate running program}]
+ <b>resume</b> [mc {Resume hibernated program}]
+ <b>switch-mcu</b> [mc {Change current MCU}]
+ <b>set-xcode</b> [mc {Set XCODE memory size for current MCU}]
+ <b>set-xdata</b> [mc {SET XDATA memory size for current MCU}]"
+ }
+ {hibernate} {
+ cmd_line_help_window [mc "Command hibernate"] [mc \
+ "<b>hibernate</b> \[<STRING target-file>\]\nHibernate running program (avaliliable only when simulator is stated).\n\nThis function saves current state of the simulator engine for future resumption. If no target is not specified it will invoke file selection dialog"]
+ }
+ {resume} {
+ cmd_line_help_window [mc "Command resume"] [mc \
+ "<b>resume</b> \[<STRING source-file>\]\nResume hibernated program (avaliliable only when simulator is stated).\n\nThis function restores previous state of the simulator engine stored in the given file. If no source is not specified it will invoke file selection dialog"]
+ }
+ {switch-mcu} {
+ cmd_line_help_window [mc "Command switch-mcu"] [mc \
+ "<b>switch-mcu</b> <STRING processor-type>\nChange current MCU. Type `switch-mcu list' for list of supported microcontrollers"]
+ }
+ {set-xcode} {
+ cmd_line_help_window [mc "Command set-xcode"] [mc \
+ "<b>set-xcode</b> <INT size>\nChange capacity of external program memory.\nNote: this command also close CODE memory hexeditor"]
+ }
+ {set-xdata} {
+ cmd_line_help_window [mc "Command set-xdata"] [mc \
+ "<b>set-xdata</b> <INT size>\nChange capacity of external data memory.\nNote: this command also close XDATA memory hexeditor"]
+ }
+ {run} {
+ cmd_line_help_window [mc "Command run"] [mc \
+ "Run simulation (avaliliable only when simulator is stated)"]
+ }
+ {exit} {
+ cmd_line_help_window [mc "Command exit"] [mc \
+ "Exits this command line"]
+ }
+ {exit-program} {
+ cmd_line_help_window [mc "Command exit-program"] [mc \
+ "Quit MCU 8051 IDE"]
+ }
+ {set-icon-border} {
+ cmd_line_help_window [mc "Command set-icon-border"] [mc \
+ "Sets the visibility of the icon border"]
+ }
+ {set-line-numbers} {
+ cmd_line_help_window [mc "Command set-line-numbers"] [mc \
+ "Sets the visibility of the line numbers."]
+ }
+ {help} {
+ cmd_line_help_window [mc "Command help"] [mc \
+ "<b>help</b> <STRING command>\nShows help for the given command\n\n<b>help list</b>\nShows list of avaliable command"]
+ }
+ {open} {
+ cmd_line_help_window [mc "Command open"] [mc \
+ "<b>open</b> <STRING full_filename>\nOpens the given file in new editor"]
+ }
+ {indent} {
+ cmd_line_help_window [mc "Command indent"] [mc \
+ "Indents current line or selected area"]
+ }
+ {unindent} {
+ cmd_line_help_window [mc "Command unindent"] [mc \
+ "Unindents current line or selected area"]
+ }
+ {comment} {
+ cmd_line_help_window [mc "Command comment"] [mc \
+ "Comments current line or selected area"]
+ }
+ {uncomment} {
+ cmd_line_help_window [mc "Command uncomment"] [mc \
+ "Uncomments current line or selected area"]
+ }
+ {kill-line} {
+ cmd_line_help_window [mc "Command kill-line"] [mc \
+ "Removes the current line"]
+ }
+ {date} {
+ cmd_line_help_window [mc "Command date"] [mc \
+ "<b>date</b> <STRING format>\nInserts formated date at the current position in text\n\n<b>Format string:</b>\n%% => %\n%a => Weekday name (Mon, Tue, etc.)\n%A => Weekday name (Monday, Tuesday, etc.)\n%b => Month name (Jan, Feb, etc.)\n%B => Full month name\n%C => Year (19 or 20)\n%d => Day of month (01 - 31)\n%D => %m/%d/%y\n%h => Abbreviated month name.\n%H => Hour (00 - 23)\n%I => Hour (01 - 12)\n%j => Day of year (001 - 366)\n%k => Hour (0 - 23)\n%l => Hour (1 - 12).\n%m => Month (01 - 12)\n%M => Minute (00 - 59)\n%n => Newline\n%p => AM/PM\n%R => %H:%M.\n%s => Unix timestamp\n%S => Seconds (00 - 59)\n%t => Tab\n%T => %H:%M:%S.\n%u => Weekday number (Monday = 1, Sunday = 7)\n%w => Weekday number (Sunday = 0, Saturday = 6)\n%y => Year without century (00 - 99)\n%Y => Year with century (e.g. 1459)"]
+ }
+ {clear} {
+ cmd_line_help_window [mc "Command clear"] [mc \
+ "Clears command line history"]
+ }
+ {char} {
+ cmd_line_help_window [mc "Command char"] [mc \
+ "<b>char</b> <NUMBER identifier>\nInserts literal characters by their numerical identifier.\nIdentifier can be in decimal hexadecimal or octal form."]
+ }
+ {goto} {
+ cmd_line_help_window [mc "Command goto"] [mc \
+ "<b>goto</b> <INT line>\nGo to the given line"]
+ }
+ {replace} {
+ cmd_line_help_window [mc "Command replace"] [mc \
+ "<b>replace\[:options\]</b> <STRING pattern> <STRING replacement>\n\n<b>options:</b>\nb Search backwards\nc Search from cursor position\nr Regular expression search\ns Case sensitive search\np Ask before replacement"]
+ }
+ {find} {
+ cmd_line_help_window [mc "Command find"] [mc \
+ "<b>find\[:options\]</b> <STRING pattern>\n\n<b>options:</b>\nb Search backwards\nc Search from cursor position\ne Search in the selection only\nr Regular expression search\ns Case sensitive search"]
+ }
+ {cut} {
+ cmd_line_help_window [mc "Command cut"] [mc \
+ "Cut selected text"]
+ }
+ {copy} {
+ cmd_line_help_window [mc "Command copy"] [mc \
+ "Copy selected text to clipboard"]
+ }
+ {paste} {
+ cmd_line_help_window [mc "Command paste"] [mc \
+ "Paste clipboard content"]
+ }
+ {tolower} {
+ cmd_line_help_window [mc "Command tolower"] [mc \
+ "Convert selected text to lowercase"]
+ }
+ {toupper} {
+ cmd_line_help_window [mc "Command toupper"] [mc \
+ "Convert selected text to upppercase"]
+ }
+ {capitalize} {
+ cmd_line_help_window [mc "Command capitalize"] [mc \
+ "Capitalize the selected text (convert 1st character to uppercase)"]
+ }
+ {save} {
+ cmd_line_help_window [mc "Command save"] [mc \
+ "Save the current document"]
+ }
+ {bookmark} {
+ cmd_line_help_window [mc "Command bookmark"] [mc \
+ "Bookmark the current line"]
+ }
+ {custom} {
+ cmd_line_help_window [mc "Command custom"] [mc \
+ "<b>custom</b> <INT command_number>\nExecute custom command (see menu Configuration -> Custom commands)"]
+ }
+ {breakpoint} {
+ cmd_line_help_window [mc "Command breakpoint"] [mc \
+ "Add / Remove breakpoint to the current line"]
+ }
+ {undo} {
+ cmd_line_help_window [mc "Command undo"] [mc \
+ "Take back last operation"]
+ }
+ {redo} {
+ cmd_line_help_window [mc "Command redo"] [mc \
+ "Take back last undo"]
+ }
+ {auto-indent} {
+ cmd_line_help_window [mc "Command auto-indent"] [mc \
+ "Reformat code"]
+ }
+ {reload} {
+ cmd_line_help_window [mc "Command reload"] [mc \
+ "Reload the current document"]
+ }
+ {assemble} {
+ cmd_line_help_window [mc "Command assemble"] [mc \
+ "Compile the current document"]
+ }
+ {sim} {
+ cmd_line_help_window [mc "Command sim"] [mc \
+ "Start / Stop simulator"]
+ }
+ {step} {
+ cmd_line_help_window [mc "Command step"] [mc \
+ "Step program (avaliliable only when simulator is stated)"]
+ }
+ {animate} {
+ cmd_line_help_window [mc "Command animate"] [mc \
+ "Animate program (avaliliable only when simulator is stated)"]
+ }
+ {d2h} {
+ cmd_line_help_window [mc "Command d2h"] [mc \
+ "Convert decimal number to hexadecimal and write result to editor"]
+ }
+ {d2o} {
+ cmd_line_help_window [mc "Command d2o"] [mc \
+ "Convert decimal number to octal and write result to editor"]
+ }
+ {d2b} {
+ cmd_line_help_window [mc "Command d2b"] [mc \
+ "Convert decimal number to binary and write result to editor"]
+ }
+ {h2d} {
+ cmd_line_help_window [mc "Command h2d"] [mc \
+ "Convert hexadecimal number to decimal and write result to editor"]
+ }
+ {h2o} {
+ cmd_line_help_window [mc "Command h2o"] [mc \
+ "Convert hexadecimal number to octal and write result to editor"]
+ }
+ {h2b} {
+ cmd_line_help_window [mc "Command h2b"] [mc \
+ "Convert hexadecimal number to binary and write result to editor"]
+ }
+ {o2h} {
+ cmd_line_help_window [mc "Command o2h"] [mc \
+ "Convert octal number to hexadecimal and write result to editor"]
+ }
+ {o2d} {
+ cmd_line_help_window [mc "Command o2d"] [mc \
+ "Convert octal number to decimal and write result to editor"]
+ }
+ {o2b} {
+ cmd_line_help_window [mc "Command o2b"] [mc \
+ "Convert octal number to binary and write result to editor"]
+ }
+ {b2h} {
+ cmd_line_help_window [mc "Command b2h"] [mc \
+ "Convert binary number to hexadecimal and write result to editor"]
+ }
+ {b2d} {
+ cmd_line_help_window [mc "Command b2d"] [mc \
+ "Convert binary number to decimal and write result to editor"]
+ }
+ {b2o} {
+ cmd_line_help_window [mc "Command b2o"] [mc \
+ "Convert binary number to octal and write result to editor"]
+ }
+ default {
+ Sbar [mc "EDITOR COMMAND LINE: Unknown command: `%s'" [lindex $args 0]]
+ }
+ }
+ }
+ {hibernate} {
+ if {[llength $args] > 2} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "hibernate"]
+ return
+ }
+
+ if {![llength $args]} {
+ ::X::__hibernate
+ } {
+ ::X::__hibernate_to [lindex $args 0] $filename
+ }
+ Sbar [mc "Success"]
+ }
+ {resume} {
+ if {[llength $args] > 2} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "resume"]
+ return
+ }
+
+ if {![llength $args]} {
+ ::X::__resume
+ } {
+ ::X::__resume_from [lindex $args 0] $filename
+ }
+ Sbar [mc "Success"]
+ }
+ {switch-mcu} {
+ if {[llength $args] > 2 || ![llength $args]} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "switch-mcu"]
+ return
+ }
+
+ set arg [string toupper [lindex $args 0]]
+ if {$arg == {list}} {
+ set arg {}
+ foreach mcu ${::X::avaliable_processors} {
+ append arg $mcu
+ append arg "\n"
+ }
+ cmd_line_help_window {Supported microcontrollers} $arg
+ } {
+ if {[lsearch ${::X::avaliable_processors} $arg] == -1} {
+ Sbar [mc "EDITOR COMMAND LINE: Unsupported processor `%s'" "$arg"]
+ } {
+ ::X::change_processor $arg
+ }
+ }
+ Sbar [mc "Success"]
+ }
+ {set-xcode} {
+ if {[llength $args] > 2 || ![llength $args]} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "set-xcode"]
+ return
+ }
+
+ set arg [lindex $args 0]
+ set error 0
+ if {![string first {0x} $arg]} {
+ if {![string is xdigit -strict [string range $arg 2 end]]} {set error 1}
+ set arg [expr "$arg"]
+ } elseif {[string index $arg 0] == {0}} {
+ if {![regexp {^[0-7]+$} $arg]} {set error 1}
+ set arg [expr "$arg"]
+ } else {
+ if {![string is digit -strict $arg]} {set error 1}
+ }
+
+ if {$error} {
+ Sbar [mc "EDITOR COMMAND LINE: Expected integer but got `%s' (command: %s)" $arg "set-xcode"]
+ return
+ }
+
+ set icode [expr {[lindex [${::X::actualProject} cget -procData] 2] * 1024}]
+ if {$arg > (0xFFFF - $icode)} {
+ Sbar [mc "EDITOR COMMAND LINE: This MCU has CODE memory limit 0x10000 B (65536) (command: %s)"] "set-xdata"
+ return
+ }
+
+ if {[lindex [${::X::actualProject} cget -procData] 1] != {yes}} {
+ Sbar [mc "This MCU cannot have connected external program memory"]
+ } {
+ ${::X::actualProject} configure -P_option_mcu_xcode $arg
+ ::X::close_hexedit code ${::X::actualProject}
+ ${::X::actualProject} simulator_resize_code_memory $arg
+ Sbar [mc "Success"]
+ }
+ }
+ {set-xdata} {
+ if {[llength $args] > 2 || ![llength $args]} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "set-xdata"]
+ return
+ }
+
+ set arg [lindex $args 0]
+ set error 0
+ if {![string first {0x} $arg]} {
+ if {![string is xdigit -strict [string range $arg 2 end]]} {set error 1}
+ set arg [expr "$arg"]
+ } elseif {[string index $arg 0] == {0}} {
+ if {![regexp {^[0-7]+$} $arg]} {set error 1}
+ set arg [expr "$arg"]
+ } else {
+ if {![string is digit -strict $arg]} {set error 1}
+ }
+
+ if {$error} {
+ Sbar [mc "EDITOR COMMAND LINE: Expected integer but got `%s' (command: %s)" $arg "set-xdata"]
+ return
+ }
+
+ if {$arg > 0xFFFF} {
+ Sbar [mc "EDITOR COMMAND LINE: This MCU has XDATA memory limit 0x10000 B (65536) (command: %s)" "set-xdata"]
+ return
+ }
+
+ if {[lindex [${::X::actualProject} cget -procData] 0] != {yes}} {
+ Sbar [mc "This MCU cannot have connected external data memory"]
+ } {
+ ${::X::actualProject} configure -P_option_mcu_xdata $arg
+ ::X::close_hexedit xdata ${::X::actualProject}
+ ${::X::actualProject} simulator_resize_xdata_memory $arg
+ Sbar [mc "Success"]
+ }
+ }
+ {d2h} {command_line_X2X_command {d2h} $args}
+ {d2o} {command_line_X2X_command {d2o} $args}
+ {d2b} {command_line_X2X_command {d2b} $args}
+ {h2d} {command_line_X2X_command {h2d} $args}
+ {h2o} {command_line_X2X_command {h2o} $args}
+ {h2b} {command_line_X2X_command {h2b} $args}
+ {o2h} {command_line_X2X_command {o2h} $args}
+ {o2d} {command_line_X2X_command {o2d} $args}
+ {o2b} {command_line_X2X_command {o2b} $args}
+ {b2h} {command_line_X2X_command {b2h} $args}
+ {b2d} {command_line_X2X_command {b2d} $args}
+ {b2o} {command_line_X2X_command {b2o} $args}
+ {set-icon-border} {
+ ::X::__show_hine_IconB
+ command_without_args $args
+ }
+ {set-line-numbers} {
+ ::X::__show_hine_LineN
+ command_without_args $args
+ }
+ {open} {
+ if {![llength $args] || [llength $args] > 1} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "open"]
+ }
+ if {$fullFileName != {}} {
+ set dir [file dirname $fullFileName]
+ } {
+ set dir $projectPath
+ }
+ set filename [file join $dir [lindex $args 0]]
+ if {![file exists $filename] || ![file isfile $filename]} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "unindent"]
+ }
+ if {[${X::actualProject} openfile $filename 1 . def def 0 0 {}] != {}} {
+ ${X::actualProject} switch_to_last
+ update idle
+ ${X::actualProject} editor_procedure {} parseAll {}
+ Sbar [mc "Success"]
+ }
+ }
+ {indent} {
+ indent
+ command_without_args $args
+ }
+ {unindent} {
+ unindent
+ command_without_args $args
+ }
+ {comment} {
+ comment
+ command_without_args $args
+ }
+ {uncomment} {
+ uncomment
+ command_without_args $args
+ }
+ {kill-line} {
+ detete_text_in_editor {insert linestart} {insert+1l linestart}
+ goto [expr {int([$editor index insert])}]
+ Sbar [mc "Success"]
+ }
+ {date} {
+ if {[catch {$editor insert insert [clock format [clock seconds] -format $args]}]} {
+ Sbar [mc "EDITOR COMMAND LINE: Invalid format string"]
+ } {
+ parse [expr {int([$editor index insert])}]
+ Sbar [mc "Success"]
+ }
+ }
+ {char} {
+ if {[llength $args] > 1} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "char"]
+ } {
+ Sbar [mc "Success"]
+ }
+ set char [lindex $args 0]
+ if {![regexp {^(0|0x|0X)?[0-9]+$} $char]} {
+ Sbar [mc "EDITOR COMMAND LINE: syntax error: expected integer (command: %s)" "char"]
+ return
+ }
+ $editor insert insert [format %c $char]
+ parse [expr {int([$editor index insert])}]
+ }
+ {goto} {
+ if {[llength $args] > 1} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "goto"]
+ } {
+ Sbar [mc "Success"]
+ }
+ set target_line [lindex $args 0]
+
+ if {![regexp {^(0|0x|0X)?[0-9]+$} $target_line]} {
+ Sbar [mc "EDITOR COMMAND LINE: syntax error: expected integer (command: %s)" "goto"]
+ return
+ }
+ if {$target_line > [editor_linescount]} {
+ Sbar [mc "Target line out of range"]
+ } {
+ goto $target_line
+ Sbar [mc "Success"]
+ }
+ }
+ {replace} {
+ if {[llength $args] > 2} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "replace"]
+ } {
+ Sbar [mc "Success"]
+ }
+ set pattern [lindex $args 0]
+ set replacement [lindex $args 1]
+ set Backwards 0
+ set fromCursor 0
+ set regExp 0
+ set noCase 0
+ set confirm 0
+ set options {}
+ foreach opt $options {
+ switch -- $opt {
+ {b} { ;# Search backwards
+ set Backwards 1
+ }
+ {c} { ;# Search from cursor position
+ set fromCursor 1
+ }
+ {r} { ;# Regular expression search
+ set regExp 1
+ }
+ {s} { ;# Do case sensitive search
+ set noCase 1
+ }
+ {p} { ;# Prompt before replacement
+ set confirm 1
+ }
+ default {
+ Sbar [mc "Invalid option: %s" $opt]
+ }
+ }
+ }
+ replace $fromCursor $Backwards $regExp \
+ $noCase $pattern $replacement \
+ $confirm ::X::replace_prompt
+ }
+ {find} {
+ if {[llength $args] > 1} {
+ Sbar [mc "EDITOR COMMAND LINE: wrong # args (command: %s)" "find"]
+ }
+ set pattern [lindex $args 0]
+ set Backwards 0
+ set fromCursor 0
+ set regExp 0
+ set noCase 0
+ set confirm 0
+ set inSelection 0
+ set options {}
+ foreach opt $options {
+ switch -- $opt {
+ {b} { ;# Search backwards
+ set Backwards 1
+ }
+ {e} { ;# Search in the selection only
+ set inSelection 1
+ }
+ {c} { ;# Search from cursor position
+ set fromCursor 1
+ }
+ {r} { ;# Regular expression search
+ set regExp 1
+ }
+ {s} { ;# Do case sensitive search
+ set noCase 1
+ }
+ default {
+ Sbar [mc "Invalid option: %s" $opt]
+ }
+ }
+ }
+ set result [find $fromCursor $Backwards $regExp $noCase $inSelection 1.0 $pattern]
+ if {[lindex $result 0] == -1} {
+ Sbar [mc "String not found: %s" [lindex $result 1]]
+ } {
+ Sbar [mc "Found %s occurences" [lindex $result 2]]
+ }
+ }
+ {cut} {
+ cut
+ command_without_args $args
+ }
+ {copy} {
+ copy
+ command_without_args $args
+ }
+ {paste} {
+ paste
+ command_without_args $args
+ }
+ {tolower} {
+ lowercase
+ command_without_args $args
+ }
+ {toupper} {
+ uppercase
+ command_without_args $args
+ }
+ {capitalize} {
+ capitalize
+ command_without_args $args
+ }
+ {save} {
+ save
+ command_without_args $args
+ }
+ {bookmark} {
+ Bookmark
+ command_without_args $args
+ }
+ {breakpoint} {
+ Breakpoint
+ command_without_args $args
+ }
+ {undo} {
+ undo
+ command_without_args $args
+ }
+ {redo} {
+ redo
+ command_without_args $args
+ }
+ {auto-indent} {
+ ::X::__reformat_code
+ command_without_args $args
+ }
+ {reload} {
+ ::X::__reload
+ command_without_args $args
+ }
+ {assemble} {
+ ::X::__compile 0
+ command_without_args $args
+ }
+ {sim} {
+ ::X::__initiate_sim
+ command_without_args $args
+ }
+ {step} {
+ ::X::__step
+ command_without_args $args
+ }
+ {animate} {
+ ::X::__animate
+ command_without_args $args
+ }
+ {run} {
+ ::X::__run
+ command_without_args $args
+ }
+ {custom} {
+ set cmd [lindex $args 0]
+ if {$cmd != 0 && $cmd != 1 && $cmd != 2}
+ __exec_custom_cmd $cmd
+ Sbar [mc "Success"]
+ }
+ {clear} {
+ $cmd_line delete 1.0 end
+ command_without_args $args
+ return
+ }
+ {exit-program} {
+ ::X::__exit
+ }
+ {exit} {
+ pack forget $cmd_line
+ focus $editor
+ command_without_args $args
+ }
+ default {
+ Sbar [mc "EDITOR COMMAND LINE: invalid command, type `help list' to get list of avaliable commands"]
+ }
+ }
+
+ # Manage command line history
+ if {int([$cmd_line index end-1l]) == int([$cmd_line index insert])} {
+ $cmd_line insert {insert lineend} "\n"
+ } {
+ set txt [$cmd_line get {insert linestart} {insert lineend}]
+ $cmd_line mark set insert end
+ $cmd_line insert insert $txt
+ cmd_line_highlight 1
+ $cmd_line insert insert "\n"
+ }
+ $cmd_line mark set insert end
+ $cmd_line see end
+}
+
+## Auxiliary procedure for "cmd_line_enter"
+ # Performs number base conversions
+ # @parm String command - Type of conversion (e.g h2b, d2o)
+ # @parm String argument - Number to convert
+ # @retrun void
+private method command_line_X2X_command {command argument} {
+ set len [llength $argument]
+ if {!$len} {
+ Sbar [mc "EDITOR COMMAND LINE: This command requires exactly one argument"]
+ return
+ }
+
+ set argument [lindex $argument 0]
+
+ switch -- $command {
+ {d2h} { ;# DEC -> HEX
+ set ver_cmd {isdec}
+ set conv_cmd {dec2hex}
+ }
+ {d2o} { ;# DEC -> OCT
+ set ver_cmd {isdec}
+ set conv_cmd {dec2oct}
+ }
+ {d2b} { ;# DEC -> BIN
+ set ver_cmd {isdec}
+ set conv_cmd {dec2bin}
+ }
+ {h2d} { ;# HEX -> DEC
+ set ver_cmd {ishex}
+ set conv_cmd {hex2dec}
+ }
+ {h2o} { ;# HEX -> OCT
+ set ver_cmd {ishex}
+ set conv_cmd {hex2oct}
+ }
+ {h2b} { ;# HEX -> BIN
+ set ver_cmd {ishex}
+ set conv_cmd {hex2bin}
+ }
+ {o2h} { ;# OCT -> HEX
+ set ver_cmd {isoct}
+ set conv_cmd {oct2hex}
+ }
+ {o2d} { ;# OCT -> BIN
+ set ver_cmd {isoct}
+ set conv_cmd {oct2dec}
+ }
+ {o2b} { ;# OCT -> BIN
+ set ver_cmd {isoct}
+ set conv_cmd {oct2bin}
+ }
+ {b2h} { ;# BIN -> HEX
+ set ver_cmd {isbin}
+ set conv_cmd {bin2hex}
+ }
+ {b2d} { ;# BIN -> DEC
+ set ver_cmd {isbin}
+ set conv_cmd {bin2dec}
+ }
+ {b2o} { ;# BIN -> OCT
+ set ver_cmd {isbin}
+ set conv_cmd {bin2oct}
+ }
+ default {
+ error "Unknown error in Editor.command_line_X2X_command()"
+ }
+ }
+
+ if {![::NumSystem::$ver_cmd $argument]} {
+ Sbar [mc "EDITOR COMMAND LINE: Invalid number format"]
+ return
+ }
+
+ $editor insert insert [::NumSystem::$conv_cmd $argument]
+ parse [expr {int([$editor index insert])}]
+ Sbar [mc "Success"]
+}
+
+## Check if the given list of arguments is empty and display result on main statusbar
+ # @parm List args - list of arguments
+ # @retrun void
+private method command_without_args {args} {
+ if {[llength $args]} {
+ if {[llength $args] != 1 || [lindex $args 0] != {}} {
+ Sbar [mc "EDITOR COMMAND LINE: This command takes no arguments"]
+ }
+ }
+ Sbar [mc "Success"]
+}
+
+## Highlight current contents of editor command line
+ # @parm Bool = 0 - Disable popup-based completion
+ # @return void
+private method cmd_line_highlight args {
+ # Remove all tags from command line
+ foreach tag {tag_cmd tag_argument tag_option tag_error} {
+ $cmd_line tag remove $tag {insert linestart} {insert lineend}
+ }
+
+ # Get line contents and line number
+ set line [$cmd_line get {insert linestart} {insert lineend}]
+ set lineNumber [expr {int([$cmd_line index insert])}]
+
+ # Split line into command and arguments
+ set cmd {}
+ set opt {}
+ if {[regexp {^[\w:-]+} $line cmd]} {
+ if {[regexp {\:\w*$} $cmd opt]} {
+ set cmd [regsub {\:\w*$} $cmd {}]
+ }
+ }
+
+ # Resolve possible commands, start index and end index
+ set command [cmd_line_get_possible_cmds $cmd]
+ set startIdx [$cmd_line index {insert linestart}]
+ set endIdx [string length $cmd]
+ # Highlight command (+ post down list of possible commands | + return)
+ if {[llength $command] == 1} {
+ $cmd_line tag add tag_cmd $startIdx $lineNumber.$endIdx
+ } elseif {$endIdx && [llength $command] > 1 && [$cmd_line compare $lineNumber.$endIdx == insert]} {
+ if {$cline_completion && $args != 1} {
+ # Automaticaly complete command
+ set possible_cmd [lindex $command 0]
+ set insert [$cmd_line index insert]
+ $cmd_line insert insert [string range $possible_cmd $endIdx end]
+ $cmd_line tag remove sel 1.0 end
+ $cmd_line tag add sel $lineNumber.$endIdx $lineNumber.[string length $possible_cmd]
+ $cmd_line mark set insert $insert
+ # Postdown completion menu
+ cmd_line_menu_postdown $command
+ }
+ return
+ } else {
+ $cmd_line tag add tag_error $startIdx $lineNumber.$endIdx
+ }
+ # Insure than list of possible commands is not visible
+ cmd_line_menu_close
+
+ # Highlight command options (characters after colon)
+ if {$opt != {}} {
+ set startIdx $endIdx
+ incr endIdx [string length $opt]
+ if {[lsearch $commands_with_option $command] != -1} {
+ $cmd_line tag add tag_option $lineNumber.$startIdx $lineNumber.$endIdx
+ } {
+ $cmd_line tag add tag_error $lineNumber.$startIdx $lineNumber.$endIdx
+ }
+ }
+
+ # Highlight remaining as arguments
+ $cmd_line tag add tag_argument $lineNumber.$endIdx {insert lineend}
+}
+
+## Postdown list of possible commands for command line
+ # @parm List commands - contents of the list
+ # @retrun void
+private method cmd_line_menu_postdown {commands} {
+ # List is not mapped -> create new toplevel window
+ if {![winfo exists $cmd_line_listbox]} {
+ # Determinate window coordinates and width
+ set x [winfo rootx $cmd_line]
+ set y [expr {[winfo rooty $cmd_line] + [winfo height $cmd_line]}]
+ set width [winfo width $cmd_line]
+
+ # Create window
+ set win {.editor_cmd_help_widow}
+ if {[winfo exists $win]} {
+ grab release $win
+ destroy $win
+ }
+ toplevel $win -background {#000000} -class {Help window}
+ wm overrideredirect $win 1
+ wm geometry $win "=${width}x100+${x}+${y}"
+ bind $win <ButtonPress-1> "$this cmd_line_win_B1 %X %Y"
+ bind $win <FocusOut> "$this cmd_line_menu_close_now"
+
+ # Create listbox of possible commands
+ set frame [frame $win.frame]
+ set cmd_line_listbox [ListBox $frame.lisbox \
+ -relief flat -bd 0 -selectfill 1 \
+ -selectbackground {#AAAAFF} \
+ -yscrollcommand "$frame.scrollbar set" \
+ -selectmode single -highlightthickness 0\
+ -bg {#FFFFFF} \
+ ]
+ pack $cmd_line_listbox -fill both -expand 1 -side left
+ # Create scrollbar
+ pack [ttk::scrollbar $frame.scrollbar \
+ -orient vertical \
+ -command "$cmd_line_listbox yview" \
+ ] -side right -after $cmd_line_listbox -fill y
+ pack $frame -padx 1 -pady 1 -fill both -expand 1
+
+ # Configure listbox event bindings
+ if {[winfo exists $cmd_line_listbox.c]} {
+ bind $cmd_line_listbox.c <Button-5> {%W yview scroll +5 units; break}
+ bind $cmd_line_listbox.c <Button-4> {%W yview scroll -5 units; break}
+ }
+ bind $cmd_line_listbox <Key-Escape> "$this cmd_line_menu_close_now"
+ bind $cmd_line_listbox <Key-Return> \
+ "$this cmd_line_listbox_sel \[$cmd_line_listbox selection get\]"
+ bind $cmd_line_listbox <Key-KP_Enter> \
+ "$this cmd_line_listbox_sel \[$cmd_line_listbox selection get\]"
+ $cmd_line_listbox bindText <Button-1> "$this cmd_line_listbox_sel"
+ $cmd_line_listbox bindText <Enter> "
+ update
+ %W selection clear
+ %W selection set"
+
+ # Finalize window initialization (global grab)
+ update idle
+ catch {
+ grab -global $win
+ raise $win
+ }
+ }
+
+ # Fill listbox with the given list of commands
+ $cmd_line_listbox delete [$cmd_line_listbox items]
+ foreach cmd $commands {
+ $cmd_line_listbox insert end #auto -text $cmd
+ }
+}
+
+## Binding for command line event <Key-Down>
+ # Possible results:
+ # A) Focus on list of possible commands
+ # C) Return 0
+ # @retrun Bool - $cmd_line_listbox focused
+public method cmd_line_down {} {
+ if {![winfo exists $cmd_line_listbox]} {
+ return 0
+ } {
+ $cmd_line_listbox selection set [$cmd_line_listbox item 0]
+ focus -force $cmd_line_listbox
+ return 1
+ }
+}
+
+## Clear command line and write there text
+ # of the given item in list of possible commands.
+ # This procedure also closes command line help window
+ # @parm String item - ID of choosen item
+ # @retrun void
+public method cmd_line_listbox_sel {item} {
+ $cmd_line delete {insert linestart} {insert lineend}
+ $cmd_line insert end [$cmd_line_listbox itemcget $item -text]
+ $cmd_line tag add tag_cmd {insert linestart} {insert lineend}
+ cmd_line_menu_close
+}
+
+## Binding common for all command line help windows: event <ButtonPress-1>
+ # This procedure will close help window if user click outside it.
+ # @parm Int X - absolute horizontal position of mouse pointer
+ # @parm Int Y - absolute vertical position of mouse pointer
+ # @retrun void
+public method cmd_line_win_B1 {X Y} {
+ set win {.editor_cmd_help_widow}
+ set min_x [winfo rootx $win]
+ set min_y [winfo rooty $win]
+ set max_x [expr {$min_x + [winfo width $win]}]
+ set max_y [expr {$min_y + [winfo height $win]}]
+
+ if {$X > $max_x || $X < $min_x || $Y > $max_y || $Y < $min_y} {
+ cmd_line_menu_close_now
+ }
+}
+
+## Close command line help window if opened
+ # @retrun void
+public method cmd_line_menu_close {} {
+ if {![winfo exists $cmd_line_listbox]} {
+ return
+ }
+ cmd_line_menu_close_now
+}
+
+## Unconditionaly close command line help window
+ # @retrun void
+public method cmd_line_menu_close_now {} {
+ grab release .editor_cmd_help_widow
+ destroy .editor_cmd_help_widow
+ if {[winfo viewable $cmd_line]} {
+ focus -force $cmd_line
+ }
+}
+
+## Create command line help window for purpose of help
+ # @parm String header - Window header
+ # @parm String content - Window contents (can contain tags <b>bold</b>)
+ # @return Widget - Text widget
+private method cmd_line_help_window {header content} {
+ # Destroy the previous window
+ if {[winfo exists .editor_cmd_help_widow]} {
+ grab release .editor_cmd_help_widow
+ destroy .editor_cmd_help_widow
+ }
+
+ # Create window
+ set win [toplevel .editor_cmd_help_widow -bg {#EEEEEE}]
+ wm overrideredirect $win 1
+
+ bind $win <ButtonPress-1> "$this cmd_line_win_B1 %X %Y"
+ bind $win <FocusOut> "$this cmd_line_menu_close_now"
+
+ # Create header
+ set header_frame [frame $win.header]
+ pack [label $header_frame.lbl_heder \
+ -text $header -fg {#FF0000} \
+ -bg {#AAAAFF} -bd 0 -anchor w \
+ -relief flat \
+ -font $cmd_line_win_font \
+ ] -fill x -expand 1 -side left -ipadx 5
+ pack [Button $header_frame.lbl_close \
+ -text [mc "Close"] -bd 0 -pady 0\
+ -compound left -cursor hand2 \
+ -bg {#AAAAFF} -relief flat \
+ -fg {#FFFFFF} -anchor e \
+ -image ::ICONS::16::button_cancel\
+ -font $cmd_line_win_font \
+ -helptext [mc "Close this window"]\
+ -command "destroy $win" \
+ ] -fill none -side left -pady 0 -ipady 0
+ pack $header_frame -fill x -side top
+
+ # Create text widget
+ set text [text $win.text \
+ -bg {#FFFFFF} \
+ -cursor left_ptr \
+ -bd 1 \
+ -width 0 -height 0 \
+ -font $cl_hw_nrml_font \
+ -yscrollcommand "$win.scrollbar set" \
+ ]
+ $text tag configure tag_bold -font $cl_hw_bold_font
+
+ # Create map of bold font tags
+ regsub -all -line {^\t+} $content {} content
+ set bold_tag_map {}
+ while 1 {
+ set tag_pair {}
+
+ set idx [string first {<b>} $content]
+ if {$idx == -1} {break}
+ regsub {<b>} $content {} content
+ lappend tag_pair $idx
+
+ set idx [string first {</b>} $content]
+ if {$idx == -1} {break}
+ regsub {</b>} $content {} content
+ lappend tag_pair $idx
+
+ lappend bold_tag_map $tag_pair
+ }
+
+ # Adjust content and insert tags
+ set start [$text index insert]
+ $text insert end $content
+ foreach pair $bold_tag_map {
+ $text tag add tag_bold $start+[lindex $pair 0]c $start+[lindex $pair 1]c
+ }
+ $text configure -state disabled
+
+ # Create and pack scrollbar
+ pack $text -side left -fill both -expand 1
+ pack [ttk::scrollbar $win.scrollbar \
+ -orient vertical \
+ -command "$text yview" \
+ ] -side right -fill y -after $text
+
+ # Show the window
+ set x [winfo rootx $cmd_line]
+ set y [expr {[winfo rooty $cmd_line] + [winfo height $cmd_line]}]
+ update idle
+ if {150 > ([winfo height .] - $y)} {
+ incr y -150
+ incr y -[winfo height $cmd_line]
+ }
+ catch {
+ wm transient $win .
+ grab -global $win
+ update
+ wm geometry $win "=[winfo width $cmd_line]x150+${x}+${y}"
+ }
+}
+
+## Focus on editor / editor command line
+ # @parm Bool = 0 - Do not call proc. "cmd_line_on"
+ # @return void
+public method cmd_line_focus args {
+ # Show command line
+ if {![winfo viewable $cmd_line]} {
+ pack $cmd_line -side top -fill x
+ if {$args != 1} {
+ ${::X::actualProject} cmd_line_on
+ }
+ }
+
+ if {[focus] == $cmd_line} {
+ focus $editor
+ } {
+ focus $cmd_line
+ }
+ update
+}
diff --git a/lib/editor/editor.tcl b/lib/editor/editor.tcl
new file mode 100755
index 0000000..d4d9bec
--- /dev/null
+++ b/lib/editor/editor.tcl
@@ -0,0 +1,2786 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements source code editor with syntax highligh and
+# lightweight syntax validation.
+# This GUI component consist of line numbers border, icon border,
+# editor, command line and status bar.
+#
+# Consist of:
+# * PROCEDURES RELATED TO EDITOR COMMAND LINE
+# * GENERAL PURPOSE PROCEDURES
+# * EXPORTS TO OTHER DATA FORMATS (XHTML && LATEX)
+# * KEY EVENT HANDLERS
+# * AUTOCOMPLETION RELATED PROCEDURES
+# --------------------------------------------------------------------------
+
+# Load syntax highlighting
+source "${::LIB_DIRNAME}/editor/ASMsyntaxhighlight.tcl"
+source "${::LIB_DIRNAME}/editor/R_ASMsyntaxhighlight.tcl"
+source "${::LIB_DIRNAME}/editor/Csyntaxhighlight.tcl"
+source "${::LIB_DIRNAME}/editor/LSTsyntaxhighlight.tcl"
+
+# Initialize variable containing count of matched strings
+set ::editor_search_count 0
+
+class Editor {
+
+ # Load procedures related to editor command line
+ source "${::LIB_DIRNAME}/editor/commandline.tcl"
+
+ # Load procedures related to exports to other data formats
+ source "${::LIB_DIRNAME}/editor/exports.tcl"
+
+ # Load autocompletion related procedures
+ source "${::LIB_DIRNAME}/editor/autocompletion.tcl"
+
+ # Load general purpose procedures
+ source "${::LIB_DIRNAME}/editor/generalproc.tcl"
+
+ # Load event handlers
+ source "${::LIB_DIRNAME}/editor/eventhandlers.tcl"
+
+
+ ## COMMON
+ ## Editor to use
+ # 0 - Native editor
+ # 1 - Vim
+ # 2 - Emacs
+ # 3 - Nano
+ # 4 - dav
+ # 5 - le
+ common editor_to_use 0
+ common intentation_mode {normal};# Editor indentation mode
+ common spaces_no_tabs 0 ;# Bool: Use spaces instead of tabs
+ common number_of_spaces 8 ;# Number of spaces to use instead of tab
+ common auto_brackets 1 ;# Automaticaly insert oposite brackets, quotes, etc.
+ common auto_completion 1 ;# Enable popup-base completion for code editor
+ common cline_completion 1 ;# Enable popup-base completion for command line
+ common autosave 0 ;# Int: 0 == Disable autosave; N > 0 == minutes
+ common hg_trailing_sp 1 ;# Bool: Highlight trailing spaces
+
+ common finishigh_hg_dlg_max ;# Int: Highlight dialog -- maximum value for progress bar
+ common finishigh_hg_dlg_const ;# Int: Highlight dialog -- current value for progress bar
+
+ common set_shortcuts {} ;# Currently set shortcut bindigs
+ common shortcuts_cat {edit} ;# Key shortcut categories related to this segment
+ common count 0 ;# Counter of class instances
+ common bookmark 0 ;# Auxiliary variable for popup menu for Icon Border
+ common breakpoint 0 ;# Auxiliary variable for popup menu for Line Numbers
+ common pmenu_cline 0 ;# Auxiliary variable for popup menu for Icon Border and Line Numbers
+ common wrap_char "\uB7" ;# Character intended for marking wrapped lines
+
+ # Commands supported by editor command line
+ common editor_commands {
+ animate assemble auto-indent bookmark breakpoint
+ capitalize clear comment copy custom
+ cut date exit exit-program find
+ goto help char indent kill-line
+ open paste redo reload replace
+ run save set-icon-border sim set-line-numbers
+ step tolower toupper uncomment undo
+ unindent d2h d2o d2b h2d
+ h2o h2b o2h o2d o2b
+ b2h b2d b2o hibernate resume
+ switch-mcu set-xcode set-xdata
+ }
+ # Editor commands wich can take options
+ common commands_with_option {find replace}
+ ## Tags which defines background color for specific type of lines
+ # {{tagname bg-color bool-priority} ...}
+ common line_markers {
+ {sel #AAAAFF}
+ {tag_current_line #FFFF88}
+ {tag_bookmark #DDDDFF}
+ {tag_breakpoint #FF0000}
+ {tag_simulator_curr #AAFFAA}
+ {tag_error_line #FFDDDD}
+ {tag_trailing_space #E8FFF0}
+ }
+
+ # Font for command line: Normal help window text
+ common cl_hw_nrml_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ ]
+ # Font for command line: Bold help window text
+ common cl_hw_bold_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ -weight bold \
+ ]
+ # Font for command line: Subheader in help window text
+ common cl_hw_hdr_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ -weight bold \
+ ]
+ # Font for command line: Main header in help window text
+ common cmd_line_win_font [font create \
+ -size -17 -weight bold \
+ -family {helvetica} \
+ ]
+ common cmd_line_fontSize 14 ;# Font size for command line
+ common cmd_line_fontFamily $::DEFAULT_FIXED_FONT ;# Font family for command line
+ # Font for editor command line
+ common cmd_line_font [font create \
+ -family $cmd_line_fontFamily \
+ -size -$cmd_line_fontSize \
+ ]
+ ## Highlight tags for command line
+ # {
+ # {tag_name ?foreground? ?overstrike? ?italic? ?bold?}
+ # }
+ common cmd_line_highlighting {
+ {tag_cmd #0000DD 0 0 1}
+ {tag_argument #00DD00 0 0 0}
+ {tag_option #DD0000 0 0 1}
+ }
+
+ common normal_text_bg #FFFFFF ;# Default background color for editor
+ common iconBorder_bg #C8C5FF ;# Default background color for icon border
+ common lineNumbers_bg #9497D8 ;# Default background color for line numbers
+ common lineNumbers_fg #FFFFFF ;# Default foreground color for line numbers
+ # Items in editor menu, which should be disabled when editor goes to simulator mode
+ common freezable_menu_items {
+ Cut Paste Undo Redo Comment Uncomment Indent
+ Unindent Uppercase Lowercase Capitalize
+ }
+ # Items in editor menu, which should be disabled when editor is in read only mode
+ common read_na_only_menu_items {
+ Cut Paste Undo Redo Comment Uncomment Indent
+ Unindent Uppercase Lowercase Capitalize
+ }
+
+ common fontSize 13 ;# Default font size
+ common fontFamily $::DEFAULT_FIXED_FONT ;# Default font family
+
+ # Default font for editor
+ common defaultFont \
+ [font create \
+ -size -$fontSize \
+ -family $fontFamily \
+ -weight {normal} \
+ ]
+ common defaultFont_bold \
+ [font create \
+ -size -$fontSize \
+ -family $fontFamily \
+ -weight {bold} \
+ ]
+ common defaultCharWidth 0 ;# Width of one character of the default font
+ common defaultCharHeight 0 ;# Height of one character of the default font
+ # Font for status bar (Normal)
+ common statusBarFont \
+ [font create \
+ -size -12 \
+ -family $::DEFAULT_FIXED_FONT \
+ ]
+ # Font for status bar (Bold)
+ common statusBarBoldFont \
+ [font create \
+ -size -12 \
+ -weight bold \
+ -family $::DEFAULT_FIXED_FONT \
+ ]
+ # Definition of editor popup menu
+ common EDITORMENU {
+ {command {LJMP this line} {$edit:jmp} 2 "ljmp_this_line {}"
+ {exec} "Program jump"}
+ {command {LCALL this line} {$edit:call} 4 "lcall_this_line {}"
+ {exec} "Call subprogram"}
+ {separator}
+ {command {Breakpoint} {$edit:breakpoint} 0 "Breakpoint {}"
+ {flag} "Add/Remove breakpoint to/from current line"}
+ {command {Bookmark} {$edit:bookmark} 1 "Bookmark {}"
+ {bookmark_add} "Add/Remove bookmark to/from current line"}
+ {separator}
+ {command {Undo} {$edit:undo} 0 "undo {}"
+ {undo} "Take back last operation"}
+ {command {Redo} {$edit:redo} 2 "redo {}"
+ {redo} "Take back last undo"}
+ {separator}
+ {command {Cut} {$edit:cut} 2 "cut {}"
+ {editcopy} "Move selected text into the clipboard"}
+ {command {Copy} {$edit:copy} 0 "copy {}"
+ {editcut} "Copy selected text into the clipboard"}
+ {command {Paste} {$edit:paste} 0 "paste {}"
+ {editpaste} "Paste text from clipboard"}
+ {separator}
+ {command {Select all} {$edit:select_all} 0 "select_all {}"
+ {} "Select all text in the editor"}
+ {separator}
+ {command {Comment} {$edit:comment} 1 "comment {}"
+ {} "Comment selected text"}
+ {command {Uncomment} {$edit:uncomment} 4 "uncomment {}"
+ {} "Uncomment selected text"}
+ {separator}
+ {command {Indent} {$edit:indent} 2 "indent {}"
+ {indent} "Indent selected text"}
+ {command {Unindent} {$edit:unindent} 1 "unindent {}"
+ {unindent} "Unindent selected text"}
+ {separator}
+ {command {Uppercase} {$edit:uppercase} 0 "lowercase {}"
+ {up0} "Indent selected text"}
+ {command {Lowercase} {$edit:lowercase} 2 "uppercase {}"
+ {down0} "Unindent selected text"}
+ {command {Capitalize} {$edit:capitalize} 4 "capitalize {}"
+ {} "Unindent selected text"}
+ {separator}
+ {command {Save file} {$edit:save} 0 "save {}"
+ {filesave} "Save this file"}
+ }
+ # Definition of popup menu for icon border
+ common IBMENU {
+ {checkbutton "Bookmark" {$edit:bookmark} {::Editor::bookmark} 1 0 0
+ {Bookmark ${::Editor::pmenu_cline}}}
+ {separator}
+ {command "Configure panel" "" 0 {configDialogs_mkDialog Colors}
+ {configure} "Invoke editor configuration dialog"}
+ {command "Hide" "" 0 {show_hine_IconB}
+ {2leftarrow} "Hide this panel"}
+ }
+ # Definition of popup menu for line numbers
+ common LNMENU {
+ {checkbutton "Breakpont" {$edit:breakpoint} {::Editor::breakpoint} 1 0 0
+ {Breakpoint ${::Editor::pmenu_cline}}}
+ {separator}
+ {command "Configure panel" "" 0 {configDialogs_mkDialog Colors}
+ {configure} "Invoke editor configuration dialog"}
+ {command "Hide panel" "" 0 {show_hine_LineN}
+ {2leftarrow} "Hide this panel"}
+ }
+ # Definition of popup menu for editor statis bar
+ common STATMENU {
+ {command "Split vertical" {$edit:split_v} 8 {__split_vertical}
+ {view_left_right} "Split the editor vertically"}
+ {command "Split horizontal" {$edit:split_h} 6 {__split_horizontal}
+ {view_top_bottom} "Split the editor horizontally"}
+ {separator}
+ {command "Close current view" {$edit:close_cv} 2 {__close_current_view_from_pmenu}
+ {view_remove} ""}
+ {separator}
+ {command "Back" {$edit:prev} 0 {__prev_editor_from_pmenu}
+ {left} "Go to prevoius file in the file list"}
+ {command "Forward" {$edit:next} 0 {__next_editor_from_pmenu}
+ {right} "Go to next file in the file list"}
+ }
+
+ ## PUBLIC
+ public variable editor ;# text widget identifier
+ public variable ed_sc_frame ;# frame identifier (need packing)
+ public variable show_iconBorder 1 ;# on/off indicator for Icon Border (bool)
+ public variable show_lineNum 1 ;# on/off indicator for Line NUmbers (bool)
+ public variable iconBorder ;# Identifier of Icon Border text widget
+ public variable lineNumbers ;# Identifier of Line Numbers text widget
+ public variable scrollbar ;# Identifier of scrollbar widget
+ public variable lastEnd 1 ;# Last end index of Edior text widget (for speed optimalization)
+ public variable Sbar_lock_file ;# Identifier of image label widget at the left site of status bar
+ public variable Sbar_sim_mode ;# Identifier of label widget at the left site of status bar
+ public variable Sbar_ssim_mode
+ public variable Sbar_dis_mode ;# Identifier of label widget at the left site of status bar
+ public variable Sbar_CRT_frame ;# ID of frame on statusbar containing labels "Line: x Col: x Total: x"
+ public variable Sbar_row ;# ID of label showing current line number
+ public variable Sbar_col ;# ID of label showing current column
+ public variable Sbar_total ;# ID of label showing total number of lines
+ public variable Sbar_image ;# Identifier of floppy disk icon at the middle site of status bar
+ public variable Sbar_fileName ;# Identifier of the text of filename at the right site of status bar
+ public variable Sbar_prog_lang ;# ID of text specifing file type at the right site of status bar
+ public variable fullFileName ;# Full file name of the current file ("" == untitled)
+ public variable filename ;# Name of currently opened file or 'untitled'
+ public variable modified 0 ;# Boolean value indicating than the text has been modified since last save
+ public variable encoding ;# Current character encoding (eg. 'utf-8')
+ public variable eol ;# Current End of Line character (one of {lf crlf cr})
+ public variable ro_mode 0 ;# Bool: Read only mode
+
+ ## PRIVATE
+ private variable finishigh_hg_dlg_wdg {} ;# Widget: Finishing highlight dialog
+ private variable finishigh_hg_dlg_tmr {} ;# Timer: Finishing highlight dialog
+ private variable object_initialized 0 ;# Bool: Flag "Object initialized"
+ private variable c_hg_tags_created 0 ;# Bool: C language highlight tags created
+ private variable lst_hg_tags_created 0 ;# Bool: Code listing highlight tags created
+ private variable cmd_prefix ;# Command prefix for popup menu
+ private variable last_cur_line 1 ;# Number of the last current line in the editor
+ private variable last_sim_line 1 ;# Number of the last simulator line in the editor
+ private variable enable_parseAll 1 ;# Enable reparese whole document (used by: parse_all)
+ private variable bookmarks {0} ;# List of boolean bookmarks, eg. {0 0 0 1 1 0 0}
+ private variable breakpoints {0} ;# List of boolean breakpoint, eg. {0 0 0 1 1 0 0}
+ private variable menu ;# Identifier of popup menu for editor text widget
+ private variable stat_menu ;# Identifier of popup menu for editor statusbar
+ private variable IB_menu ;# Identifier of popup menu for icon border
+ private variable ins_mode_lbl ;# Identifier of insertion mode label (on status bar)
+ private variable sel_mode_lbl ;# Identifier of selection mode label (on status bar)
+ private variable left_frame_L ;# ID of frame containing Line Numbers
+ private variable left_frame_R ;# ID of frame containing Icon Border
+ private variable LN_menu ;# Identifier of popup menu for line numbers
+ private variable frozen 0 ;# True if editor is in simulator mode
+ private variable getDataAsXHTML_abort 0 ;# Set this variable to 1 to immediate stop export to XHTML
+ private variable getDataAsLaTeX_abort 0 ;# Set this variable to 1 to immediate stop export to LaTeX
+ private variable changeLCase_abort 0 ;# Set this variable to 1 to immediate stop changing letter case
+ private variable parentObject ;# Identifier parent GUI component (some frame widget)
+ private variable lastUpDownIndex 0 ;# Last column index (for Up and Down actions)
+ private variable scroll_in_progress 0 ;# Bool: scroll procedure in progress
+ private variable highlighted_lines {0} ;# String/array of highlighted lines (eg. 00011111110001111)
+ private variable critical_edit_proc 0 ;# Bool: Critical edit procedure in progess
+ private variable map_of_wraped_lines {} ;# Map of wrapped lines (eg. {0 0 5 0 0 2 0})
+ private variable number_of_wraps 0 ;# Number of line wraps
+ private variable ins_ovr_mode 1 ;# Current insertion mode (1 == INS; 0 == OVR)
+ private variable editor_width 0 ;# Width of active area of the editor widget
+ private variable editor_height 0
+ private variable cmd_line ;# ID of command line entry widget
+ private variable cmd_line_listbox {} ;# Widget: ListBox of command line auto-completion window
+ private variable completion_listbox ;# Widget: ListBox of editor popup-based completion
+ private variable do_not_hide_comp_win 0 ;# Bool: Disable highing of editor completion win. on KeyRelease
+ private variable autosave_timer {} ;# ID of autosave timer (command "after")
+ private variable key_handler_buffer {} ;# List: Buffer for <Key> event handler
+ private variable key_handler_in_progress 0 ;# Bool: <Key> event handler in progress
+ private variable statusbar_menu_config {} ;# List: Statusbra menu configuration list
+ private variable auto_switching_lock 0 ;# Bool: Automatic file switching enabled
+ private variable selection_in_progress 0 ;# Bool: Procedure "editor_selection" in progress
+ private variable selection_mode 0 ;# Bool: Block selection mode flag
+ private variable save_in_progress 0 ;# Bool: Saving in progress
+ ## Programming language
+ # 0 - Assembly language
+ # 1 - C
+ # 2 - Code listing
+ # 3 - ASX8051
+ private variable prog_language 0
+
+ private variable top_frame ;# Widget: Container frame for embedded external editor
+ private variable terminal_created 0 ;# Bool: Terminal emulator to run embedded editor has been created
+ private variable top_frame_idx 0 ;# Int: Unique number of container frame for embedded editor
+ private variable pid {} ;# Int: Process indentifier of embedded external editor (e.g. Vim)
+
+ ## Array: Strings avaliable for autocompletion
+ # Index 0 - Labels in assembly
+ # Index 1 - Constants/variables
+ # Index 2 - C variables
+ # Index 3 - Macros
+ # Index 4 - SFR's
+ # Index 5 - Expression symbols
+ # Index 6 - Doxygen tags
+ # Index 7 - C Functions
+ common invoke_com_win_in_p 0 ;# Bool: invoke_completion_popup_window in progress
+ common completion_win_opened 0 ;# Bool: Editor popup-based completion window opended
+ private variable autocompletion_list
+ private variable completion_win_str_i 1.0 ;# TextIndex: String to complete - start index
+ private variable completion_win_end_i 1.0 ;# TextIndex: String to complete - end index
+ private variable completion_win_mode 0 ;# Int: Completion window mode
+ private variable comp_win_loading_in_p 0 ;# Bool: Completion window list loading is in progress
+ private variable comp_win_loading_max 1 ;# Int: Maximum for progressbar in the completion window
+ private variable macl_invocations 0 ;# Int: Number of invocations of "manage_autocompletion_list"
+ private variable doxytag_fg {#000000} ;# Color: Highlight color for doxygen tag
+ private variable indirect_fg {#000000} ;# Color: Highlight color for indirect address
+ private variable symbol_fg {#000000} ;# Color: Highlight color for asm. symbol
+ private variable sfr_fg {#000000} ;# Color: Highlight color for SFR
+ private variable label_fg {#000000} ;# Color: Highlight color for asm. label
+ private variable macro_fg {#000000} ;# Color: Highlight color for asm. macro
+ private variable const_fg {#000000} ;# Color: Highlight color for asm. const
+ private variable dir_fg {#000000} ;# Color: Highlight color for asm. directive
+ private variable cs_fg {#000000} ;# Color: Highlight color for constrol sequence
+ private variable ins_fg {#000000} ;# Color: Highlight color for instruction
+ private variable doxytag_font $defaultFont ;# Font: Font for doxygen tag
+ private variable indirect_font $defaultFont ;# Font: Font for indirect address
+ private variable symbol_font $defaultFont ;# Font: Font for asm. symbol
+ private variable sfr_font $defaultFont ;# Font: Font for SFR
+ private variable label_font $defaultFont ;# Font: Font for asm. label
+ private variable macro_font $defaultFont ;# Font: Font for asm. macro
+ private variable const_font $defaultFont ;# Font: Font for asm. const
+ private variable dir_font $defaultFont ;# Font: Font for asm. directive
+ private variable cs_font $defaultFont ;# Font: Font for constrol sequence
+ private variable ins_font $defaultFont ;# Font: Font for instruction
+
+ ## Object constructor
+ # @parm Bool create_tags - Create highlighting tags
+ # @parm String eol_char - EOL (one of {lf cr crlf})
+ # @parm String enc - Character encoding (some iso-8859-x or utf-8)
+ # @parm Bool read_only - Read only flag
+ # @parm Bool switch_lock - Automatic file switching enabled
+ # @parm widget parentobject - Reference to parent object
+ # @parm String fileName - filename to be showed in statusbar
+ # @parm String filepath - location where to optionaly save the data, "" == untitled document
+ # @parm String cmd_prefix - command prefix for popup menu
+ # @parm String data - an input text data
+ # @parm Int sh - Syntax highlight
+ constructor {create_tags eol_char enc read_only switch_lock parentobject fileName filepath Cmd_prefix data sh} {
+ close_completion_popup_window_NOW
+
+ # Configure specific ttk styles
+ ttk::style configure Editor_DarkBg.TButton \
+ -background {#DDDDDD} \
+ -padding 0 \
+ -borderwidth 1 \
+ -relief flat
+ ttk::style map Editor_DarkBg.TButton \
+ -relief [list active raised !active flat]
+
+ # increment instance counter
+ incr count
+
+ # Set object variables
+ array set autocompletion_list {0 {} 1 {} 2 {} 3 {} 4 {} 5 {} 6 {} 7 {}}
+ set autocompletion_list(5) [lsort -ascii ${::ASMsyntaxHighlight::expr_instructions}]
+ set autocompletion_list(6) [lsort -ascii [concat\
+ ${::CsyntaxHighlight::doxy_tags_type2} \
+ ${::CsyntaxHighlight::doxy_tags_type1} \
+ ${::CsyntaxHighlight::doxy_tags_type0} \
+ ]]
+ set auto_switching_lock [expr {!$switch_lock}]
+ set ro_mode $read_only
+ set encoding $enc
+ set eol $eol_char
+ set cmd_prefix $Cmd_prefix
+ set parentObject $parentobject ;# Identifier parent GUI component (some frame widget)
+ set fullFileName $filepath ;# Full file name (including path) of current file
+ set filename $fileName ;# Name of currently opened file or 'untitled'
+ refresh_avaliable_SFR
+
+ if {$sh == {}} {
+ determinate_prog_lang 0
+ } {
+ set prog_language_old $prog_language
+ set prog_language $sh
+ }
+
+ if {$editor_to_use} {
+ set ed_sc_frame [frame .editor_frame$count -bd 2 -relief sunken]
+ recreate_terminal $fullFileName
+ set editor [text .editor_frame$count.dummy_editor]
+ return
+ }
+
+ # Create frames
+ set ed_sc_frame [frame .editor_frame$count]
+ set top_frame [frame $ed_sc_frame.editor_top_frame -relief sunken -bd 1]
+ set left_frame [frame $top_frame.editor_left_frame]
+ set left_frame_L [frame $left_frame.left -bg $iconBorder_bg]
+ set left_frame_R [frame $left_frame.right -bg $lineNumbers_bg]
+ set bottom_frame [frame $ed_sc_frame.bottom_frame]
+ set statusbar [frame $bottom_frame.editor_status -bg #DDDDDD]
+
+ # Create command line
+ set cmd_line [text $bottom_frame.cmd_line \
+ -bd 1 -bg #FFFFFF -highlightcolor #8888FF \
+ -highlightthickness 1 -height 1 \
+ -font $cmd_line_font \
+ ]
+ setStatusTip -widget $cmd_line \
+ -text [mc "Editor command line, type `help' for more"]
+ $cmd_line delete 1.0 end
+
+ ## Create "Icon border"
+ set iconBorder [text $left_frame_L.editor_iconB \
+ -font $defaultFont_bold \
+ -width 2 \
+ -bd 0 \
+ -highlightthickness 0 \
+ -bg $iconBorder_bg \
+ -exportselection 0 \
+ -state disabled \
+ -takefocus 0 \
+ -cursor hand2 \
+ -relief flat \
+ ]
+ $iconBorder tag configure center -justify center
+ setStatusTip -widget $iconBorder \
+ -text [mc "Icon border - click to add/remove bookmark"]
+ # Create poup menu for "Icon border"
+ set IB_menu $iconBorder.editor_iconB_menu
+
+ ## Create "Line numbers"
+ set lineNumbers [text $left_frame_R.editor_lines \
+ -font $defaultFont_bold \
+ -width 0 \
+ -bd 0 \
+ -highlightthickness 0 \
+ -exportselection 0 \
+ -bg $lineNumbers_bg \
+ -fg $lineNumbers_fg \
+ -state normal \
+ -takefocus 0 \
+ -cursor hand2 \
+ -relief flat \
+ ]
+ $lineNumbers delete 1.0 end
+ $lineNumbers insert end {1}
+ $lineNumbers configure -state disabled
+ $lineNumbers tag configure right -justify right
+ $lineNumbers tag configure center -justify center
+ $lineNumbers tag raise center right
+ setStatusTip -widget $lineNumbers \
+ -text [mc "Line numbers - click to add/remove breakpoint"]
+
+ # Create poup menu for "Line numbers"
+ set LN_menu $lineNumbers.editor_lines_menu
+
+ # Create "Editor"
+ frame $top_frame.f -bd 0 -bg $normal_text_bg -cursor xterm
+ set editor [text $top_frame.f.editor \
+ -yscrollcommand "$this scrollSet" \
+ -bg $normal_text_bg \
+ -font $defaultFont_bold \
+ -undo 1 -exportselection 1 \
+ -wrap word \
+ -maxundo 0 \
+ -selectborderwidth 1 \
+ -bd 0 -relief flat \
+ -tabstyle wordprocessor \
+ ]
+ bind $top_frame.f <Button-1> "$this click_under_editor %x %y; break"
+ bind $top_frame.f <Button-4> "$this scroll scroll -3 units; break"
+ bind $top_frame.f <Button-5> "$this scroll scroll +3 units; break"
+ # Create scrollbar
+ set scrollbar [ttk::scrollbar \
+ $top_frame.editor_scrollbar \
+ -orient vertical \
+ -command "$this scroll_0" \
+ ]
+
+ # Set new font attributes
+ set defaultCharWidth [font measure $defaultFont_bold -displayof $editor { }]
+ set defaultCharHeight [font metrics $defaultFont_bold -displayof $editor -linespace]
+
+ ## Pack that all into mainframe
+ # Parts of Left frame
+ pack $lineNumbers -fill none -expand 1 -side right -anchor n
+ pack $iconBorder -fill none -expand 1 -side left -anchor n
+ pack [frame $left_frame.editor_redutant_frame] -side left
+ pack $left_frame_L -side left -fill y
+ pack $left_frame_R -side right -fill y
+ # Parts of Top frame
+ pack $left_frame -side left -fill y -expand 0
+ pack $scrollbar -fill y -expand 0 -side right
+ pack $top_frame.f -fill both -expand 1 -side left
+ pack $editor -fill x -expand 1 -side left -anchor nw
+ # Parts of Bottom frame
+ pack $statusbar -side bottom -fill x
+ # Bottom and Top frame$ins_mode_lbl
+ pack $bottom_frame -side bottom -fill x
+ pack $top_frame -side top -fill both -expand 1
+
+ ## Create statusbar
+ set stat_menu $statusbar.popup_menu
+ set status_left [frame $statusbar.editor_status_left -bg #DDDDDD]
+ set status_middle [frame $statusbar.editor_status_middle -width 16 -bg #DDDDDD -width 20]
+ set status_right [frame $statusbar.editor_status_right -bg #DDDDDD]
+ set ins_mode_lbl [Label $statusbar.ins_mode_lbl \
+ -text [mc "INS"] -fg #000000 -pady 0 \
+ -bg #DDDDDD -cursor hand2 \
+ -helptext [mc "Insertion mode"] \
+ -font $statusBarBoldFont \
+ ]
+ set sel_mode_lbl [Label $statusbar.sel_mode_lbl \
+ -text [mc "NORM"] -fg #000000 -pady 0 \
+ -bg #DDDDDD -cursor hand2 \
+ -helptext [mc "Selection mode"] \
+ -font $statusBarBoldFont -width 7 \
+ ]
+ setStatusTip -widget $sel_mode_lbl -text [mc "Selection mode -- BLK == block; NORM == normal"]
+ bind $sel_mode_lbl <Button-1> "$this switch_sel_mode"
+
+ pack $status_left -side left -padx 10
+ pack $status_middle -side left
+ pack $ins_mode_lbl -side left -padx 5
+ pack $sel_mode_lbl -side left -padx 5
+ pack $status_right -side right -fill x -padx 10
+
+ # Frame for "Line: x Col: x Total: x"
+ set Sbar_CRT_frame [frame $status_left.sbar_crt_frame -bg #DDDDDD]
+ # Labels "Line:"
+ pack [label $Sbar_CRT_frame.sbar_row_lbl \
+ -text [mc "Line:"] -fg {#444444} \
+ -bg #DDDDDD \
+ -font $statusBarFont -pady 0 \
+ ] -side left -pady 0
+ set Sbar_row [label $Sbar_CRT_frame.sbar_row_val \
+ -fg {#0000AA} -font $statusBarBoldFont -pady 0 \
+ -bg #DDDDDD -anchor e -bd 1 \
+ ]
+ pack $Sbar_row -side left -pady 0
+ # Labels "Column:"
+ pack [label $Sbar_CRT_frame.sbar_col_lbl \
+ -text [mc " Column:"] -fg {#444444} \
+ -bg #DDDDDD \
+ -font $statusBarFont -pady 0 \
+ ] -side left -pady 0
+ set Sbar_col [label $Sbar_CRT_frame.sbar_col_val \
+ -fg {#0000AA} -font $statusBarBoldFont -pady 0 \
+ -bg #DDDDDD -anchor e \
+ ]
+ pack $Sbar_col -side left -pady 0
+ # Labels "Total:"
+ pack [label $Sbar_CRT_frame.sbar_total_lbl \
+ -text [mc " Total:"] -fg {#444444} \
+ -bg #DDDDDD \
+ -font $statusBarFont -pady 0 \
+ ] -side left -pady 0
+ set Sbar_total [label $Sbar_CRT_frame.sbar_total_val \
+ -fg {#006600} -font $statusBarBoldFont -pady 0 \
+ -bg #DDDDDD -anchor e \
+ ]
+ pack $Sbar_total -side left -pady 0
+ # Image label: Lock/Unlock file
+ set Sbar_lock_file [ttk::button $status_left.editor_status_left_lock \
+ -style Editor_DarkBg.TButton \
+ -command "$this invert_lock" \
+ ]
+ set_lock $auto_switching_lock
+ # Label: "Simulator mode"
+ set Sbar_sim_mode [Label $status_left.editor_status_left_l0 \
+ -font $statusBarBoldFont \
+ -fg #DD0000 -bg #DDDDDD \
+ -helptext [mc "Editor status bar"] \
+ -padx 5 -pady 0 \
+ -text [mc "Simulator mode "] \
+ ]
+ # Label: "Simulator mode"
+ set Sbar_ssim_mode [Label $status_left.editor_status_left_l2 \
+ -font $statusBarBoldFont \
+ -fg #555555 -bg #DDDDDD \
+ -helptext [mc "Editor status bar"] \
+ -padx 5 -pady 0 \
+ -text [mc "Starting simulator"] \
+ ]
+ # Label: "Editor disabled"
+ set Sbar_dis_mode [Label $status_left.editor_status_left_l1 \
+ -font $statusBarBoldFont \
+ -fg #3333DD -bg #DDDDDD \
+ -helptext [mc "Editor status bar"] \
+ -padx 5 -pady 0 \
+ -text [mc "Editor disabled"] \
+ ]
+ set Sbar_image [Label $status_middle.editor_status_middle_l \
+ -bg #DDDDDD \
+ -pady 0 \
+ -cursor hand2 \
+ ]
+ bind $Sbar_image <Button-1> "$this save"
+ bind $Sbar_image <Double-1> "$this save"
+ setStatusTip -widget $Sbar_image \
+ -text [mc "File has been modified, click to save"]
+
+ pack $Sbar_CRT_frame
+
+ set Sbar_fileName [Label $status_right.editor_status_right_l \
+ -text $filename \
+ -helptext $filename \
+ -font $statusBarBoldFont \
+ -bg #DDDDDD \
+ ]
+ pack $Sbar_fileName -side left
+ setStatusTip -widget $Sbar_fileName \
+ -text [mc "Name of the current file or \"untitled\" if the file has not yet been saved under any name"]
+
+ set Sbar_prog_lang [Label $status_right.sbar_prog_lang \
+ -helptext [mc "File type\n C/H\tC source / header\n ASM\tAssembly language\n LST\tCode listing\n ASX\tASX8051 assembler"] \
+ -font $statusBarBoldFont \
+ -bg #DDDDDD \
+ ]
+ adjust_sbar_to_prog_lang
+ pack $Sbar_prog_lang -side right -padx 5
+ setStatusTip -widget $Sbar_prog_lang -text [mc "File type"]
+
+ # Set status bar event bindings
+ bind $statusbar <ButtonRelease-3> "$this statusbar_popup_menu $editor %X %Y; break"
+ foreach widget [winfo children $statusbar] {
+ bind $widget <ButtonRelease-3> "$this statusbar_popup_menu $editor %X %Y; break"
+ foreach wdg [winfo children $widget] {
+ bind $wdg <ButtonRelease-3> "$this statusbar_popup_menu $editor %X %Y; break"
+ foreach w [winfo children $wdg] {
+ bind $w <ButtonRelease-3> "$this statusbar_popup_menu $editor %X %Y; break"
+ }
+ }
+ }
+
+ # Create text tags
+ if {$create_tags} {
+ create_highlighting_tags
+ }
+ define_line_markers
+ $editor tag configure c_lang_var
+ $editor tag configure c_lang_func
+ $editor tag raise sel tag_current_line
+ $editor tag raise sel tag_bookmark
+ $editor tag raise sel tag_simulator_curr
+ $editor tag raise sel tag_trailing_space
+ $editor tag raise tag_error_line tag_bookmark
+ $editor tag raise tag_error_line tag_trailing_space
+ $editor tag raise tag_current_line tag_bookmark
+ $editor tag raise tag_current_line tag_error_line
+ $editor tag raise tag_trailing_space tag_current_line
+ $editor tag raise tag_simulator_curr tag_current_line
+ $editor tag raise tag_simulator_curr tag_error_line
+ $editor tag raise tag_simulator_curr tag_bookmark
+ $editor tag raise tag_simulator_curr tag_trailing_space
+
+ # Insert the given data
+ if {$data != {}} {
+ $editor insert end $data
+ $editor edit modified 0
+ $editor edit reset
+ }
+
+ # Reset status modified
+ set modified 0
+
+ ## Set unredefinable event bindings for editor
+ # Set priorities
+ bindtags $editor [list $editor . all]
+ # Special keys
+ for {set i 1} {$i < 21} {incr i} {
+ bind $editor "<Key-F$i>" {continue}
+ }
+ bind $editor <Control-Key> {continue}
+ bind $editor <Alt-Key> {continue}
+ # Keep default
+ foreach key {
+ <ButtonRelease-1> <B1-Enter> <B1-Leave>
+ <B2-Motion> <MouseWheel>
+ } {
+ bind $editor $key [bind Text $key]
+ }
+
+ # Scroll wheel
+ bind $editor <Button-4> "$this scroll scroll -3 units; break"
+ bind $editor <Button-5> "$this scroll scroll +3 units; break"
+
+ # Other
+ foreach key {
+ <Double-Shift-Button-1> <Shift-Button-1>
+ <Triple-Shift-Button-1> <Control-Button-1>
+ <Control-Shift-Key-Right> <Control-Shift-Key-Left>
+ <Control-Key-Right> <Control-Key-Left>
+ <Shift-Key-Next> <Shift-Key-Prior>
+ <Shift-Key-Right> <Shift-Key-Left>
+ <Shift-Key-End> <Key-End>
+ <Control-Key-T>
+ } {
+ bind $editor $key "
+ [bind Text $key]
+ $this rightPanel_adjust \[expr {int(\[%W index insert\])}\]
+ $this recalc_status_counter {}
+ $this resetUpDownIndex
+ break"
+ }
+ bind $editor <Shift-Button-5> "
+ $this scroll scroll +30 lines
+ break
+ "
+ bind $editor <Shift-Button-4> "
+ $this scroll scroll -30 lines
+ break
+ "
+ bind $editor <Double-Button-1> "
+ if {\[string is alnum -strict \[%W get insert-1c insert\]\]} {
+ [bind Text <Double-Button-1>]
+ }
+
+ $this rightPanel_adjust \[expr {int(\[%W index insert\])}\]
+ $this recalc_status_counter {}
+ $this resetUpDownIndex
+ break"
+ bind $editor <Shift-Key-Down> "
+ if {\[catch {$this shift_down}\]} {
+ [bind Text <Shift-Key-Down>]
+ $this rightPanel_adjust \[expr {int(\[%W index insert\])}\]
+ $this recalc_status_counter {}
+ }
+ break"
+ bind $editor <Shift-Key-Up> "
+ if {\[catch {$this shift_up}\]} {
+ [bind Text <Shift-Key-Up>]
+ $this rightPanel_adjust \[expr {int(\[%W index insert\])}\]
+ $this recalc_status_counter {}
+ }
+ break"
+ bind $editor <Control-Insert> "$this copy; break"
+ bind $editor <Shift-Insert> "$this paste; break"
+ bind $editor <Shift-Delete> "$this cut; break"
+ bind $editor <Control-Key-Down> "$this control_down; break"
+ bind $editor <Control-Key-Up> "$this control_up; break"
+ bind $editor <Key-Down> "$this down; break"
+ bind $editor <Key-Up> "$this up; break"
+ bind $editor <Key-Home> "$this home_press; break"
+ bind $editor <Shift-Key-Home> "$this shift_home; break"
+ bind $editor <Key-Insert> "$this switch_ins_ovr; break"
+ bind $editor <Key-Tab> "$this tab_press; break"
+ if {!$::MICROSOFT_WINDOWS} {
+ bind $editor <Key-ISO_Left_Tab> "$this unindent; break"
+ }
+ bind $editor <Button-2> "$this paste 1 %x %y; break"
+ bind $editor <<Paste>> "$this paste; break"
+ bind $editor <<Cut>> "$this cut; break"
+ bind $editor <<Copy>> "$this copy; break"
+ bind $editor <Control-Key-V> "$this paste; break"
+ bind $editor <Control-Key-X> "$this cut; break"
+ bind $editor <Control-Key-C> "$this copy; break"
+ bind $editor <<Undo>> "$this undo; break"
+ bind $editor <<Redo>> "$this redo; break"
+ bind $editor <Shift-Return> "$this shift_enter; break"
+ bind $editor <Shift-KP_Enter> "$this shift_enter; break"
+ bind $editor <Return> "$this enter; break"
+ bind $editor <KP_Enter> "$this enter; break"
+ bind $editor <Key> "$this Key %A; break"
+ bind $editor <KeyRelease> "$this KeyRelease %K; break"
+ bind $editor <ButtonRelease-3> "$this popupMenu %X %Y %x %y; break"
+ bind $editor <Key-Menu> "$this Key_Menu; break"
+ bind $editor <Key-Escape> "$this key_escape"
+ bind $editor <Control-Key-y> "$this delete_current_line; break"
+ bind $editor <Key-BackSpace> "$this key_backspace; break"
+ bind $editor <Key-Delete> "$this key_delete; break"
+ bind $editor <Key-Prior> "
+ %W mark set insert {insert-30l}
+ $this scroll scroll -30 lines
+ $this resetUpDownIndex
+ $this rightPanel_adjust \[expr {int(\[%W index insert\])}\]
+ $this recalc_status_counter {}
+ break"
+ bind $editor <Key-Next> "
+ %W mark set insert {insert+30l}
+ $this scroll scroll +30 lines
+ $this resetUpDownIndex
+ $this rightPanel_adjust \[expr {int(\[%W index insert\])}\]
+ $this recalc_status_counter {}
+ break"
+ bind $editor <Control-Key-Next> "break"
+ bind $editor <Control-Key-Prior> "break"
+ bind $editor <Key-Left> "
+ [bind Text <Key-Left>]
+ $this resetUpDownIndex
+ $this recalc_status_counter {}
+ $this rightPanel_adjust \[expr {int(\[%W index insert\])}\]
+ break"
+ bind $editor <Key-Right> "
+ [bind Text <Key-Right>]
+ $this resetUpDownIndex
+ $this recalc_status_counter {}
+ $this rightPanel_adjust \[expr {int(\[%W index insert\])}\]
+ break"
+ bind $editor <Control-Key-t> "
+ set ln \[expr {int(\[$editor index insert\])}\]
+
+ $this autocompletion_maybe_important_change \$ln.0 \$ln.0
+ [bind Text <Control-Key-t>]
+ $this resetUpDownIndex
+ $this parse \$ln
+ $this manage_autocompletion_list \$ln
+ update
+ break"
+ bind $editor <<PasteSelection>> "
+ [bind Text <<PasteSelection>>]
+ $this resetUpDownIndex
+ $this recalc_left_frame
+ $this parse \[expr {int(\[$editor index insert\])}\]
+ catch {$editor tag remove sel sel.first sel.last}
+ update
+ break"
+ bind $editor <Button-1> "
+ [bind Text <Button-1>]
+ $this rightPanel_adjust \[expr {int(\[%W index insert\])}\]
+ $this resetUpDownIndex
+ $this recalc_status_counter {%x %y}
+ focus -force $editor
+ break"
+ bind $editor <B1-Motion> "
+ [bind Text <B1-Motion>]
+ $this rightPanel_adjust \[expr {int(\[%W index @%x,%y\])}\]
+ $this resetUpDownIndex
+ $this recalc_status_counter {%x %y}
+ break"
+ bind $editor <<Selection>> "$this editor_selection; break"
+
+
+ # Set event bindings for editor command line
+ bind $cmd_line <Key-Escape> "
+ \${::X::actualProject} cmd_line_off
+ pack forget $cmd_line
+ catch {$this cmd_line_menu_close_now}
+ focus $editor
+ update
+ break"
+ for {set i 1} {$i < 21} {incr i} {
+ bind $cmd_line <F$i> {continue}
+ bind $cmd_line <Control-F$i> {continue}
+ }
+ bind $cmd_line <Control-Key> {continue}
+ bind $cmd_line <Alt-Key> {continue}
+ bind $cmd_line <Control-a> {%W tag add sel {insert linestart} {insert lineend}; break}
+ bind $cmd_line <Key-Return> "$this cmd_line_enter; break"
+ bind $cmd_line <Key-KP_Enter> "$this cmd_line_enter; break"
+ bind $cmd_line <KeyPress> "$this cmd_line_key_press %A; break"
+ bind $cmd_line <Delete> "$this cmd_line_key Delete; break"
+ bind $cmd_line <BackSpace> "$this cmd_line_key BackSpace; break"
+ bind $cmd_line <Home> "$this cmd_line_key Home; break"
+ bind $cmd_line <End> "$this cmd_line_key End; break"
+ bind $cmd_line <Left> "$this cmd_line_key Left; break"
+ bind $cmd_line <Right> "$this cmd_line_key Right; break"
+ bind $cmd_line <Down> "if {\[$this cmd_line_down\]} {break}"
+ bind $cmd_line <Shift-Left> "if {!\[$this cmd_line_key SLeft\]} {break}"
+ bind $cmd_line <Shift-Right> "if {!\[$this cmd_line_key SRight\]} {break}"
+ foreach keysym {Shift-Home Shift-End Up} {
+ bind $cmd_line <$keysym> "[bind Text <$keysym>];break"
+ }
+ foreach keysym {Undo Redo Cut Copy Paste} {
+ bind $cmd_line <<$keysym>> "[bind Text <<$keysym>>];break"
+ }
+
+ # Create bindings for defined key shortcuts
+ shortcuts_reevaluate
+
+ # Create editor popup menu
+ set menu $editor.editor_menu
+ makePopupMenu
+
+ bind $editor <Configure> "$this Configure"
+ bind $editor <FocusIn> "$parentObject filelist_editor_selected $this"
+ bind $cmd_line <FocusIn> "$parentObject filelist_editor_selected $this"
+
+
+ # Set event bindings for "Line numbers"
+ bind $lineNumbers <Button-1> "
+ $parentObject filelist_editor_selected $this
+ focus -force $editor
+ $this lineNumbers_click %x %y
+ break"
+ bind $lineNumbers <ButtonRelease-3> "
+ $parentObject filelist_editor_selected $this
+ focus -force $editor
+ $this lineNumbers_popup_menu %X %Y %x %y
+ break"
+ bind $lineNumbers <Button-4> "$this scroll scroll -20 units; break"
+ bind $lineNumbers <Button-5> "$this scroll scroll +20 units; break"
+ bindtags $lineNumbers [list $lineNumbers . all]
+
+ # Set event bindings for "Icon border"
+ bind $iconBorder <Button-1> "
+ $parentObject filelist_editor_selected $this
+ focus -force $editor
+ $this iconBorder_click %x %y
+ break"
+ bind $iconBorder <ButtonRelease-3> "
+ $parentObject filelist_editor_selected $this
+ focus -force $editor
+ $this iconBorder_popup_menu %X %Y %x %y
+ break"
+ bind $iconBorder <Button-4> "$this scroll scroll -20 units; break"
+ bind $iconBorder <Button-5> "$this scroll scroll +20 units; break"
+ bindtags $iconBorder [list $iconBorder . all]
+
+ # Finalize initialization
+ set object_initialized 1
+ change_RO_MODE $ro_mode
+ }
+
+ ## Object destructor
+ destructor {
+ if {$editor_to_use} {
+ kill_childern
+ } {
+ # Stop autosave timer
+ catch {
+ after cancel $autosave_timer
+ }
+ # Cancel highlight dialog timer
+ if {$finishigh_hg_dlg_tmr != {}} {
+ after cancel $finishigh_hg_dlg_tmr
+ }
+ # Unregister statusbar tips
+ menu_Sbar_remove $menu
+ menu_Sbar_remove $IB_menu
+ menu_Sbar_remove $LN_menu
+ }
+
+ # Destroy main frame
+ destroy $ed_sc_frame
+ }
+
+ ## Adjust number of lines (height) in the editor text widget
+ # This function ensures that the editor text widget height conforms to
+ #+ height of its scrollbar / line_height
+ # @return void
+ private method adjust_editor_height {} {
+ set editor_height [$editor cget -height]
+ set nh [expr {int([winfo height $scrollbar] / $defaultCharHeight)}]
+ if {$nh == $editor_height} {
+ return
+ }
+ $editor configure -height $nh
+ $lineNumbers configure -height $nh
+ $iconBorder configure -height $nh
+ }
+
+ ## Refresh color setting (excluding highlightind)
+ # @return void
+ public method change_colors {} {
+ if {$editor_to_use} {return}
+
+ $lineNumbers configure -bg $lineNumbers_bg -fg $lineNumbers_fg
+ $left_frame_R configure -bg $lineNumbers_bg
+
+ $iconBorder configure -bg $iconBorder_bg
+ $left_frame_L configure -bg $iconBorder_bg
+
+ $editor configure -bg $normal_text_bg
+ $top_frame.f configure -bg $normal_text_bg
+ }
+
+ ## Refresh font setting (excluding highlightind)
+ # @return void
+ public method refresh_font_settings {} {
+ if {$editor_to_use} {return}
+
+ # Remove all text tags
+ foreach tag [$editor tag names] {
+ if {[lsearch {
+ sel tag_current_line tag_bookmark
+ tag_breakpoint tag_simulator_curr tag_error_line
+ } $tag] != -1
+ } then {
+ break
+ }
+ $editor tag remove $tag 1.0 end
+ }
+ # Change fonts
+ $iconBorder configure -font $defaultFont_bold
+ $lineNumbers configure -font $defaultFont_bold
+ $editor configure -font $defaultFont_bold
+
+ $lineNumbers tag configure right -justify right
+ $lineNumbers tag configure center -justify center
+ $lineNumbers tag raise center right
+ $iconBorder tag configure center -justify center
+
+ # Enable writing to the left border
+ $iconBorder configure -state normal
+ # Set new font
+ set defaultCharHeight_org $defaultCharHeight
+ set defaultFont [font create -size -$fontSize -family $fontFamily]
+ set defaultFont_bold [font create -size -$fontSize -family $fontFamily -weight {bold}]
+ set defaultCharWidth [font measure $defaultFont_bold -displayof $editor { }]
+ set defaultCharHeight [font metrics $defaultFont_bold -displayof $editor -linespace]
+ # Adjust bookmark images
+ if {$defaultCharHeight_org != $defaultCharHeight} {
+ set indexes {}
+ if {$defaultCharHeight_org < 9} {
+ set idx 1.0
+ set idx_prev $idx
+ while 1 {
+ set idx [$iconBorder search -exact -- {*} $idx]
+ if {$idx == {}} {break}
+ if {[$iconBorder compare $idx_prev >= $idx]} {break}
+ lappend indexes $idx
+ set idx_prev $idx
+ set idx [$iconBorder index "$idx+1c"]
+ }
+ } {
+ foreach img [$iconBorder image names] {
+ lappend indexes [$iconBorder index $img]
+ }
+ }
+ if {$defaultCharHeight < 9} {
+ foreach idx $indexes {
+ $iconBorder delete $idx "$idx+1c"
+ $iconBorder insert $idx {*}
+ }
+ } {
+ if {$defaultCharHeight < 15} {
+ set image {dot}
+ } {
+ set image {bookmark}
+ }
+ foreach idx $indexes {
+ $iconBorder delete $idx "$idx+1c"
+ $iconBorder image create $idx \
+ -image ::ICONS::16::$image \
+ -align center
+ }
+ }
+ }
+ # Disable writing to the left border
+ $iconBorder configure -state disabled
+ # Reset line wrap settings
+ set highlighted_lines [string repeat 0 [string bytelength $highlighted_lines]]
+ update idle
+ highlight_visible_area
+
+ # Adjust editor height
+ adjust_editor_height
+ }
+
+ ## Adjust Insert/Overwrite label on status bar
+ # @return void
+ private method adjust_INS_OVR_label {} {
+ if {$ins_ovr_mode} {
+ $ins_mode_lbl configure -text [mc "INS"] -fg #000000
+ $editor configure -blockcursor 0
+ } {
+ $ins_mode_lbl configure -text [mc "OVR"] -fg #FF0000
+ $editor configure -blockcursor 1
+ }
+ }
+
+ ## This function should be called after each column change
+ # -- Close popup completion menu
+ # @return void
+ public method resetUpDownIndex {} {
+ set lastUpDownIndex 0
+ }
+
+ ## Restore tags "Bookmark" and "Error" on the given line
+ # @parm Int line - line number
+ # @return void
+ private method restore_line_markers {line} {
+ # Restore bookmark
+ if {[lindex $bookmarks $line] == 1} {
+ $editor tag add tag_bookmark $line.0 "$line.0+1l"
+ }
+ # Restore tag error
+ if {
+ $prog_language != 2 &&
+ [llength [$editor tag nextrange tag_error $line.0 "$line.0 lineend"]]
+ } then {
+ $editor tag add tag_error_line $line.0 "$line.0+1l"
+ }
+ }
+
+ ## Determinate whether editor text has been modified
+ # and adjust internal variables
+ # @parm bool force - 1: "I'm sure it has been modified !"
+ # 0: "discover it automaticaly"
+ # @return bool - a new modified flag or {}
+ public method recalc_status_modified {force} {
+
+ # Modified
+ if {[$editor edit modified] || $force} {
+
+ # Adjust editor status bar
+ $Sbar_image configure \
+ -image ::ICONS::16::filesave \
+ -helptext [mc "File has been modified, click to save"]
+ pack $Sbar_image -side left
+
+ # Set modified flag
+ set modified 1
+
+ # Start autosave timer
+ if {$autosave} {
+ catch {
+ after cancel $autosave_timer
+ }
+ set autosave_timer [after [expr {$autosave * 60000}] [list $this save]]
+ }
+
+ # Not modifed
+ } {
+ # Adjust editor status bar
+ pack forget $Sbar_image
+
+ # Set modified flag
+ set modified 0
+
+ # Stop autosave timer
+ catch {
+ after cancel $autosave_timer
+ }
+ }
+
+ ::X::adjust_title
+
+ # Return modified flag
+ return $modified
+ }
+
+ ## Call ::configDialogs::mkDialog $args
+ # @return void
+ public method configDialogs_mkDialog args {
+ ::configDialogs::editor::mkDialog $args
+ }
+
+ ## Recalculate variables related to bookmarks, line numbers and list of highlighted lines
+ # @parm Bool force = 1 - perform recalcutaion even if length of text wasn't changed
+ # @return bool - 0: failed; 1: successful
+ public method recalc_left_frame args {
+ if {$editor_to_use} {return}
+
+ # Parse arguments
+ set force [lindex $args 0]
+ if {$force == {}} {
+ set force 0
+ }
+
+ # Determinate editor lines count and End index
+ set End [$editor index end]
+ set Tlines [expr {int($End)}]
+
+ # Current line number -> Actline
+ set insert [$editor index insert]
+ set Actline [expr {int($insert)}]
+
+ # Return if lines count has not been changed
+ if {!$force && $lastEnd == $Tlines} {
+ return 0
+ }
+ incr Tlines -1
+
+ # Determinate iconBorder lines count - 1
+ set Ilines [expr {int([$iconBorder index end]) - $number_of_wraps}]
+ incr Ilines -1
+
+ # Remove wrap markers from line numbers
+ if {$number_of_wraps && ($Ilines != $Tlines)} {
+ $lineNumbers configure -state normal
+ set remaining $number_of_wraps
+ set i 1
+ foreach wrap $map_of_wraped_lines {
+ if {$wrap > 0} {
+ $lineNumbers delete $i.0 $i.0+${wrap}l
+ incr remaining -$wrap
+ }
+ if {!$remaining} {break}
+ incr i
+ }
+ }
+
+ ## Some lines have been removed
+ if {$Ilines > $Tlines} {
+ # Determinate how many lines should be removed
+ regexp {\d+$} $insert cur_line_col
+ if {$cur_line_col != 0} {
+ set Actline_m1 $Actline
+ incr Actline
+ restore_line_markers $Actline_m1
+ }
+
+ set diff $Actline
+ incr diff -$Tlines
+ incr diff $Ilines
+
+ # Delete bookmark icon(s) from left bar
+ $iconBorder configure -state normal
+ set Actline_tmp $Actline
+ set diff_tmp $diff
+ if {$number_of_wraps} {
+ set remaining $number_of_wraps
+ for {set i 1} {$i < $diff} {incr i} {
+ set wrap [lindex $map_of_wraped_lines $i]
+ if {$wrap < 0} {
+ set wrap 0
+ }
+ incr diff_tmp $wrap
+ if {$i < $Actline} {
+ incr Actline_tmp $wrap
+ }
+ incr remaining -$wrap
+ if {!$remaining} {break}
+ }
+ }
+ $iconBorder delete $Actline_tmp.0 $diff_tmp.0
+ $iconBorder configure -state disabled
+
+ # Unregister bookmarks for deletion
+ incr diff -1
+ set bookmarks [lreplace $bookmarks $Actline $diff]
+ set breakpoints [lreplace $breakpoints $Actline $diff]
+ for {set i $Actline} {$i <= $diff} {incr i} {
+ set number_of_wraps [expr {$number_of_wraps - [lindex $map_of_wraped_lines $i]}]
+ }
+ set map_of_wraped_lines [lreplace $map_of_wraped_lines $Actline $diff]
+ set highlighted_lines [string replace $highlighted_lines $Actline $diff]
+
+ # Adjust the right panel
+ $parentObject rightPanel_remove_bookmarks $Actline $diff
+ $parentObject rightPanel_remove_breakpoints $Actline $diff
+ $parentObject rightPanel_shift_symbols $Actline [expr {$Actline - $diff - 1}]
+
+ # rewrite breakpoints
+ rewrite_breakpoint_tags
+
+ ## Some lines have been added
+ } elseif {$Ilines < $Tlines} {
+ # Determinate how many lines should be added
+ set diff $Tlines
+ incr diff -$Ilines
+ set ins [string repeat "\n" $diff]
+ set BMStr [string range [string repeat {0 } $diff] 0 end-1]
+ set insIndex $Actline
+ incr insIndex -$diff
+ if {$insIndex == 0} {incr insIndex}
+ set insLineEnd [$editor index "$insIndex.0 lineend"]
+ regexp {\d+$} $insLineEnd ins_line_col
+
+ set insIndex_1 $insIndex
+ incr insIndex_1
+
+ if {$ins_line_col != 0} {
+ # Remove tag "Bookmark"
+ if {[lindex $bookmarks $insIndex] == 1} {
+ $editor tag remove tag_bookmark $insIndex.0 [expr {$Actline + 1}].0
+ }
+
+ # Adjust insert index
+ incr insIndex
+ incr insIndex_1
+
+ # Prepare lists
+ if {[string length $highlighted_lines] == $insIndex} {
+ append highlighted_lines 0
+ }
+ if {[llength $bookmarks] == $insIndex} {
+ lappend bookmarks 0
+ }
+ if {[llength $breakpoints] == $insIndex} {
+ lappend breakpoints 0
+ }
+ if {[llength $map_of_wraped_lines] == $insIndex} {
+ lappend map_of_wraped_lines 0
+ }
+
+ # Adjust list of highlighted lines
+ set highlighted_lines [string replace $highlighted_lines \
+ [expr {$insIndex - 1}] [expr {$insIndex - 1}] \
+ [string repeat 0 [expr {$diff + 1}]]]
+
+ # Adjust bookmark and breakpoint lists
+ set map_of_wraped_lines [linsert $map_of_wraped_lines $insIndex $BMStr]
+ set bookmarks [linsert $bookmarks $insIndex $BMStr]
+ set breakpoints [linsert $breakpoints $insIndex $BMStr]
+ regsub -all {[\{\}]} $map_of_wraped_lines {} map_of_wraped_lines
+ regsub -all {[\{\}]} $bookmarks {} bookmarks
+ regsub -all {[\{\}]} $breakpoints {} breakpoints
+
+ # Shift bookmarks and breakpoints on the right panel
+ $parentObject rightPanel_shift_bookmarks $insIndex $diff
+ $parentObject rightPanel_shift_breakpoints $insIndex $diff
+ $parentObject rightPanel_shift_symbols $insIndex $diff
+
+ if {[lindex $bookmarks [expr {$insIndex - 1}]] == 1} {
+ $editor tag add tag_bookmark [expr {$insIndex - 1}].0 $insIndex.0
+ }
+
+ } {
+ # Adjust list of highlighted lines
+ set highlighted_lines [string replace \
+ $highlighted_lines $insIndex $insIndex \
+ [string repeat 0 [expr {$diff + 1}]]]
+
+ # Adjust bookmark and breakpoint lists
+ set map_of_wraped_lines [linsert $map_of_wraped_lines $insIndex $BMStr]
+ set bookmarks [linsert $bookmarks $insIndex $BMStr]
+ set breakpoints [linsert $breakpoints $insIndex $BMStr]
+ regsub -all {[\{\}]} $map_of_wraped_lines {} map_of_wraped_lines
+ regsub -all {[\{\}]} $bookmarks {} bookmarks
+ regsub -all {[\{\}]} $breakpoints {} breakpoints
+
+ $parentObject rightPanel_shift_bookmarks $insIndex $diff
+ $parentObject rightPanel_shift_breakpoints $insIndex $diff
+ $parentObject rightPanel_shift_symbols $insIndex $diff
+ }
+
+ $iconBorder configure -state normal
+ if {$number_of_wraps} {
+ set insIndex_tmp $insIndex
+ for {set i 1} {$i < $insIndex_tmp} {incr i} {
+ incr insIndex [lindex $map_of_wraped_lines $i]
+ }
+ }
+ $iconBorder insert $insIndex.0 $ins
+ $iconBorder configure -state disabled
+
+ # rewrite breakpoints
+ rewrite_breakpoint_tags
+ }
+
+ ## Recalculate Line Numbers
+ # Prepare Line Numbers
+ if {$Tlines != [expr {int([$lineNumbers index end]) - 1}]} {
+ # Enable the widget
+ $lineNumbers configure -state normal
+ }
+
+ # Determinate LineNumbers lines count - 1
+ set Llines [expr {int([$lineNumbers index end])}]
+ incr Llines -1
+
+ if {$Llines > $Tlines} { ;# too many lines -> remove some ones
+ $lineNumbers delete $End end
+
+ } elseif {$Llines < $Tlines} { ;# not enought lines -> add some ones
+ # Create string to insert to Line Numbers
+ set ins {}
+ for {set i [expr {$Llines + 1}]} {$i <= $Tlines} {incr i} {
+ append ins "\n$i"
+ }
+
+ # Insert it at the end of widget and adjust widget width
+ $lineNumbers insert end $ins
+ }
+
+ # Finalize
+ if {$Llines != $Tlines} {
+ # Adjust widget width
+ $lineNumbers configure -width [string length [expr {int([$lineNumbers index end]) - 1}]]
+ # Restore wrap markers
+ if {$number_of_wraps} {
+ set remaining $number_of_wraps
+ set i 1
+ foreach wrap $map_of_wraped_lines {
+ if {$wrap > 0} {
+ $lineNumbers insert $i.0 [string repeat "$wrap_char\n" $wrap]
+ $lineNumbers tag add center $i.0 [expr {$i + $wrap}].0
+ incr i $wrap
+ incr remaining -$wrap
+ }
+ if {!$remaining} {break}
+ incr i
+ }
+ }
+ # Disable Line Numbers
+ $lineNumbers configure -state disabled
+ }
+ scrollSet [lindex [$editor yview] 0] [lindex [$editor yview] 1]
+ $lineNumbers tag add right 1.0 end
+ $iconBorder tag add center 1.0 end
+
+ # Parse the current line
+ parse $Actline
+ highlight_visible_area
+
+ # Save last lines count
+ set lastEnd [expr {int($End)}]
+ # done ...
+ return 1
+ }
+
+ ## Select appropriate item in right panel lists (bookmarks and breapoints)
+ # @parm Int lineNumber - current line
+ # @return void
+ public method rightPanel_adjust {lineNumber} {
+
+ # Adjust list of bookmarks
+ if {[lindex $bookmarks $lineNumber] == 1} {
+ $parentObject rightPanel_bm_select $lineNumber
+ } {
+ $parentObject rightPanel_bm_unselect
+ }
+
+ # Adjust list of breakpoints
+ if {[lindex $breakpoints $lineNumber] == 1} {
+ $parentObject rightPanel_bp_select $lineNumber
+ } {
+ $parentObject rightPanel_bp_unselect
+ }
+ }
+
+ ## Line wrapping manager - variant 2
+ # Adjust map of wrapped lines and left border to wrap of the specified line
+ # This function using function 'get_count_of_lines' (slow)
+ # @parm Int line_number - Line number
+ # @return Bool - result
+ private method wrap_mgr2 {line_number} {
+ # Check if editor is properly initialized
+ if {$editor_width <= 0 || $map_of_wraped_lines == {}} {return 1}
+
+ # Not empty line
+ if {[$editor compare [$editor index "$line_number.0 linestart"] != "$line_number.0 lineend"]} {
+ set new_wrap [get_count_of_lines $line_number.0 "$line_number.0 lineend"]
+ incr new_wrap -1
+ # Empty line
+ } {
+ set new_wrap 0
+ }
+
+ # Determinate the current wrap factor
+ set wrap [lindex $map_of_wraped_lines $line_number]
+ if {$new_wrap == $wrap} {return 1}
+
+ # Adjust map of wrapped lines
+ if {$line_number >= [llength $map_of_wraped_lines]} {
+ Configure
+ return
+ } {
+ lset map_of_wraped_lines $line_number $new_wrap
+ }
+
+ # Adjust line number
+ set line_number_tmp $line_number
+ for {set i 1} {$i < $line_number_tmp} {incr i} {
+ incr line_number [lindex $map_of_wraped_lines $i]
+ }
+ incr line_number
+
+ # Adjust left border and number of line wraps
+ set scroll_in_progress 1
+ $lineNumbers configure -state normal
+ $iconBorder configure -state normal
+ if {$new_wrap > $wrap} {
+ set diff [expr {$new_wrap - $wrap}]
+ set ins [string repeat "$wrap_char\n" $diff]
+ incr number_of_wraps $diff
+ $lineNumbers insert $line_number.0 $ins
+ $iconBorder insert $line_number.0 $ins
+ $lineNumbers tag add center $line_number.0 [expr {$line_number + $diff}].0
+ } elseif {$new_wrap < $wrap} {
+ set diff [expr {$wrap - $new_wrap}]
+ incr number_of_wraps $diff
+ $lineNumbers delete $line_number.0 $line_number.0+${diff}l
+ $iconBorder delete $line_number.0 $line_number.0+${diff}l
+ }
+ $lineNumbers configure -state disabled
+ $iconBorder configure -state disabled
+ set scroll_in_progress 0
+
+ # Success
+ return 1
+ }
+
+ ## Line wrapping manager - variant 1
+ # Adjust map of wrapped lines and left border to wrap of the specified line
+ # This function is using method 'dlineinfo' (fast)
+ # @parm Int line_number - Line number
+ # @return Bool - result
+ private method wrap_mgr {line_number} {
+ # Check if editor is properly initialized
+ if {$editor_width <= 0 || $map_of_wraped_lines == {}} {return 1}
+
+ # Deterinate current and previous wrap factor
+ set new_wrap [lindex [$editor dlineinfo $line_number.0+1l] 1]
+ set wrap [lindex [$editor dlineinfo $line_number.0] 1]
+ if {$wrap == {} || $new_wrap == {}} {
+ return 0
+ }
+ set new_wrap [expr {($new_wrap - $wrap) / $defaultCharHeight - 1}]
+ set wrap [lindex $map_of_wraped_lines $line_number]
+ if {$new_wrap == $wrap} {return 1}
+
+ # Adjust map of wrapped lines
+ if {$line_number >= [llength $map_of_wraped_lines]} {
+ Configure
+ return
+ } {
+ lset map_of_wraped_lines $line_number $new_wrap
+ }
+
+ # Adjust line number
+ set line_number_tmp $line_number
+ for {set i 1} {$i < $line_number_tmp} {incr i} {
+ incr line_number [lindex $map_of_wraped_lines $i]
+ }
+ incr line_number
+
+ # Adjust left border
+ set scroll_in_progress 1
+ $lineNumbers configure -state normal
+ $iconBorder configure -state normal
+ if {$new_wrap > $wrap} {
+ set diff [expr {$new_wrap - $wrap}]
+ set ins [string repeat "$wrap_char\n" $diff]
+ incr number_of_wraps $diff
+ $lineNumbers insert $line_number.0 $ins
+ $iconBorder insert $line_number.0 $ins
+ $lineNumbers tag add center $line_number.0 [expr {$line_number + $diff}].0
+ } elseif {$new_wrap < $wrap} {
+ set diff [expr {$wrap - $new_wrap}]
+ incr number_of_wraps $diff
+ $lineNumbers delete $line_number.0 $line_number.0+${diff}l
+ $iconBorder delete $line_number.0 $line_number.0+${diff}l
+ }
+ $lineNumbers configure -state disabled
+ $iconBorder configure -state disabled
+ set scroll_in_progress 0
+
+ # Success
+ return 1
+ }
+
+ ## Reset map of wrapped lines and count of line wraps
+ # @return void
+ public method reset_wraped_lines {} {
+ set number_of_wraps 0
+ set map_of_wraped_lines [string repeat {0 } [expr {int([$editor index end])}]]
+ return
+ }
+
+ ## Create highlight dialog
+ # @return void
+ public method open_highlight_wait_dialog {} {
+ # Create dialog frame
+ set finishigh_hg_dlg_wdg [frame $ed_sc_frame.hg_dialog \
+ -bg {#EEEEFF} -bd 2 -relief raised \
+ ]
+
+ # Create heder label
+ pack [label $finishigh_hg_dlg_wdg.label \
+ -text [mc "Finishing highlight"]\
+ -bg {#EEEEFF} -fg {#0000FF} \
+ ] -fill x
+ # Create progress bar
+ pack [ttk::progressbar $finishigh_hg_dlg_wdg.progressbar\
+ -mode determinate -orient horizontal \
+ -maximum $finishigh_hg_dlg_max \
+ -variable ::Editor::finishigh_hg_dlg_const \
+ ] -fill x -pady 5 -padx 5
+
+ # Show dialog
+ place $finishigh_hg_dlg_wdg \
+ -width 200 -height 45 -in $ed_sc_frame \
+ -x -100 -y -25 -relx 0.5 -rely 0.5
+ raise $finishigh_hg_dlg_wdg
+ grab $finishigh_hg_dlg_wdg
+ update
+ }
+
+ ## Close highlight dialog
+ # @return void
+ private method close_highlight_wait_dialog {} {
+ if {$finishigh_hg_dlg_tmr != {}} {
+ after cancel $finishigh_hg_dlg_tmr
+ set finishigh_hg_dlg_tmr {}
+ }
+ if {[winfo exists $finishigh_hg_dlg_wdg]} {
+ grab release $finishigh_hg_dlg_wdg
+ destroy $finishigh_hg_dlg_wdg
+ }
+ }
+
+ ## Perform syntax highlight for C language on specified line
+ # @return void
+ private method c_syntax_highlight {lineNumber} {
+ # Get highlight status of the previous line
+ if {$lineNumber > 1} {
+ set highlight_status [string index $highlighted_lines [expr {$lineNumber - 1}]]
+ if {$highlight_status == {}} {
+ set highlight_status 0
+ }
+ } {
+ set highlight_status 1
+ }
+
+ # Highlighted all lines before the current one
+ if {!$highlight_status} {
+ # determinate highlight status of previous line
+ set i [string first 0 $highlighted_lines 1]
+ set highlight_status [string index $highlighted_lines [expr {$i - 1}]]
+ if {$highlight_status == {}} {
+ set highlight_status 1
+ }
+
+ # Highlight dialog
+ set finishigh_hg_dlg_const 0
+ set finishigh_hg_dlg_max [expr {($lineNumber - $i) / 500}]
+ if {$object_initialized && $finishigh_hg_dlg_tmr == {}} {
+ set finishigh_hg_dlg_tmr [after 500 "$this open_highlight_wait_dialog"]
+ }
+
+ # Highlight preceeding lines
+ for {set j 0} {$i < $lineNumber} {incr i; incr j} {
+ highlight_trailing_space $i
+ set highlight_status [CsyntaxHighlight::highlight $editor $i $highlight_status]
+ autocompletion_c_syntax_analyze $i
+ set highlighted_lines [string replace $highlighted_lines $i $i $highlight_status]
+
+ if {$j > 500} {
+ set j 0
+ incr finishigh_hg_dlg_const
+ update
+ }
+ }
+
+ # Close highlight dialog
+ if {$object_initialized} {
+ close_highlight_wait_dialog
+ }
+ }
+
+ # Highlight this line
+ set i $lineNumber
+ set last_visible_line [expr {int([lindex [$editor yview] 1] * int([$editor index end])) + 1}]
+
+ # Highlight all line after the current one until it is nessesary
+ while 1 {
+ autocompletion_maybe_important_change $i.0 $i.0
+ set highlight_status_org [string index $highlighted_lines $i]
+ set highlight_status [CsyntaxHighlight::highlight $editor $i $highlight_status]
+ autocompletion_c_syntax_analyze $i
+ set highlighted_lines \
+ [string replace $highlighted_lines $i $i $highlight_status]
+ if {
+ $highlight_status_org != 0 &&
+ $highlight_status_org != {} &&
+ $highlight_status_org != $highlight_status
+ } then {
+ incr i
+ } else {
+ break
+ }
+ if {$i > $last_visible_line} {
+ set highlighted_lines \
+ [string replace $highlighted_lines $i end \
+ [string repeat 0 [expr { \
+ [string length $highlighted_lines] - $i
+ }] \
+ ] \
+ ]
+ break
+ }
+ }
+ }
+
+ ## Highlight trailing space
+ # @parm Int lineNumber - number of the target line
+ # @return void
+ private method highlight_trailing_space {lineNumber} {
+ $editor tag remove tag_trailing_space $lineNumber.0 [list $lineNumber.0 lineend]
+ if {$hg_trailing_sp && [regexp {[\t  ]+$} [$editor get $lineNumber.0 [list $lineNumber.0 lineend]] space]} {
+ $editor tag add tag_trailing_space \
+ [list $lineNumber.0 lineend]-[string length $space]c \
+ [list $lineNumber.0 lineend]
+ }
+ }
+
+ ## Parse given line
+ # Restore highlight, recalculate counters on status bar, adjust right panel
+ # @parm Int lineNumber - number of the target line
+ # @return Bool - result from wrap manager
+ public method parse {lineNumber} {
+ # Check if the given line number is valid
+ if {$lineNumber >= int([$editor index end])} {
+ set lineNumber [expr {int([$editor index end]) - 1}]
+ }
+
+ # Is the given line number is the current line ?
+ if {int([$editor index insert]) == $lineNumber} {
+ set curLine 1
+ } {
+ set curLine 0
+ }
+
+ # Highlight trailing space
+ highlight_trailing_space $lineNumber
+
+ # Basic validation
+ if {!$curLine || !${::ASMsyntaxHighlight::validation_L1}} {
+ ## Restore highlight
+ # Assembly language
+ if {$prog_language == 0} {
+ ASMsyntaxHighlight::highlight $editor $lineNumber
+
+ # Adjust list of highlighted lines
+ if {[string index $highlighted_lines $lineNumber] == 0} {
+ set highlighted_lines \
+ [string replace $highlighted_lines $lineNumber $lineNumber 1]
+ }
+
+ # C language
+ } elseif {$prog_language == 1} {
+ c_syntax_highlight $lineNumber
+
+ # Code listing
+ } elseif {$prog_language == 2} {
+ LSTsyntaxHighlight::highlight $editor $lineNumber
+
+ # Adjust list of highlighted lines
+ if {[string index $highlighted_lines $lineNumber] == 0} {
+ set highlighted_lines \
+ [string replace $highlighted_lines $lineNumber $lineNumber 1]
+ }
+
+ # ASX8051
+ } elseif {$prog_language == 3} {
+ R_ASMsyntaxHighlight::highlight $editor $lineNumber
+
+ # Adjust list of highlighted lines
+ if {[string index $highlighted_lines $lineNumber] == 0} {
+ set highlighted_lines \
+ [string replace $highlighted_lines $lineNumber $lineNumber 1]
+ }
+
+ # No highlighting
+ } else {
+ set highlight_status 1
+ }
+
+ manage_autocompletion_list $lineNumber
+
+ # Finalize validation
+ validate_line $lineNumber 0
+ }
+
+ # Recalculate counters on status bar
+ if {$curLine} {
+ recalc_status_counter {}
+ }
+
+ # Put tag "tag_error_line" (but not for code listing)
+ if {$prog_language != 2} {
+ set add 0
+ set remove 0
+
+ if {${::ASMsyntaxHighlight::validation_L0}} {
+ if {[llength [$editor tag nextrange tag_error $lineNumber.0 [list $lineNumber.0 lineend]]]} {
+ set add 1
+ } {
+ set remove 1
+ }
+ # Remove tag "tag_error_line"
+ } elseif {!${::ASMsyntaxHighlight::validation_L1}} {
+ set remove 1
+ }
+
+ if {$add || $remove} {
+ $iconBorder configure -state normal
+ if {$add} {
+ $editor tag add tag_error_line $lineNumber.0 $lineNumber.0+1l
+
+ if {$defaultCharHeight >= 15} {
+ set lineNumber_i [wrap_aux_idx2line $lineNumber]
+ $iconBorder delete $lineNumber_i.0 $lineNumber_i.2
+
+ if {[lindex $bookmarks $lineNumber] == 1} {
+ set image {bm_ex}
+ } {
+ set image {exclamation}
+ }
+
+ $iconBorder image create $lineNumber_i.0 \
+ -image ::ICONS::16::$image \
+ -align center
+ }
+
+ } else {
+ $editor tag remove tag_error_line $lineNumber.0 $lineNumber.0+1l
+
+ if {$defaultCharHeight >= 15} {
+ set lineNumber_i [wrap_aux_idx2line $lineNumber]
+ $iconBorder delete $lineNumber_i.0 $lineNumber_i.2
+
+ if {[lindex $bookmarks $lineNumber] == 1} {
+ $iconBorder image create $lineNumber_i.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ }
+ }
+ $iconBorder configure -state disabled
+ }
+ }
+
+ if {$curLine} {
+ resetUpDownIndex
+ recalc_status_modified 0
+ }
+
+ # Agjust right panel
+ rightPanel_changeLineContent $lineNumber
+
+ set result [wrap_mgr $lineNumber]
+ if {!$result} {
+ wrap_mgr2 $lineNumber
+ }
+ return $result
+ }
+
+ ## Finalize syntax validation on the given line (validates operands only)
+ # @parm Int - Number of line in source code
+ # @parm Bool = 1 - Affect panel "Instruction details"
+ # @return void
+ private method validate_line args {
+ # Parse input arguments
+ set line [lindex $args 0]
+ set ins_det [lindex $args 1]
+ if {$ins_det == {}} {
+ set ins_det 1
+ }
+
+ # Check if basic validation is enabled
+ if {!${::ASMsyntaxHighlight::validation_L0}} {return}
+
+ # Detereminate range of instruction tag
+ set ins_range [$editor tag nextrange tag_instruction $line.0 "$line.0 lineend"]
+
+ # Detereminate instruction name
+ if {[llength $ins_range]} {
+ set instruction [$editor get [lindex $ins_range 0] [lindex $ins_range 1]]
+ set instruction [string tolower $instruction]
+
+ if {[lsearch -ascii -exact ${CompilerConsts::AllInstructions} $instruction] == -1} {
+ return
+ }
+ } {
+ return
+ }
+
+ # Inset selection in "Instruction details" tab on the Right Panel
+ if {$ins_det} {
+ $parentObject rightPanel_ins_unselect
+ }
+
+ # Check for allowed number of operands
+ if {
+ ${::ASMsyntaxHighlight::operands_count}
+ !=
+ [lindex $::CompilerConsts::InstructionDefinition($instruction) 0]
+ } then {
+ $editor tag add tag_error [lindex $ins_range 0] [lindex $ins_range 1]
+ return
+ }
+
+ # Handle instruction without operands
+ if {!${::ASMsyntaxHighlight::operands_count}} {
+ if {$ins_det} {
+ $parentObject rightPanel_ins_select 1 0
+ }
+ return
+ }
+
+ # Check for valid operand types
+ if {${::ASMsyntaxHighlight::validation_L1}} {
+ # Local variables
+ set matches {} ;# List of matched operand sets
+ set matches0 {} ;# List of not perfectly matched operand sets
+
+ # Iterate over simple definitions and find matches
+ set operands ${::ASMsyntaxHighlight::opr_types}
+ set operands_org $operands
+ for {set i 0} {$i < 3} {incr i} {
+
+ set idx 0
+ foreach opr_set $CompilerConsts::SimpleOperandDefinitions($instruction) {
+ if {$opr_set == $operands} {
+ if {$i} {
+ lappend matches0 $idx
+ } {
+ lappend matches $idx
+ }
+ }
+ incr idx
+ }
+
+ # Try to change operand set without changing meaning
+ while {$i < 2} {
+ if {
+ [lindex $operands $i] != {A}
+ &&
+ [lindex $operands $i] != {C}
+ } then {
+ incr i
+ continue
+ }
+
+ set operands $operands_org
+ if {[lindex $operands $i] == {A}} {
+ lset operands $i {D}
+ } elseif {[lindex $operands $i] == {C}} {
+ lset operands $i {D}
+ }
+ break
+ }
+ }
+
+ # Highlight coresponding operand sets in "Instruction details"
+ if {[llength $matches] || [llength $matches0]} {
+ if {$ins_det} {
+ if {[llength $matches]} {
+ $parentObject rightPanel_ins_select 1 $matches
+ }
+ if {[llength $matches0]} {
+ $parentObject rightPanel_ins_select 0 $matches0
+ }
+ }
+ } {
+ $editor tag add tag_error [lindex $ins_range 0] [lindex $ins_range 1]
+ }
+
+ # Check for legal usege of SFRs and SFBs
+ set sfr_range_start $line.0
+ set sfr_range {}
+ set sfr_name {}
+ while 1 {
+ # Try to find SFR
+ set sfr_range [$editor tag nextrange tag_sfr $sfr_range_start [list $line.0 lineend]]
+ if {![llength $sfr_range]} {
+ break
+ }
+
+ # Check for its legality
+ set sfr_range_start [lindex $sfr_range 1]
+ set sfr_name [$editor get [lindex $sfr_range 0] [lindex $sfr_range 1]]
+
+ if {[string index $sfr_name 0] == {/}} {
+ set sfr_name [string range $sfr_name 1 end]
+ }
+
+ if {
+ [lsearch -ascii -exact \
+ [$parentObject cget -avaliable_SFR] \
+ [string toupper $sfr_name] \
+ ] == -1
+ } then {
+ $editor tag add tag_error [lindex $sfr_range 0] [lindex $sfr_range 1]
+ }
+ }
+ }
+ }
+
+ ## Adjust content of the given line in list of bookmakrs and list of breakpoint (in right panel)
+ # This function should be called after change content of any line
+ # @parm Int lineNumber - line number
+ # @return void
+ private method rightPanel_changeLineContent {lineNumber} {
+ # Adjust list of bookmarks
+ if {[lindex $bookmarks $lineNumber] == 1} {
+ $parentObject rightPanel_remove_bookmark $lineNumber
+ $parentObject rightPanel_add_bookmark $lineNumber
+ $parentObject rightPanel_bm_select $lineNumber
+ }
+ # Adjust list of breakpoints
+ if {[lindex $breakpoints $lineNumber] == 1} {
+ $parentObject rightPanel_remove_breakpoint $lineNumber
+ $parentObject rightPanel_add_breakpoint $lineNumber
+ $parentObject rightPanel_bp_select $lineNumber
+ }
+ }
+
+ ## Convert editor line number to left border line number
+ # @parm Int idx - line number (in editor)
+ # @return Int - line number (in left border)
+ private method wrap_aux_idx2line {idx} {
+ if {$number_of_wraps} {
+ set remaining $number_of_wraps
+ set line $idx
+ for {set i 1} {$i < $idx} {incr i} {
+ set wrap [lindex $map_of_wraped_lines $i]
+ if {$wrap < 0} {
+ set wrap 0
+ }
+ incr line $wrap
+ incr remaining -$wrap
+ if {!$remaining} {break}
+ }
+ return $line
+ } else {
+ return $idx
+ }
+ }
+
+ ## Convert left border line number to editor line number
+ # @parm Int idx - line number (in left border)
+ # @return Int - line number (in editor)
+ private method wrap_aux_line2idx {line} {
+ if {$number_of_wraps} {
+ set i 1
+ while 1 {
+ incr line [expr { -1 - [lindex $map_of_wraped_lines $i]}]
+ if {$line < 1 || $line == {}} {break}
+ incr i
+ }
+ return $i
+ } else {
+ return $line
+ }
+ }
+
+ ## Focus on the editor widget
+ # @return void
+ public method focus_in {} {
+ focus $editor
+ }
+
+ ## Get ranges for all highlighting tags on the given line
+ # @parm Int lineNum - line number
+ # @return List - tag ranges {{tag_name {start_idx end_idx ...}} ... }
+ public method getTagsRanges {lineNum} {
+ # Initialize resulting ranges
+ set ranges {}
+
+ # Determnate end index
+ set endIdx [$editor index "$lineNum.0 lineend"]
+
+ # Iterate over defined highlighting tags
+ foreach tag [concat \
+ ${ASMsyntaxHighlight::hightlight_tags} \
+ ${CsyntaxHighlight::hightlight_tags} \
+ ${LSTsyntaxHighlight::hightlight_tags} \
+ {tag_macro_def tag_constant_def} \
+ ] {
+
+ # Determinate tag name
+ set tag [lindex $tag 0]
+
+ # Determinate range of the tag
+ set range {}
+ while 1 {
+ # Determinate start index
+ set startIdx [lindex $range [expr {[llength $range] - 1}]]
+ if {$startIdx == {}} {
+ set startIdx $lineNum.0
+ }
+ # Gain tag range
+ set rng [$editor tag nextrange $tag $startIdx $endIdx]
+ if {![llength $rng]} {break}
+ # Append range
+ append range $rng
+ append range { }
+ }
+ set range [string range $range 0 {end-1}]
+
+ # Skip empty ranges
+ if {[llength $range] == 0} {continue}
+
+ # Append the range to result
+ lappend tag $range
+ lappend ranges $tag
+ }
+
+ # Return resulting range
+ return $ranges
+ }
+
+ ## Restore breakpoint tags in "Line numbers"
+ # @return void
+ private method rewrite_breakpoint_tags {} {
+ if {$editor_to_use} {return}
+
+ # Enable line numbers
+ $lineNumbers configure -state normal
+
+ # Remove current tags
+ $lineNumbers tag remove tag_breakpoint 1.0 end
+ # Restore tags
+ foreach line [lsearch -ascii -exact -all $breakpoints 1] {
+ append line {.0}
+ $lineNumbers tag add tag_breakpoint $line "$line+1l"
+ }
+
+ # Disable line numbers
+ $lineNumbers configure -state disabled
+ }
+
+ ## Define line markers (bookmark, breakpoint, simulator line, etc.)
+ # @return void
+ public method define_line_markers {} {
+ if {$editor_to_use} {return}
+
+ # Iterate over definition
+ foreach tag_definition $line_markers {
+ # Create tag in editor
+ $editor tag configure [lindex $tag_definition 0] -background [lindex $tag_definition 1]
+ # Create tag in line numbers
+ if {[lindex $tag_definition 0] == {tag_breakpoint}} {
+ $lineNumbers tag configure [lindex $tag_definition 0] \
+ -background [lindex $tag_definition 1] -relief raised -borderwidth 1
+ }
+ }
+ $editor tag configure tag_current_line -borderwidth 0 -relief flat
+ }
+
+ ## Create bindings for defined key shortcuts
+ # @return void
+ public method shortcuts_reevaluate {} {
+ # Unset previous configuration
+ foreach key $set_shortcuts {
+ bind $editor <$key> {}
+ }
+ set set_shortcuts {}
+
+ # Iterate over shortcuts definition
+ foreach block ${::SHORTCUTS_LIST} {
+ # Determinate category
+ set category [lindex $block 0]
+ if {[lsearch $shortcuts_cat $category] == -1} {continue}
+
+ # Determinate definition list and its length
+ set block [lreplace $block 0 2]
+ set len [llength $block]
+
+ # Iterate over definition list and create bindings
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ # Determinate key sequence
+ set key [lindex $block $i]
+ if {$key == {cmd_line}} {
+ catch {
+ bind $cmd_line <$::SHORTCUTS_DB($category:$key)> \
+ "$this cmd_line_focus; break"
+ bind . <$::SHORTCUTS_DB($category:$key)> \
+ "\${::X::actualProject} cmd_line_on; break"
+ }
+ continue
+ }
+ if {[catch {
+ set key $::SHORTCUTS_DB($category:$key)
+ }]} then {
+ continue
+ }
+ if {$key == {}} {continue}
+
+ # Create and register new binding
+ lappend set_shortcuts $key
+ set cmd [subst [lindex $block [list $j 1]]]
+ append cmd {;break}
+
+ bind $editor <$key> $cmd
+ }
+ }
+ }
+
+ ## Define popup menu
+ # @return void
+ public method makePopupMenu {} {
+ if {[winfo exists $menu]} {destroy $menu}
+ menuFactory $EDITORMENU $menu 0 $cmd_prefix 0 {}
+
+ if {[winfo exists $stat_menu]} {destroy $stat_menu}
+ menuFactory $STATMENU $stat_menu 0 {::X::} 0 {}
+
+ if {[winfo exists $IB_menu]} {destroy $IB_menu}
+ menuFactory $IBMENU $IB_menu 0 "$this " 0 {}
+
+ if {[winfo exists $LN_menu]} {destroy $LN_menu}
+ menuFactory $LNMENU $LN_menu 0 "$this " 0 {}
+ }
+
+ ## Configure state of statusbar popup menu entries
+ # @parm Bool split - Enable Spit vertial / horizontal or {} == keep previous value
+ # @parm Bool close - Enable "Close current view" or {} == keep previous value
+ # @parm Bool prev - Enable "Back" or {} == keep previous value
+ # @parm Bool next - Enable "Forward" or {} == keep previous value
+ # @return void
+ public method configure_statusbar_menu {split close prev next} {
+ if {[llength $statusbar_menu_config] != 4} {
+ set statusbar_menu_config [list 1 1 1 1]
+ }
+ if {$split != {}} {
+ lset statusbar_menu_config 0 $split
+ }
+ if {$close != {}} {
+ lset statusbar_menu_config 1 $close
+ }
+ if {$prev != {}} {
+ lset statusbar_menu_config 2 $prev
+ }
+ if {$next != {}} {
+ lset statusbar_menu_config 3 $next
+ }
+ }
+
+ ## Rewrite left site of editor status bar
+ # @parm List - Relative mouse cursor coordinates ({%x,%y})
+ # {} == keyboard input (eg. leftArrow pressed)
+ # @parm Bool = 1 - Highlight current line and such things
+ # @return void
+ public method recalc_status_counter args {
+ if {$editor_to_use} {return}
+
+ # Procedure can executed only in editor mode
+ if {$frozen} {return}
+
+ # Parse arguments
+ if {[lindex $args 0] == {}} {
+ set coord insert
+ } {
+ set coord "@[lindex $args {0 0}],[lindex $args {0 1}]"
+ }
+ if {[lindex $args 1] == {}} {
+ set perform_highlight 1
+ } {
+ set perform_highlight [lindex $args 1]
+ }
+
+ # Translate text index into number
+ set Index [$editor index $coord]
+ # Determinate line number and column
+ set line [expr {int($Index)}]
+ regexp {\d+$} $Index col
+
+ # Adjust column number
+ set lineText [$editor get "$Index linestart" $Index]
+ set Index $col
+ if {[regexp {\t} $lineText]} {
+ set idx -1
+ set cor 0
+ while 1 {
+ set idx [string first "\t" $lineText [expr {$idx + 1}]]
+ if {$idx == -1 || $idx > $Index} {break}
+
+ incr cor [expr {7 - (($idx + $cor) % 8)}]
+ }
+ incr col $cor
+ }
+
+ # Restore tag current line
+ set tmp $last_cur_line
+ incr tmp
+ if {$perform_highlight || $last_cur_line != $line} {
+ $editor tag remove tag_current_line 1.0 end
+ set tmp $line
+ incr tmp
+ $editor tag add tag_current_line $line.0 $tmp.0
+ set last_cur_line $line
+ } {
+ $editor tag add tag_current_line $line.0 $tmp.0
+ }
+
+ # Restore highlight
+ if {$perform_highlight && ${::ASMsyntaxHighlight::validation_L1}} {
+ if {$prog_language == 0} {
+ ASMsyntaxHighlight::highlight $editor $line
+ } elseif {$prog_language == 1} {
+ if {$line > 1 && [string index $highlighted_lines [expr {$line - 1}]] != 0} {
+ c_syntax_highlight $line
+ } elseif {$line == 1} {
+ c_syntax_highlight 1
+ }
+ } elseif {$prog_language == 2} {
+ LSTsyntaxHighlight::highlight $editor $line
+ } elseif {$prog_language == 3} {
+ R_ASMsyntaxHighlight::highlight $editor $line
+ }
+
+ manage_autocompletion_list $line
+ }
+
+ # Highlight trailing space
+ if {$perform_highlight} {
+ highlight_trailing_space $line
+ }
+
+ # Adjust content of "Instruction details" on Right Panel
+ adjust_instruction_details
+
+ # Advanced validation
+ if {$perform_highlight && ${::ASMsyntaxHighlight::validation_L1}} {
+ validate_line $line
+ }
+
+ restore_line_markers $line
+
+ # Change content of editor status bar
+ incr col
+ set total [expr {$lastEnd - 1}]
+ set line_len [string length $line]
+ set col_len [string length $col]
+ set total_len [string length $total]
+ if {$line_len < $total_len} {
+ set line "[string repeat { } [expr {$total_len - $line_len}]]$line"
+ }
+ if {$col_len < 3} {
+ set col "[string repeat { } [expr {3 - $col_len}]]$col"
+ }
+ $Sbar_row configure -text $line
+ $Sbar_col configure -text $col
+ $Sbar_total configure -text $total
+ }
+
+ ## Adjust content of "Instruction details" on Right Panel
+ # @return void
+ public method adjust_instruction_details {} {
+ set ins_range [$editor tag nextrange tag_instruction {insert linestart} {insert lineend}]
+
+ if {[llength $ins_range]} {
+ $parentObject rightPanel_ins_change [$editor get [lindex $ins_range 0] [lindex $ins_range 1]]
+ } {
+ set ins_range [$editor tag nextrange tag_directive {insert linestart} {insert lineend}]
+ if {[llength $ins_range]} {
+ $parentObject rightPanel_dir_change D [$editor get [lindex $ins_range 0] [lindex $ins_range 1]]
+ } {
+ set ins_range [$editor tag nextrange tag_control {insert linestart} {insert lineend}]
+ if {[llength $ins_range]} {
+ $parentObject rightPanel_dir_change C [$editor get [lindex $ins_range 0] [lindex $ins_range 1]]
+ } {
+ $parentObject rightPanel_ins_clear
+ }
+ }
+ }
+ }
+
+ ## Determinate new cursor position when moving by one line up or down
+ # @return TextIndex - New cursor position
+ private method get_up_down_idx {up__down} {
+ # Local variables
+ set insertIndex [$editor index insert] ;# Insert index
+ set lineNum [expr {int($insertIndex)}] ;# Line number
+
+ # Line start
+ if {
+ !$lastUpDownIndex && $insertIndex == [$editor index {insert linestart}]
+ } then {
+ if {$up__down} {
+ return [$editor index {insert-1l linestart}]
+ } {
+ return [$editor index {insert+1l linestart}]
+ }
+
+ # Somewhere else
+ } else {
+ # Determinate true column number
+ set col [text_index_to_column $insertIndex]
+
+ # Determinate target column number
+ if {!$lastUpDownIndex} {
+ set lastUpDownIndex $col
+ } {
+ set col $lastUpDownIndex
+ }
+
+ # Traslate column number to text index
+ if {$up__down} {
+ incr lineNum -1
+ } {
+ incr lineNum
+ }
+
+ return [$editor index $lineNum.[column_to_text_index $lineNum $col]]
+ }
+ }
+
+ ## Translate text index (e.g. 5.11) to column number
+ # @parm TextIndex insertIndex - Text index to translate
+ # @return Int - Resulting column
+ private method text_index_to_column {insertIndex} {
+ set col [lindex [split $insertIndex {.}] 1]
+ set lineText [$editor get [list $insertIndex linestart] $insertIndex]
+
+ if {[string first "\t" $lineText] != -1} {
+ set idx -1
+ set cor 0
+ while 1 {
+ set idx [string first "\t" $lineText [expr {$idx + 1}]]
+ if {$idx == -1} {break}
+
+ incr cor [expr {7 - (($idx + $cor) % 8)}]
+ }
+ incr col $cor
+ }
+ return $col
+ }
+
+ ## Translate column number to text index
+ # @parm Int lineNum - Line number
+ # @parm Int col - Column number
+ # @return TextIndex - Resulting insertIndex
+ private method column_to_text_index {lineNum col} {
+ set lineText [$editor get $lineNum.0 [list $lineNum.0 lineend]]
+
+ if {[string first "\t" $lineText] != -1} {
+ set col_x 0
+ set i 0
+ set l [string length $lineText]
+
+ for {set i 0} {$i < $l} {incr i} {
+ switch -- [string index $lineText $i] {
+ "\t" {
+ incr col_x [expr {8 - ($col_x % 8)}]
+ }
+ default {
+ incr col_x
+ }
+ }
+
+ if {$col_x >= $col} {
+ if {($col_x - $col) < 2} {
+ incr i
+ }
+ break
+ }
+ }
+
+ return $i
+
+ } else {
+ return $col
+ }
+ }
+
+ ## Adjust current selection (tag "sel") to block selection mode
+ # @return void
+ private method adjust_selection_to_block {} {
+ # Nothing selected -> abort
+ if {![llength [$editor tag nextrange sel 1.0]]} {
+ return
+ }
+
+ # Get current selection shape
+ set sel_range_s [$editor tag nextrange sel 1.0]
+ set sel_range_e [$editor tag prevrange sel end]
+ scan [lindex $sel_range_s 0] %d.%d row_s0 col_s0
+ scan [lindex $sel_range_s 1] %d.%d row_s1 col_s1
+ scan [lindex $sel_range_e 0] %d.%d row_e0 col_e0
+ scan [lindex $sel_range_e 1] %d.%d row_e1 col_e1
+
+ # This is only a speed improvement (may cause unexected probles)
+ if {$row_s0 == $row_s1 && $row_e0 == $row_e1 && $col_s0 == $col_e0 && $col_s1 == $col_e1} {
+ return
+ }
+
+ # Translate column numbers to real column numbers
+ set col_s0 [text_index_to_column $row_s0.$col_s0]
+ set col_s1 [text_index_to_column $row_s1.$col_s1]
+ set col_e0 [text_index_to_column $row_e0.$col_e0]
+ set col_e1 [text_index_to_column $row_e1.$col_e1]
+
+ # Adjust column numbers
+ if {$col_s0 > $col_s1} {
+ set tmp $col_s0
+ set col_s0 $col_s1
+ set col_s1 $tmp
+ }
+ if {$col_e0 > $col_e1} {
+ set tmp $col_e0
+ set col_e0 $col_e1
+ set col_e1 $tmp
+ }
+
+ # Adjust row numbers
+ set row_s1 $row_s0
+ if {$row_s0 != $row_s1} {
+ col_s0 $col_s1
+ }
+ set row_e0 $row_e1
+ if {$row_e0 != $row_e1} {
+ col_e1 $col_e0
+ }
+
+ # Determinate width of the selected block
+ if {abs($col_s1 - $col_s0) < abs($col_e1 - $col_e0)} {
+ set width [expr {abs($col_s1 - $col_s0)}]
+ } {
+ set width [expr {abs($col_e1 - $col_e0)}]
+ }
+
+ # Regerate selection tags
+ $editor tag remove sel 0.0 end
+ set col 0
+ for {set row $row_s0} {$row <= $row_e1} {incr row} {
+ set col [column_to_text_index $row $col_s0]
+ if {[$editor compare $row.$col >= [list $row.0 lineend]]} {
+ continue
+ }
+ if {[$editor compare $row.$col+${width}c > [list $row.0 lineend]]} {
+ $editor tag add sel $row.$col [list $row.0 lineend]
+ } {
+ $editor tag add sel $row.$col $row.$col+${width}c
+ }
+ }
+ }
+
+ ## Define highlighting tags in editor text widget and command line text widget
+ # @retrun void
+ public method create_highlighting_tags {} {
+ if {$editor_to_use} {return}
+
+ if {$prog_language == 1} {
+ CsyntaxHighlight::create_tags $editor $fontSize $fontFamily
+ } elseif {$prog_language == 2} {
+ LSTsyntaxHighlight::create_tags $editor $fontSize $fontFamily
+ }
+ ASMsyntaxHighlight::create_tags $editor $fontSize $fontFamily
+ ASMsyntaxHighlight::create_tags $cmd_line $cmd_line_fontSize \
+ $cmd_line_fontFamily $cmd_line_highlighting
+
+ refresh_highlighting_for_autocompletion
+ }
+
+ ## Create terminal emulator with external editor embedded into editor frame
+ # IMPORTANT: This is only an auxiliary function for "recreate_terminal"
+ # @parm String filename - Name of file to open with the external editor
+ # @return void
+ public method create_terminal {filename} {
+ if {$terminal_created} {return}
+ set terminal_created 1
+
+ if {$filename == {untitled}} {
+ set filename {}
+ }
+
+ # Determinate editor command
+ set opt {}
+ switch -- $editor_to_use {
+ 1 {set cmd {vim}}
+ 2 {
+ set cmd {emacs}
+ set opt {-nw}
+ }
+ 3 {set cmd {nano}}
+ 4 {set cmd {dav}}
+ 5 {set cmd {le}}
+ default {
+ error "Unknown internal error in ::Editor::create_terminal($filename)"
+ }
+ }
+
+ # Change directory
+ set cur_dir [pwd]
+
+ if {[catch {
+ if {$filename == {}} {
+ cd [$parentObject cget -projectPath]
+ } {
+ cd [file dirname $filename]
+ }
+ }]} then {
+ cd ~
+ }
+
+ # Run embedded editor
+ if {[catch {
+ if {$opt == {}} {
+ if {$filename == {}} {
+ set pid [exec -- urxvt -embed [expr [winfo id $top_frame]] \
+ +sb -bg "$normal_text_bg" -b 0 -w 0 -sl 0 \
+ -fn "xft:$fontFamily:pixelsize=$fontSize" \
+ -e $cmd &]
+ } {
+ set pid [exec -- urxvt -embed [expr [winfo id $top_frame]] \
+ +sb -bg "$normal_text_bg" -b 0 -w 0 -sl 0 \
+ -fn "xft:$fontFamily:pixelsize=$fontSize" \
+ -e $cmd "$filename" &]
+ }
+ } else {
+ if {$filename == {}} {
+ set pid [exec -- urxvt -embed [expr [winfo id $top_frame]] \
+ +sb -bg "$normal_text_bg" -b 0 -w 0 -sl 0 \
+ -fn "xft:$fontFamily:pixelsize=$fontSize" \
+ -e $cmd $opt &]
+ } {
+ set pid [exec -- urxvt -embed [expr [winfo id $top_frame]] \
+ +sb -bg "$normal_text_bg" -b 0 -w 0 -sl 0 \
+ -fn "xft:$fontFamily:pixelsize=$fontSize" \
+ -e $cmd $opt "$filename" &]
+ }
+ }
+ } result]} then {
+ puts stderr $result
+ tk_messageBox \
+ -parent . \
+ -icon error \
+ -type ok \
+ -title [mc "FATAL ERROR"] \
+ -message [mc "Unable to start embedded editor due to an unknow error. This error did not occured in MCU 8051 IDE code but somewhere else. Please try to restart MCU 8051 IDE with --reset-user-settings"]
+ }
+
+ # Return to previous directory
+ cd $cur_dir
+ }
+
+ ## Create terminal emulator with external editor embedded into editor frame
+ # @parm String filename - Name of file to open with the external editor
+ # @return void
+ public method recreate_terminal {filename} {
+ update idle
+ if {![winfo exists $ed_sc_frame]} {return}
+ set top_frame [frame $ed_sc_frame.top_frame_$top_frame_idx -container 1]
+ pack $top_frame -expand 1 -fill both
+ bind $top_frame <Visibility> "update; $this create_terminal {$filename}"
+ bind $top_frame <Destroy> "$this recreate_terminal {$filename}"
+ set terminal_created 0
+ incr top_frame_idx
+ }
+
+ ## Determinate file type acording to its name externsion
+ # @parm Bool reset - Reset syntax highlight
+ # @return void
+ private method determinate_prog_lang {reset} {
+ # Determinate file type
+ set ext [string replace [file extension $filename] 0 0]
+ set prog_language_old $prog_language
+ # - C language
+ if {$ext == {c} || $ext == {h} || $ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set prog_language 1
+ # - Code listing
+ } elseif {$ext == {lst}} {
+ set prog_language 2
+ # - Unknown -> Assembly language
+ } else {
+ set prog_language 0
+ }
+
+ # Reset highlight
+ if {$reset && ($prog_language_old != $prog_language)} {
+ prog_lang_changed
+ }
+ }
+
+ ## This function shoul be called after each change of file type
+ # Reset syntax highlight and adjust editor status bar
+ # @return void
+ private method prog_lang_changed {} {
+ if {$editor_to_use} {return}
+ # Clear current highlighting tags
+ $editor tag remove tag_error 0.0 end
+ $editor tag remove tag_error_line 0.0 end
+ foreach tag [concat \
+ ${::CsyntaxHighlight::hightlight_tags} \
+ ${::ASMsyntaxHighlight::hightlight_tags} \
+ ${LSTsyntaxHighlight::hightlight_tags} \
+ ] {
+ $editor tag remove [lindex $tag 0] 0.0 end
+ }
+
+ # Create C highlighting tags
+ if {$object_initialized && $prog_language == 1 && !$c_hg_tags_created} {
+ set c_hg_tags_created 1
+ CsyntaxHighlight::create_tags $editor $fontSize $fontFamily
+ $parentObject rightPanel_bm_bp_create_c_hg_tags
+ refresh_highlighting_for_autocompletion
+
+ # Create LST highlighting tags
+ } elseif {$object_initialized && $prog_language == 2 && !$lst_hg_tags_created} {
+ set lst_hg_tags_created 1
+ ::LSTsyntaxHighlight::create_tags $editor $fontSize $fontFamily
+ $parentObject rightPanel_bm_bp_create_lst_hg_tags
+ }
+
+ # Create new highlight
+ parseAll
+
+ # Adjust status bar
+ adjust_sbar_to_prog_lang
+
+ # Adjust main menu and main toolbar
+ if {$prog_language == 1} {
+ set uses_c 1
+ } {
+ set uses_c 0
+ }
+ ::X::adjust_mainmenu_and_toolbar_to_editor {} $uses_c
+ $parentObject filelist_editor_sh_changed $this $prog_language
+ }
+
+ ## Adjust editor status bar the language used (file type)
+ # @return void
+ private method adjust_sbar_to_prog_lang {} {
+ if {$editor_to_use} {return}
+ if {$prog_language == -1} {
+ $Sbar_prog_lang configure -text {}
+ } elseif {$prog_language == 1} {
+ $Sbar_prog_lang configure -fg {#AA8800} -text "C/H"
+ } elseif {$prog_language == 2} {
+ $Sbar_prog_lang configure -fg {#00DDEE} -text "LST"
+ } elseif {$prog_language == 3} {
+ $Sbar_prog_lang configure -fg {#0000DD} -text "ASX"
+ } {
+ $Sbar_prog_lang configure -fg {#00CC00} -text "ASM"
+ }
+ }
+}
diff --git a/lib/editor/eventhandlers.tcl b/lib/editor/eventhandlers.tcl
new file mode 100755
index 0000000..c6d1083
--- /dev/null
+++ b/lib/editor/eventhandlers.tcl
@@ -0,0 +1,781 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements event handlers
+# This file should be loaded into class Editor in file "editor.tcl"
+# --------------------------------------------------------------------------
+
+
+## Binding for event <Configure>
+ # Commit new width of the editor widget -- for correct line wrapping
+ # @return void
+public method Configure {} {
+ if {$editor_to_use} {return}
+
+ # Check if program is loaded
+ if {!${::APPLICATION_LOADED}} {return}
+
+ # Adjust editor height
+ set eh_org $editor_height
+ adjust_editor_height
+
+ # Determinate width and height of the active area
+ set width [winfo width $editor]
+ incr width -6
+ incr width [expr {-($width % $defaultCharWidth)}]
+
+ # If width changed then adjust line wrapping
+ if {$editor_width != $width} {
+ set editor_width $width
+ set highlighted_lines [string repeat 0 [string bytelength $highlighted_lines]]
+ highlight_visible_area
+ } elseif {$eh_org != $editor_height} {
+ highlight_visible_area
+ }
+}
+
+## This function handles mouse click in frame which wraps the editor text widget
+ # This should happen much often, so this function ensures that everything
+ # is still ok.
+ # @parm Int x - X coordinate
+ # @parm Int y - Y coordinate
+ # @return void
+public method click_under_editor {x y} {
+ Configure
+
+ catch {
+ $editor tag remove sel 0.0 end
+ }
+
+ # Move insertion cursor
+ $editor mark set insert [$editor index @$x,$y+1l]
+
+ # Adjust meters
+ rightPanel_adjust [expr {int([$editor index insert])}]
+ recalc_status_counter {} 1
+ $editor see insert
+
+}
+
+## Handle click on "Line numbers"
+ # Add/Remove breakpoint
+ # @parm Int x - realative X coordinate
+ # @parm Int y - realative Y coordinate
+ # @return void
+public method lineNumbers_click {x y} {
+ Breakpoint [wrap_aux_line2idx [expr {int([$lineNumbers index @$x,$y])}]]
+}
+
+## Handle click on "Icon border"
+ # Add/Remove bookmarks
+ # @parm Int x - realative X coordinate
+ # @parm Int y - realative Y coordinate
+ # @return void
+public method iconBorder_click {x y} {
+ Bookmark [wrap_aux_line2idx [expr {int([$iconBorder index @$x,$y])}]]
+}
+
+## Do the same as scroll + set up the scollbar
+ # @parm Float fraction0 - Freaction where to move
+ # @parm Float fraction1 - Freaction where to setup end of visible area for the scrollbar
+ # @return void
+public method scrollSet {fraction0 fraction1} {
+ if {$editor_to_use} {return}
+
+ $scrollbar set $fraction0 $fraction1
+ scroll moveto $fraction0
+}
+
+public method scroll_0 args {
+ if {$editor_to_use} {return}
+
+ if {[lindex $args 0] != {moveto}} {
+ eval "$this scroll $args"
+ return
+ }
+
+ scroll [expr {int([lindex $args 1] * [$editor index end] + 1)}]
+}
+
+## Scroll simultaneously Icon border, Lines count and editor widget
+ # @parm String - Scroll command (eg. 'moveto')
+ # @parm Float - Scroll fraction
+ # @parm String = {} - Units
+ # @return void
+public method scroll args {
+ if {$editor_to_use} {return}
+
+ # This function cannot be caled recursively
+ if {$scroll_in_progress} {return}
+ set scroll_in_progress 1
+
+ set line 0
+ if {[lindex $args 0] == {scroll}} {
+ set line [expr {int([$editor index @5,5])}]
+ set unit [string index [lindex $args end] 0]
+
+ if {$unit != {p}} {
+ incr line [lindex $args 1]
+ } {
+ incr line [expr {30 * [lindex $args 1]}]
+ }
+ incr line -1
+
+ $editor yview $line
+ set row $line
+ incr row
+ set col 0
+
+ } else {
+ eval "$editor yview $args"
+
+ set idx [$editor index @5,5]
+ scan $idx "%d.%d" row col
+ $editor see $idx
+ }
+
+ highlight_visible_area ;# Highlight lines which hasn't been highlighted yet
+ update idle
+
+ set tmp_row $row
+ if {$number_of_wraps} {
+ set remaining $number_of_wraps
+ for {set i 1} {$i < $row} {incr i} {
+ set wrap [lindex $map_of_wraped_lines $i]
+ if {$wrap < 0} {
+ set wrap 0
+ }
+ incr tmp_row $wrap
+ incr remaining -$wrap
+ if {!$remaining} {break}
+ }
+ }
+ if {$col != 0} {
+ incr tmp_row [get_count_of_lines "$idx linestart" "$idx"]
+ }
+ incr tmp_row -1
+
+ $iconBorder yview $tmp_row
+ $lineNumbers yview $tmp_row
+
+ if {$number_of_wraps} {
+ if {$tmp_row != $line} {
+ highlight_visible_area ;# Highlight lines which hasn't been highlighted yet
+ }
+ }
+
+ # Done ...
+ update idle
+ set scroll_in_progress 0
+}
+
+## Invoke editor popup menu
+ # @parm Int X - absolute X coordinate
+ # @parm Int Y - absolute Y coordinate
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative Y coordinate
+ # @return void
+public method popupMenu {X Y x y} {
+ if {![winfo exists $menu]} {return}
+
+ if {$frozen} {
+ set address [$parentObject simulator_line2address \
+ [expr {int([$editor index @$x,$y])}] \
+ [$parentObject simulator_get_filenumber $fullFileName] \
+ ]
+ if {$address == {}} {
+ set state {disabled}
+ } {
+ set state {normal}
+ }
+ $menu entryconfigure [::mc "LJMP this line"] -state $state
+ $menu entryconfigure [::mc "LCALL this line"] -state $state
+ } {
+ $menu entryconfigure [::mc "LJMP this line"] -state disabled
+ $menu entryconfigure [::mc "LCALL this line"] -state disabled
+ }
+
+ tk_popup $menu $X $Y
+ $editor mark set insert "@$x,$y"
+ recalc_status_counter {} 0
+}
+
+## Invoke Icon Border popup menu
+ # @parm Int X - absolute X coordinate
+ # @parm Int Y - absolute Y coordinate
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative Y coordinate
+ # @return void
+public method iconBorder_popup_menu {X Y x y} {
+ if {![winfo exists $IB_menu]} {return}
+ set line [expr {int([$iconBorder index @$x,$y])}]
+ set line [wrap_aux_line2idx $line]
+ set pmenu_cline $line
+ set bookmark [lindex $bookmarks $line]
+ tk_popup $IB_menu $X $Y
+}
+
+## Invoke Line Numbers popup menu
+ # @parm Int X - absolute X coordinate
+ # @parm Int Y - absolute Y coordinate
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative Y coordinate
+ # @return void
+public method lineNumbers_popup_menu {X Y x y} {
+ if {![winfo exists $LN_menu]} {return}
+ set line [expr {int([$lineNumbers index @$x,$y])}]
+ set line [wrap_aux_line2idx $line]
+ set pmenu_cline $line
+ set breakpoint [lindex $breakpoints $line]
+ tk_popup $LN_menu $X $Y
+}
+
+## Invoke statusbar popup menu
+ # @parm Widget editor - Editor widget
+ # @parm Int X - absolute X coordinate
+ # @parm Int Y - absolute Y coordinate
+ # @return void
+public method statusbar_popup_menu {editor X Y} {
+ if {![winfo exists $stat_menu]} {return}
+
+ if {[lindex $statusbar_menu_config 0] != 0} {
+ set state normal
+ } {
+ set state disabled
+ }
+ $stat_menu entryconfigure [::mc "Split vertical"] -state $state
+ $stat_menu entryconfigure [::mc "Split horizontal"] -state $state
+
+ if {[lindex $statusbar_menu_config 1] != 0} {
+ set state normal
+ } {
+ set state disabled
+ }
+ $stat_menu entryconfigure [::mc "Close current view"] -state $state
+
+ if {[lindex $statusbar_menu_config 2] != 0} {
+ set state normal
+ } {
+ set state disabled
+ }
+ $stat_menu entryconfigure [::mc "Back"] -state $state
+
+ if {[lindex $statusbar_menu_config 3] != 0} {
+ set state normal
+ } {
+ set state disabled
+ }
+ $stat_menu entryconfigure [::mc "Forward"] -state $state
+ set ::X::selectedView $this
+ focus $editor
+ tk_popup $stat_menu $X $Y
+}
+
+## Handles pseudo-event: "Selection"
+ # @return void
+public method editor_selection {} {
+ if {$selection_in_progress} {return}
+ set selection_in_progress 1
+
+ switch -- $selection_mode {
+ 0 { ;# Normal selection mode
+ }
+ 1 { ;# Block selection mode
+ adjust_selection_to_block
+ }
+ }
+
+ set selection_in_progress 0
+}
+
+## Handles event: "Control-Key-Up"
+ # @return void
+public method control_down {} {
+ $editor yview scroll 1 units
+}
+
+## Handles event: "Control-Key-Up"
+ # @return void
+public method control_up {} {
+ $editor yview scroll -1 units
+}
+
+## Handles event: "Shift-Key-Down"
+ # @return void
+public method shift_down {} {
+ tk::TextKeySelect $editor [get_up_down_idx 0]
+
+ # Adjust selection in list of bookmarks and list of breakpoints
+ rightPanel_adjust [expr {int([$editor index insert])}]
+
+ # Adjust status bar counters
+ recalc_status_counter {}
+ $editor see insert
+}
+
+## Handles event: "Shift-Key-Up"
+ # @return void
+public method shift_up {} {
+ tk::TextKeySelect $editor [get_up_down_idx 1]
+
+ # Adjust selection in list of bookmarks and list of breakpoints
+ rightPanel_adjust [expr {int([$editor index insert])}]
+
+ # Adjust status bar counters
+ recalc_status_counter {}
+ $editor see insert
+}
+
+## Handles event: "Key-Up"
+ # @return void
+public method up {} {
+ # Move insertion cursor
+ $editor mark set insert [get_up_down_idx 1]
+
+ # Remove selection
+ catch {
+ $editor tag remove sel 1.0 end
+ }
+
+ # Adjust selection in list of bookmarks and list of breakpoints
+ rightPanel_adjust [expr {int([$editor index insert])}]
+
+ # Adjust status bar counters
+ recalc_status_counter {} 1
+ $editor see insert
+}
+
+## Handles event: "Key-Down"
+ # @return void
+public method down {} {
+ # Focus completion popup window
+ if {$completion_win_opened} {
+ catch {
+ focus -force $completion_listbox
+ $completion_listbox selection set [$completion_listbox items 0]
+ }
+ return
+ }
+
+ # Move insertion cursor
+ $editor mark set insert [get_up_down_idx 0]
+
+ # Remove selection
+ catch {
+ $editor tag remove sel 1.0 end
+ }
+
+ # Adjust selection in list of bookmarks and list of breakpoints
+ rightPanel_adjust [expr {int([$editor index insert])}]
+
+ # Adjust status bar counters
+ recalc_status_counter {}
+ $editor see insert
+}
+
+## Handles event: "Key-Escape"
+ # @return void
+public method key_escape {} {
+ if {$completion_win_opened} {
+ catch {
+ detete_text_in_editor sel.first sel.last
+ }
+ }
+ catch {
+ $editor tag remove sel 1.0 end
+ }
+}
+
+## Handles event: "Shift-Key-Home"
+ # @return void
+public method shift_home {} {
+ # Selection tag defined
+ if {[llength [$editor tag nextrange sel 1.0]]} {
+ set sel_f [$editor index sel.first]
+ set sel_l [$editor index sel.last]
+ set idx0 [$editor index insert]
+ $editor tag remove sel 1.0 end
+ home_press
+ set idx1 [$editor index insert]
+
+ if {[$editor compare $idx0 == $sel_f]} {
+ $editor tag add sel $idx1 $sel_l
+ } elseif {[$editor compare $idx0 == $sel_l]} {
+ $editor tag add sel $sel_f $idx1
+ }
+
+ # Nothing selected
+ } {
+ set idx [$editor index insert]
+ home_press
+ catch {
+ $editor tag remove sel 1.0 end
+ }
+
+ if {[$editor compare $idx < insert]} {
+ $editor tag add sel $idx insert
+ } {
+ $editor tag add sel insert $idx
+ }
+ }
+}
+
+## Handles event: "Key-Home"
+ # @return void
+public method home_press {} {
+ # Local variables
+ set idx [$editor index insert] ;# Insert index
+ set row [expr {int($idx)}] ;# Current row
+ regexp {\d+$} $idx col_original ;# Current column
+
+ # Determinate start line index (true line start)
+ if {[regexp {^\s+} [$editor get $row.0 "$row.0 lineend"] space]} {
+ set col [string length $space]
+ if {$col_original == $col} {
+ $editor mark set insert $row.0
+ } {
+ $editor mark set insert $row.$col
+ }
+ } {
+ $editor mark set insert $row.0
+ }
+
+ # Unset selection
+ catch {
+ $editor tag remove sel 1.0 end
+ }
+
+ # Adjust status bar counters
+ recalc_status_counter {} 0
+ $editor see insert
+}
+
+## Handles event: "Key-Tab"
+ # @return void
+public method tab_press {} {
+ if {$spaces_no_tabs} {
+ set indent_char [string repeat { } $number_of_spaces]
+ } {
+ set indent_char "\t"
+ }
+
+ # Nothing selected or popup completion window is opened -> insert tab character
+ if {$completion_win_opened || [$editor tag ranges sel] == {}} {
+ Key $indent_char
+
+ # Something selected -> indent
+ } {
+ # convert selection indexes to line numbers
+ set start [expr {int([$editor index sel.first])}]
+ set end_o [$editor index sel.last]
+ set end [expr {int($end_o)}]
+ if {$end == $end_o} {incr end -1}
+ # perform indent on each line in the block
+ for {set line $start} {$line <= $end} {incr line} {
+ $editor insert $line.0 $indent_char
+ rightPanel_changeLineContent $line
+ restore_line_markers $line
+ }
+ $editor tag add sel $start.0 [expr {$end + 1}].0
+
+ # Recalculate status bar
+ recalc_status_counter {} 0
+
+ $editor see insert
+ }
+}
+
+## Handles event: "Shift-Key-Return", "Shift-Key-KP_Enter"
+ # Smart new line
+ # @return void
+public method shift_enter {} {
+ if {$critical_edit_proc} {return}
+ set critical_edit_proc 1
+
+ deleteselection
+ $editor insert insert "\n"
+
+ set line [$editor get [list insert-1l linestart] [list insert-1l lineend]]
+ if {![regexp {^\s*[^\w]+} $line line]} {
+ set critical_edit_proc 0
+ return
+ }
+ $editor insert insert $line
+
+ # Recalcutlate Left frame, status bar and right panel
+ $editor see insert
+ update
+ recalc_left_frame
+ recalc_status_counter {}
+ rightPanel_adjust [expr {int([$editor index insert])}]
+ set critical_edit_proc 0
+
+ # Reevaluate highlight on the next line if C language is used
+ if {$prog_language == 1} {
+ c_syntax_highlight [expr {int([$editor index insert])+1}]
+ }
+}
+
+## Handles event: "Key-Return", "Key-KP_Enter"
+ # @return void
+public method enter {} {
+ if {$critical_edit_proc} {return}
+ set critical_edit_proc 1
+
+ $editor configure -autoseparators 0
+
+ set idx [$editor index insert] ;# Determinate insert index
+ $editor insert $idx "\n" ;# Insert EOL
+ resetUpDownIndex ;# Column changed
+
+ set idx [expr {int($idx)}]
+ incr idx
+
+ # Keep indention of the previous line
+ if {$intentation_mode == {normal}} {
+
+ # Determinate indetication charactes
+ set prev_line [$editor get \
+ [$editor index {insert-1l linestart}] \
+ [$editor index {insert-1l lineend}] \
+ ]
+ if {[string length $prev_line]} {
+ set indent_chars {}
+ regexp {^\s+} $prev_line indent_chars
+
+ # Insert indentication characers from the previous line
+ if {$indent_chars != {}} {
+ $editor insert $idx.0 $indent_chars
+ }
+
+ if {$prev_line == $indent_chars} {
+ $editor delete {insert-1l linestart} {insert-1l lineend}
+ }
+ }
+ }
+
+ # Remove selected text
+ deleteselection
+
+ # Recalcutlate Left frame, status bar and right panel
+ $editor see $idx.0
+ update
+ recalc_left_frame
+ recalc_status_counter {}
+ rightPanel_adjust $idx
+ set critical_edit_proc 0
+
+ # Reevaluate highlight on the next line if C language is used
+ if {$prog_language == 1} {
+ incr idx
+ c_syntax_highlight $idx
+ }
+
+ $editor edit separator
+ $editor configure -autoseparators 1
+}
+
+## Handles event: 'Menu'
+ # @return void
+public method Key_Menu {} {
+ # Close autocompletion popup window
+ if {$completion_win_opened} {
+ close_completion_popup_window
+ }
+
+ # Invoke popup menu
+ $editor see insert
+ set bbox [$editor bbox [$editor index insert]]
+ tk_popup $menu \
+ [expr {[winfo rootx $editor] + [lindex $bbox 0] + 10}] \
+ [expr {[winfo rooty $editor] + [lindex $bbox 1] + 10}]
+}
+
+## Handles event: 'KeyRelease'
+ # @parm String key - Key name
+ # @return void
+public method KeyRelease {key} {
+ if {[lsearch {ISO_Next_Group ISO_Prev_Group Alt_R Alt_L Control Meta Shift_L Shift_R} $key] == -1} {
+ if {$do_not_hide_comp_win} {
+ set do_not_hide_comp_win 0
+ } {
+ close_completion_popup_window
+ }
+ }
+}
+
+## Handles event: 'Key'
+ # @return void
+public method Key {key} {
+ # Skip values with no meaning
+ if {![string is print -strict $key] && $key != "\t"} {
+ return
+ }
+
+ if {$key_handler_in_progress} {
+ if {[llength $key_handler_buffer] < 4} {
+ lappend key_handler_buffer $key
+ }
+ return
+ }
+ set key_handler_in_progress 1
+ set scroll_in_progress 1 ;# Block scrolling
+
+ autocompletion_maybe_important_change insert insert
+ $editor configure -autoseparators 0
+
+ if {
+ $auto_brackets &&
+ ($key == {'} || $key == "\"" || $key == {(} || $key == "\[" || $key == "\{")
+ } then {
+ # Enclose selected text by the selected charactere
+ if {[llength [$editor tag nextrange sel 1.0]]} {
+ $editor insert sel.first $key
+ switch -- $key {
+ {(} {$editor insert sel.last {)}}
+ {[} {$editor insert sel.last {]}}
+ "\{" {$editor insert sel.last "\}"}
+ default {
+ $editor insert sel.last $key
+ }
+ }
+ $editor mark set insert sel.last
+ $editor tag remove sel 1.0 end
+
+ # Insert the selected character twice
+ } {
+ set next_char [$editor get insert insert+1c]
+ $editor insert insert $key
+ switch -- $key {
+ {(} {$editor insert insert {)}}
+ {[} {$editor insert insert {]}}
+ "\{" {$editor insert insert "\}"}
+ {'} {
+ if {$next_char != {'}} {
+ $editor insert insert {'}
+ }
+ }
+ "\"" {
+ if {$next_char != "\""} {
+ $editor insert insert "\""
+ }
+ }
+ default {
+ $editor insert insert $key
+ }
+ }
+ $editor mark set insert {insert - 1c}
+ }
+
+ } else {
+ # Delete selected text
+ deleteselection
+
+ # Mode overwrite
+ if {!$ins_ovr_mode} {
+ if {[$editor compare insert != {insert lineend}]} {
+ detete_text_in_editor insert insert+1c
+ }
+ }
+
+ # Insert the given character
+ $editor insert insert $key
+ }
+ # Restore highlight on the current line
+ parse [expr {int([$editor index insert])}]
+ set scroll_in_progress 1 ;# Block scrolling
+ recalc_left_frame
+ set scroll_in_progress 1 ;# Block scrolling
+
+ # Invoke popup completion menu
+ if {$auto_completion} {
+ aux_Key_autocompletion_0 \
+ [$editor index {insert-1c wordstart}] \
+ [$editor index {insert-1c wordend}]
+ }
+
+ $editor edit separator
+ $editor configure -autoseparators 1
+
+ if {[llength $key_handler_buffer]} {
+ set key [lindex $key_handler_buffer 0]
+ set key_handler_buffer [lreplace $key_handler_buffer 0 0]
+ update
+ set scroll_in_progress 0 ;# Unblock scrolling
+ set key_handler_in_progress 0
+ Key $key
+ }
+ set key_handler_in_progress 0
+ update
+ set scroll_in_progress 0 ;# Unblock scrolling
+}
+
+## Handles event: 'Key-Delete'
+ # @return void
+public method key_delete {} {
+ if {![$this deleteselection 1]} {
+ if {[$editor compare {insert linestart} != {insert+1c linestart}]} {
+ set remove_trailing_space 1
+ } {
+ set remove_trailing_space 0
+ }
+
+ $this detete_text_in_editor insert insert+1c
+
+ if {$remove_trailing_space && [regexp {\s+$} [$editor get {insert linestart} {insert lineend}] space]} {
+ set line_end [$editor index {insert lineend}]
+ $editor delete $line_end-[string length $space]c {insert lineend}
+ }
+ }
+
+ $this resetUpDownIndex
+ $this recalc_left_frame
+ update
+}
+
+## Handles event: 'Key-Backspace'
+ # @return void
+public method key_backspace {} {
+ if {$auto_brackets} {
+ set char0 [$editor get insert-1c insert]
+ set char1 [$editor get insert insert+1c]
+ if {
+ ($char0 == "\{" && $char1 == "\}") ||
+ ($char0 == {(} && $char1 == {)}) ||
+ ($char0 == {[} && $char1 == {]})
+ } then {
+ $this detete_text_in_editor insert insert+1c
+ } elseif {$char0 == $char1 && ($char0 == "\"" || $char1 == {'})} {
+ $this detete_text_in_editor insert insert+1c
+ }
+ }
+ if {![$this deleteselection]} {
+ $this detete_text_in_editor insert-1c insert
+ }
+ $this resetUpDownIndex
+ $this recalc_left_frame
+ $this parse [expr {int([$editor index insert])}]
+ update
+}
diff --git a/lib/editor/exports.tcl b/lib/editor/exports.tcl
new file mode 100755
index 0000000..2ce2ed4
--- /dev/null
+++ b/lib/editor/exports.tcl
@@ -0,0 +1,486 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements exports to other data formats (XHTML && LaTeX)
+# This file should be loaded into class Editor in file "editor.tcl"
+# --------------------------------------------------------------------------
+
+## Get maximum value for progressbar showing highlightion progress (proc. highlight_all)
+ # @return Int - Number of lines to highlight divided by 50
+public method highlight_all_count_of_iterations {} {
+ set result 0
+ for {set i 1} {$i < [string bytelength $highlighted_lines]} {incr i} {
+ if {[string index $highlighted_lines $i] == 0} {
+ incr result
+ }
+ if {![expr {$i % 1000}]} {update}
+ }
+ return [expr {$result / 50}]
+}
+
+## Highlight all lines in the editor (can take a long time !)
+ # @return void
+public method highlight_all {} {
+ # Reset abort variables
+ set getDataAsLaTeX_abort 0
+
+ # Highlight all lines
+ set len [string bytelength $highlighted_lines]
+ for {set i 1} {$i < $len} {incr i} {
+ if {[string index $highlighted_lines $i]} {continue}
+
+ # Highlight line
+ parse $i
+
+ # Update progress bar
+ if {![expr {$i % 50}]} {
+ incr ::X::compilation_progress
+ update
+ }
+
+ # Conditional abort
+ if {$getDataAsLaTeX_abort} {
+ set getDataAsLaTeX_abort 0
+ return
+ }
+ }
+}
+
+## Get maximum value for export progress bar
+ # @return Int - the value
+public method getDataAsXHTML_count_of_iterations {} {
+ set result 0
+ foreach tag_def [concat \
+ ${ASMsyntaxHighlight::hightlight_tags} \
+ ${CsyntaxHighlight::hightlight_tags} \
+ ${LSTsyntaxHighlight::hightlight_tags} \
+ ] {
+ set range [$editor tag ranges [lindex $tag_def 0]]
+ incr result [llength $range]
+ if {![expr {$result % 1000}]} {update}
+ }
+ return [expr {$result / 50}]
+}
+
+## Abort export to LaTeX
+ # @return void
+public method getDataAsLaTeX_abort_now {} {
+ set getDataAsLaTeX_abort 1
+}
+
+## Export editor content as LaTeX source (include colors)
+ # @return String - LaTeX source code
+public method getDataAsLaTeX {} {
+
+ # Reset abort variables
+ set getDataAsLaTeX_abort 0
+
+ # Local variables
+ set end [$editor index end] ;# Editor end index
+ set last_index 0 ;# Current position (by characters)
+ set line(1) 0 ;# Map of indexes ($line(num) == scalar_index)
+
+ # Create map of indexes
+ for {set i 1; set j 2} {$i < $end} {incr i; incr j} {
+
+ # Conditional abort
+ if {$getDataAsLaTeX_abort} {
+ set getDataAsLaTeX_abort 0
+ return {}
+ }
+
+ # Determinate last column of the line
+ set idx [$editor index "$i.0 lineend"]
+ regexp {\d+$} $idx idx
+
+ # Adjust map of indexes
+ incr last_index $idx
+ incr last_index
+ set line($j) $last_index
+ }
+
+ # Create LaTeX preamble
+ set latex "\\documentclass\[a4paper,12pt\]{article}"
+ append latex "\n\n% Creator: ${::APPNAME}\n\n"
+ append latex "\\usepackage\[utf-8\]{inputenc}\n"
+ append latex "\\usepackage\[T1\]{fontenc}\n"
+ append latex "\\usepackage{color}\n"
+ append latex "\\title{$filename}\n"
+ append latex "\\date{[clock format [clock seconds] -format {%D}]}\n"
+ append latex "\n% define highlighting\n"
+
+ ## Determinate highlighting tag ranges and define colors for 'color' package
+ set ranges {}
+ # Iterate over predefined highlighting tags
+ foreach tag_def [concat \
+ ${ASMsyntaxHighlight::hightlight_tags} \
+ ${CsyntaxHighlight::hightlight_tags} \
+ ${LSTsyntaxHighlight::hightlight_tags} \
+ ] {
+
+ # Conditional abort
+ if {$getDataAsLaTeX_abort} {
+ set getDataAsLaTeX_abort 0
+ return {}
+ }
+
+ # Local variables
+ set color [lindex $tag_def 1] ;# RGB color
+ set red [string range $color 1 2] ;# Color - RED
+ set green [string range $color 3 4] ;# Color - GREEN
+ set blue [string range $color 5 6] ;# Color - BLUE
+ set tag [lindex $tag_def 0] ;# Tag name
+ set range [$editor tag ranges $tag] ;# List of tag ranges
+ set len [llength $range] ;# Number of ranges
+ set mirror_tag {} ;# Tag with exatly the same highlight
+
+ # Determinate mirror tag
+ switch -- $tag {
+ {tag_constant} {set mirror_tag tag_constant_def}
+ {tag_macro} {set mirror_tag tag_macro_def}
+ }
+ if {$mirror_tag != {}} {
+ set mirror_range [$editor tag ranges $mirror_tag]
+ } {
+ set mirror_range {}
+ }
+
+ # If the tag isn't present in the text -> skip
+ if {$len == 0 && ![llength $mirror_range]} {
+ continue
+ }
+ # Adjust tag name
+ set tag [string replace $tag 0 3]
+
+ # Convert hexadecimal color values to decimal representation
+ set red [string range [expr "0x$red / 255.0"] 0 4]
+ set green [string range [expr "0x$green / 255.0"] 0 4]
+ set blue [string range [expr "0x$blue / 255.0"] 0 4]
+ # Define color (for package color)
+ append latex "\\definecolor{highlight_$tag}{rgb}{$red, $green, $blue}\n"
+
+ # Adjust map of text tags
+ set mirror_tag {}
+ switch -- $tag {
+ {constant} {set mirror_tag tag_constant_def}
+ {macro} {set mirror_tag tag_macro_def}
+ }
+ for {set i 0} {$i < $len} {incr i} {
+ lappend ranges [list [lindex $range $i] $tag 1]
+ incr i
+ lappend ranges [list [lindex $range $i] $tag 0]
+ }
+ if {$mirror_tag != {}} {
+ set range [$editor tag ranges $mirror_tag]
+ set len [llength $range]
+ for {set i 0} {$i < $len} {incr i} {
+ lappend ranges [list [lindex $range $i] $tag 1]
+ incr i
+ lappend ranges [list [lindex $range $i] $tag 0]
+ }
+ }
+ }
+
+ # Sort map of text tags (recursive)
+ set ranges [lsort -command "::FileList::editor__sort_tag_ranges" $ranges]
+
+ # Get plain text
+ set text [$editor get 1.0 end]
+ regsub -all {'} $text "\a" text
+
+ ## Create map of tabulators ("\t")
+ set tab_map {}
+ # Iterate ovet lines in editor
+ foreach textLine [split $text "\n"] {
+
+ if {$textLine == {}} {continue}
+ set idx -1
+ set spaces 0
+ set correction 0
+
+ while 1 {
+ set idx [string first "\t" $textLine [expr {$idx + 1}]]
+ if {$idx == -1} {break}
+
+ set spaces [expr {8 - (($idx + $correction) % 8)}]
+ incr correction [expr {$spaces - 1}]
+
+ lappend tab_map $spaces
+ }
+ }
+
+ # Write LaTeX control sequences
+ set i 0
+ foreach range $ranges {
+
+ # Conditional abort
+ if {$getDataAsLaTeX_abort} {
+ set getDataAsLaTeX_abort 0
+ return {}
+ }
+
+ # Update progress bar
+ if {![expr {$i % 50}]} {
+ incr ::X::compilation_progress
+ update
+ }
+
+ set idx [split [lindex $range 0] {.}] ;# Text index
+ set row [lindex $idx 0] ;# Line number
+ set col [lindex $idx 1] ;# Column number
+
+ # Determinate scalar text index
+ set idx [expr {$line($row) + $col}]
+ if {$idx < 0} {set idx 0}
+
+ # Determinate string to insert
+ if {[lindex $range 2]} {
+ set tag "'\{\\color{highlight_[lindex $range 1]}\\verb'"
+ } {
+ set tag "'\}\\verb'"
+ }
+
+ # Insert control sequence into plain text
+ set char [string index $text $idx]
+ set text [string replace $text $idx $idx "$tag$char"]
+
+ incr i
+ }
+
+ # Covert tabs to spaces
+ set i 0
+ foreach spaces $tab_map {
+ set idx [string first "\t" $text]
+ if {$idx == -1} {break}
+
+ set text [string replace $text $idx $idx [string repeat { } $spaces]]
+ if {![expr {$i % 1000}]} {update}
+ incr i
+ }
+
+ # Adjust lines
+ regsub -all -line {^} $text {\\verb'} text
+ regsub -all -line {$} $text "'\\\\\\" text
+ regsub -all -line {\s+'\\\\$} $text {'\\\\} text
+ regsub -all {\\verb''} $text {} text
+ regsub -all -line {^\\\\$} $text {\\verb''&} text
+ regsub -all "\a" $text {'\\verb"'"\\verb'} text
+
+ # Create final LaTeX document
+ append latex "\n\n\\begin{document}\n"
+ append latex "\\ \\\\\n"
+ append latex $text
+ append latex "\n\\end{document}"
+
+ # Return result
+ return $latex
+}
+
+## Abort export to XHTML
+ # @return void
+public method getDataAsXHTML_abort_now {} {
+ set getDataAsXHTML_abort 1
+}
+
+## Export editor content as XHTML source (include colors)
+ # @return String - XHTML source code
+public method getDataAsXHTML {} {
+
+ # Reset abort variables
+ set getDataAsXHTML_abort 0
+
+ # Local variables
+ set end [$editor index end] ;# Editor end index
+ set last_index 0 ;# Current position (by characters)
+ set line(1) 0 ;# Map of indexes ($line(num) == scalar_index)
+
+ # Create map of indexes
+ for {set i 1; set j 2} {$i < $end} {incr i; incr j} {
+
+ # Conditional abort
+ if {$getDataAsXHTML_abort} {
+ set getDataAsXHTML_abort 0
+ return {}
+ }
+
+ # Determinate last column of the line
+ set idx [$editor index [list $i.0 lineend]]
+ regexp {\d+$} $idx idx
+
+ # Adjust map of indexes
+ incr last_index $idx
+ incr last_index
+ set line($j) $last_index
+ }
+
+ # Create XHTML header
+ set html "<?xml version='1.0' encoding='utf-8' standalone='no'?>\n"
+ append html "<!DOCTYPE html PUBLIC\n"
+ append html "\t'-//W3C//DTD XHTML 1.1//EN'\n"
+ append html "\t'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'>\n"
+ append html "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en'>\n"
+ append html "<!--\n\tCreator: ${::APPNAME}\n\tDate: [clock format [clock seconds] -format {%D}]\n-->\n"
+ append html "\t<head>\n"
+ append html "\t\t<title>$filename</title>\n"
+ append html "\t\t<meta http-equiv=\"Content-Type\" content=\"application/xhtml+xml; charset=UTF-8\" />\n"
+ append html "\t\t<meta name=\"Generator\" content=\"${::APPNAME}\" />\n"
+ append html "\t\t<style type=\"text/css\">\n"
+ append html "\t\t\tbody {\n\t\t\t\tfont-family: $fontFamily;\n\t\t\t\tfont-size: ${fontSize}px;\n\t\t\t}\n"
+
+ ## Determinate highlighting tag ranges and define inline CSS
+ set ranges {}
+ # Iterate over predefined highlighting tags
+ foreach tag_def [concat \
+ ${ASMsyntaxHighlight::hightlight_tags} \
+ ${CsyntaxHighlight::hightlight_tags} \
+ ${LSTsyntaxHighlight::hightlight_tags} \
+ ] {
+
+ # Conditional abort
+ if {$getDataAsXHTML_abort} {
+ set getDataAsXHTML_abort 0
+ return {}
+ }
+
+ # Local variables
+ set tag [lindex $tag_def 0] ;# Tag name
+ set range [$editor tag ranges $tag] ;# List of tag ranges
+ set len [llength $range] ;# Number of ranges
+ set mirror_tag {} ;# Tag with exatly the same highlight
+
+ # Determinate mirror tag
+ switch -- $tag {
+ {tag_constant} {set mirror_tag tag_constant_def}
+ {tag_macro} {set mirror_tag tag_macro_def}
+ }
+ if {$mirror_tag != {}} {
+ set mirror_range [$editor tag ranges $mirror_tag]
+ } {
+ set mirror_range {}
+ }
+
+ # If the tag isn't present in the text -> skip
+ if {$len == 0 && ![llength $mirror_range]} {
+ continue
+ }
+ # Adjust tag name
+ set tag [string replace $tag 0 3]
+
+ # create CSS
+ append html "\t\t\t.$tag {\n"
+ append html "\t\t\t\tcolor: [lindex $tag_def 1];\n"
+ if {[lindex $tag_def 2]} {
+ append html "\t\t\t\ttext-decoration: line-through;\n"
+ }
+ if {[lindex $tag_def 3]} {
+ append html "\t\t\t\tfont-style: italic;\n"
+ }
+ if {[lindex $tag_def 4]} {
+ append html "\t\t\t\tfont-weight: bold;\n"
+ }
+ append html "\t\t\t}\n"
+
+ for {set i 0} {$i < $len} {incr i} {
+ lappend ranges [list [lindex $range $i] $tag 1]
+ incr i
+ lappend ranges [list [lindex $range $i] $tag 0]
+ }
+ if {$mirror_tag != {}} {
+ set len [llength $mirror_range]
+ for {set i 0} {$i < $len} {incr i} {
+ lappend ranges [list [lindex $mirror_range $i] $tag 1]
+ incr i
+ lappend ranges [list [lindex $mirror_range $i] $tag 0]
+ }
+ }
+ }
+ append html "\t\t</style>\n"
+ append html "\t</head>\n"
+
+ # Sort tag ranges (recursive)
+ set ranges [lsort -command "::FileList::editor__sort_tag_ranges" $ranges]
+
+ # Get plain text
+ set text [$editor get 1.0 end]
+ # Translate '<' and '>' to '\a' and '\b'
+ regsub -all {<} $text "\a" text
+ regsub -all {>} $text "\b" text
+
+ # Write XHTML tags to plain text
+ set i 0
+ foreach range $ranges {
+
+ # Conditional abort
+ if {$getDataAsXHTML_abort} {
+ set getDataAsXHTML_abort 0
+ return {}
+ }
+
+ # Update progress bar
+ if {![expr {$i % 50}]} {
+ incr ::X::compilation_progress
+ update
+ }
+
+ # Local variables
+ set idx [split [lindex $range 0] {.}] ;# Text index
+ set row [lindex $idx 0] ;# Line number
+ set col [lindex $idx 1] ;# Column number
+
+ # Determinate scalar text index
+ set idx [expr {$line($row) + $col}]
+ # Skip unused tags
+ if {$idx < 0} {set idx 0}
+
+ # Deterinate string to insert
+ if {[lindex $range 2]} {
+ set tag "span class='[lindex $range 1]'"
+ } {
+ set tag {/span}
+ }
+
+ # Insert XHTML tag into the text
+ set char [string index $text $idx]
+ set text [string replace $text $idx $idx "<$tag>$char"]
+
+ incr i
+ }
+
+ # Translate '&' -> &amp;
+ regsub -all "&" $text {\&amp;} text
+ # Traslate '\a', '\b' -> '&lt;', '&gt;'
+ regsub -all "\a" $text {\&lt;} text
+ regsub -all "\b" $text {\&gt;} text
+
+ # Create final XHTML document
+ append html "\t<body>\n\t\t<pre>\n"
+ append html "\t\t<!-- CODE BLOCK - begin -->\n"
+ append html $text
+ append html "\t\t<!-- CODE BLOCK - end -->\n"
+ append html "\t\t</pre>\n\t</body>\n</html>"
+
+ # Return result
+ return $html
+}
diff --git a/lib/editor/generalproc.tcl b/lib/editor/generalproc.tcl
new file mode 100755
index 0000000..f73be85
--- /dev/null
+++ b/lib/editor/generalproc.tcl
@@ -0,0 +1,2288 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements general purpose procedures
+# This file should be loaded into class Editor in file "editor.tcl"
+# --------------------------------------------------------------------------
+
+
+## Insure than simulator cursor is in visible area
+ # @return void
+public method see_sim_cursor {} {
+ if {[llength [$editor tag nextrange tag_simulator_curr 1.0 end]]} {
+ $editor see tag_simulator_curr.first
+ }
+}
+
+## Switch betweeen selection modes (Normal / Block)
+ # @return void
+public method switch_sel_mode {} {
+ set selection_mode [expr {!$selection_mode}]
+ if {$selection_mode} {
+ adjust_selection_to_block
+ $sel_mode_lbl configure -text [mc "BLK"] -fg #0088CC
+ } {
+ if {[llength [$editor tag nextrange sel 1.0]]} {
+ $editor tag add sel sel.first sel.last
+ }
+ $sel_mode_lbl configure -text [mc "NORM"] -fg #000000
+ }
+}
+
+## Switch between modes "Insert" and "Overwrite"
+ # @return void
+public method switch_ins_ovr {} {
+ if {$ro_mode} {return}
+ set ins_ovr_mode [expr {!$ins_ovr_mode}]
+ adjust_INS_OVR_label
+}
+
+## Get list of breapoints
+ # @return List - result (eg. '{0 1 1 0 0 0}')
+public method getBreakpoints {} {
+ return $breakpoints
+}
+
+## Find a string in the text, scroll to it and select it
+ # @parm Bool fromCursor - Search from cursor / whole document
+ # @parm Bool Backwards - Search backwards from cursor / forwards
+ # @parm Bool regExp - Use regular expressions / exact matching
+ # @parm Bool noCase - Case insensitive / sensitive
+ # @parm Bool inSelection - Search in the selected block / search globaly
+ # @parm String Sindex - index in the text where the search should start
+ # @parm String String - String to search
+ # @return List - {indexMatchBegining indexMatchEnd matchesCount}
+public method find {fromCursor Backwards regExp noCase inSelection Sindex String} {
+
+ ## adjust search options
+
+ # set Stop-Index (and Start-index) depending on variable $inSelection
+ if {![llength [$editor tag nextrange sel 1.0]]} {
+ set inSelection 0
+ }
+ if {$inSelection} {
+ set Sindex sel.first
+ set Eindex sel.last
+ } {
+ if {$Backwards} {
+ set Eindex 1.0
+ } {
+ set Eindex {end}
+ }
+ }
+
+ # set direction and possibly Start-index too
+ if {$fromCursor} {
+ # Sindex
+ set Sindex {insert}
+ } {
+ # Sindex
+ if {$Sindex == {}} {
+ if {$Backwards} {
+ set Sindex end
+ } {
+ set Sindex 1.0
+ }
+ }
+ }
+
+ # direction
+ if {$Backwards} {
+ append Sindex -[expr {[string length $String] - 1}]c
+ set direction {-backwards}
+ } {
+ set direction {-forwards}
+ }
+
+ # set exact or regexp based on search and case sensitivity
+ if {$regExp} {set regexp {-regexp}} {set regexp {-exact}}
+
+ ## Perform search
+ if {[catch {
+ if {$noCase} {
+ set index [$editor search $direction $regexp -nocase \
+ -count {::editor_search_count} -- \
+ $String $Sindex $Eindex]
+ } {
+ set index [$editor search $direction $regexp \
+ -count {::editor_search_count} -- \
+ $String $Sindex $Eindex]
+ }
+ } result]} then {
+ return [list -1 $result]
+ }
+
+ ## Focus on the found string
+ if {$index != {}} {
+ # Determinate number of column (begin) and row of matched string
+ set lineNumber [expr {int($index)}]
+ regexp {\d+$} $index colNumber
+ # Determinate lenght of matched string
+ if {$regExp} {
+ regexp $String [$editor get $Sindex $Eindex] String
+ }
+ # Determinate number of end column of matched string
+ set end_col [string length $String]
+ set end_col [expr {$end_col + $colNumber}]
+ # Goto line with the found match and select that matched string
+ if {$Backwards} {
+ goto $lineNumber.$colNumber
+ } {
+ goto $lineNumber.$end_col
+ }
+ $editor tag remove sel 1.0 end
+ $editor tag add sel $index $lineNumber.$end_col
+ # set result acording to values determinated above
+ set matches "$index $lineNumber.$end_col ${::editor_search_count}"
+ } {
+ # set result to something like 'nothing found'
+ set matches "$Sindex $Sindex 0"
+ }
+
+ # return result (see procedure header for details)
+ return $matches
+}
+
+## Find a string in the text and replce it by something else ...
+ # note: using 'find' procedure
+ # @parm Bool fromCursor - Search from cursor / whole document
+ # @parm Bool inSelection - Search in the selected block / search globaly
+ # @parm Bool Backwards - Search backwards from cursor / forwards
+ # @parm Bool regExp - Use regular expressions / exact matching
+ # @parm Bool noCase - Case insensitive / sensitive
+ # @parm String SearchString - String to search
+ # @parm String Replacement - String to replace SearchString
+ # @parm Bool confirm - (see attribute confirmCMD below)
+ # @parm String confirmCMD - command which will be executed on each match if cofirm is 1,
+ # acceptable return values are:
+ # 0 : Replace and search next
+ # 1 : Replace and close
+ # 2 : Replace all without prompt
+ # 3 : Search next
+ # 4 : Close
+ # @return Bool - 1 == Ok; 0 == last replacement was refused by user
+public method replace {fromCursor Backwards regExp noCase SearchString Replacement confirm confirmCMD} {
+ # Local variables
+ set remaining 1 ;# Int - Count of remaining matches to replace
+ set repl_made 0 ;# Int - Count of replacements made
+ set close 0 ;# Bool - Close after this replace
+ set cnd 1 ;# Bool - Perform replacement in this iteration
+
+ # Save the current insertion cursor index
+ set ins_index [$editor index insert]
+
+ if {$critical_edit_proc} {return 0}
+ set critical_edit_proc 1
+
+ ## Derminate indexes of area to be affected
+ if {$fromCursor} {
+ # from actual cursor position
+ set index {insert}
+ } {
+ if {$Backwards} {
+ set index {end}
+ } {
+ set index 1.0
+ }
+ }
+
+ ## Perform replacement for each match
+ while $remaining {
+ # Initiate search and determinate count of remaining matches
+ set result [find $fromCursor $Backwards $regExp $noCase 0 $index $SearchString]
+
+ set remaining [lindex $result 2]
+ if {$remaining == 0} {break}
+
+ # Determinate index where to reinitiate search
+ set index [lindex $result [expr {!$Backwards}]]
+
+ # "Annoy user" if there is requested confirmation before each replace
+ if {$confirm} {
+ # invoke confirmation command and setup new parameters
+ switch [$confirmCMD] {
+ 0 { ;# Replace
+ set cnd 1
+ }
+
+ 1 { ;# Replace & close
+ set cnd 1
+ set close 1
+ }
+
+ 2 { ;# Replace all
+ set cnd 1;
+ set confirm 0
+ }
+
+ 3 { ;# Find next
+ set cnd 0
+ }
+
+ 4 { ;# Close
+ set cnd 1
+ break
+ }
+ }
+ } {
+ # automaticaly replace all without any prompt
+ set cnd 1
+ }
+
+ # Perform replace if it's allowed
+ if {$cnd} {
+ # Determinate indexes of string to replace
+ set start [lindex $result 0]
+ set end [lindex $result 1]
+ # Replace
+ $editor configure -autoseparators 0
+ detete_text_in_editor $start $end
+ $editor insert $start $Replacement
+ if {!$Backwards} {
+ set index [$editor index insert]
+ }
+ $editor edit separator
+ $editor configure -autoseparators 1
+ # restore syntax highlight on all affected lines
+ set start [expr {int($start)}]
+ set end [expr {int($end)}]
+ if {$confirm} {
+ for {set line $start} {$line <= $end} {incr line} {
+ parse $line
+ }
+ } {
+ for {set line $start} {$line <= $end} {incr line} {
+ restore_line_markers $line
+ }
+ set highlighted_lines [string replace $highlighted_lines \
+ $start $end [string repeat 0 [expr {$end - $start + 1}]]]
+ }
+ # increment counter of made replacemetns
+ incr repl_made
+ # contitionaly break replacing loop
+ if {$close} {break}
+ }
+ # decrease counter of remining replacements
+ incr remaining -1
+ }
+
+ $editor tag remove sel 1.0 end
+
+ ## Change application status bar (show results)
+ Sbar [mc "Replace: %s replacements made" $repl_made]
+
+ goto $ins_index
+ highlight_visible_area
+ set critical_edit_proc 0
+ return $cnd
+}
+
+## Select all content of the editor's text widget
+ # @return void
+public method select_all {} {
+ catch {
+ $editor tag remove sel 1.0 end
+ }
+ $editor tag add sel 1.0 end
+}
+
+## Comment the selected area or current line
+ # @return void
+public method comment {} {
+ if {$editor_to_use} {return}
+ if {$completion_win_opened} {return}
+
+ set start [expr {int([$editor index insert])}]
+ $editor configure -autoseparators 0
+
+ # Assembly language
+ if {$prog_language == 0 || $prog_language == 3 || [string index $highlighted_lines $start] == 6} {
+ # determinate indexes of area to comment
+ if {[getselection] == {}} {
+ set restore_sel 0
+ set end $start
+ } {
+ set restore_sel 1
+ set start [expr {int([$editor index sel.first])}]
+ set end_o [$editor index sel.last]
+ set end [expr {int($end_o)}]
+ if {$end == $end_o} {incr end -1}
+ }
+
+ # comment each line in the block
+ autocompletion_maybe_important_change $start.0 $end.0
+ for {set line $start} {$line <= $end} {incr line} {
+ $editor insert $line.0 {;}
+ restore_line_markers $line
+ }
+
+ # C language
+ } elseif {$prog_language == 1} {
+ # determinate indexes of area to comment
+ if {[getselection] == {}} {
+ set by_lines 1
+ set restore_sel 0
+ set end $start
+ } {
+ set start_o [$editor index sel.first]
+ set start [expr {int($start_o)}]
+ set end_o [$editor index sel.last]
+ set end [expr {int($end_o)}]
+ if {$end == $end_o && $start == $start_o} {
+ set restore_sel 1
+ set by_lines 1
+ } {
+ set restore_sel 0
+ set by_lines 0
+ }
+ if {$end == $end_o} {
+ incr end -1
+ }
+ }
+
+ # Comment each line in the block
+ autocompletion_maybe_important_change $start.0 $end.0
+ if {$by_lines} {
+ for {set line $start} {$line <= $end} {incr line} {
+ $editor insert $line.0 {// }
+ restore_line_markers $line
+ }
+ # Comment only selected characters
+ } {
+ $editor insert $end_o { */}
+ $editor insert $start_o {/* }
+ $editor tag add sel sel.first-3c sel.last+3c
+ }
+ } else {
+ $editor edit separator
+ $editor configure -autoseparators 1
+ return
+ }
+
+ $editor edit separator
+ $editor configure -autoseparators 1
+
+ if {$prog_language != -1} {
+ # Restore highlight
+ if {$prog_language == 1 && ![string index $highlighted_lines $start] == 6} {
+ parse $start
+ } {
+ for {set i $start} {$i <= $end} {incr i} {
+ parse $i
+ }
+ }
+
+ # Restore selection shape
+ if {$restore_sel} {
+ $editor tag add sel "$start.0 linestart" "$end.0 lineend"
+ }
+ }
+}
+
+## Remove first semicolon in selected area or current line
+ # @return bool - result
+public method uncomment {} {
+ if {$editor_to_use} {return}
+ if {$completion_win_opened} {return}
+
+ set succesful 0
+ set start [expr {int([$editor index insert])}]
+ $editor configure -autoseparators 0
+
+ # Assembly language
+ if {$prog_language == 0 || $prog_language == 3 || [string index $highlighted_lines $start] == 6} {
+ # determinate indexes of area to uncomment
+ if {[getselection] == {}} {
+ set restore_sel 0
+ set end $start
+ } {
+ set restore_sel 1
+ set start [expr {int([$editor index sel.first])}]
+ set end_o [$editor index sel.last]
+ set end [expr {int($end_o)}]
+ if {$end == $end_o} {incr end -1}
+ }
+
+ # Uncomment each line in the block
+ for {set line $start} {$line <= $end} {incr line} {
+ # get line
+ set line_data [$editor get $line.0 "$line.0 lineend"]
+
+ if {[regexp {^\s*;\s*} $line_data comment]} {
+ detete_text_in_editor $line.0 $line.[string length $comment]
+ regsub {;} $comment {} comment
+ $editor insert $line.0 $comment
+ restore_line_markers $line
+ manage_autocompletion_list $line
+ set succesful 1
+ }
+ }
+
+ # C language
+ } elseif {$prog_language == 1} {
+ # determinate indexes of area to comment
+ if {[getselection] == {}} {
+ set by_lines 1
+ set restore_sel 0
+ set end $start
+ } {
+ set start_o [$editor index sel.first]
+ set start [expr {int($start_o)}]
+ set end_o [$editor index sel.last]
+ set end [expr {int($end_o)}]
+ if {$end == $end_o && $start == $start_o} {
+ set restore_sel 1
+ set by_lines 1
+ } {
+ set restore_sel 0
+ set by_lines 0
+ }
+ if {$end == $end_o} {
+ incr end -1
+ }
+ }
+
+ # Uncomment only selected characters
+ if {!$by_lines} {
+ set start_data [$editor get $start_o [list $start_o lineend]]
+ set end_data [$editor get [list $end_o linestart] $end_o]
+ if {
+ [regexp {^\s*/\* ?} $start_data start_data]
+ &&
+ [regexp { ?\*/\s*$} $end_data end_data]
+ } then {
+ set succesful 1
+ set start_data [string length $start_data]
+ set end_data [string length $end_data]
+ detete_text_in_editor $end_o-${end_data}c $end_o
+ detete_text_in_editor $start_o $start_o+${start_data}c
+ }
+ }
+
+ # Uncomment each line in the block
+ for {set line $start} {$line <= $end} {incr line} {
+ set line_data [$editor get $line.0 [list $line.0 lineend]]
+ if {[regexp {^\s*// ?} $line_data line_data]} {
+ set line_data [string length $line_data]
+ detete_text_in_editor $line.0 $line.$line_data
+ manage_autocompletion_list $line
+ set succesful 1
+ }
+ restore_line_markers $line
+ }
+ } {
+ $editor edit separator
+ $editor configure -autoseparators 1
+ return $succesful
+ }
+ $editor edit separator
+ $editor configure -autoseparators 1
+
+ if {$prog_language != -1} {
+ # Restore highlight
+ if {$prog_language == 1 && ![string index $highlighted_lines $start] == 6} {
+ parse $start
+ } {
+ for {set i $start} {$i <= $end} {incr i} {
+ parse $i
+ }
+ }
+
+ # Restore selection shape
+ if {$restore_sel} {
+ $editor tag add sel "$start.0 linestart" "$end.0 lineend"
+ }
+
+ }
+
+ # Return result
+ return $succesful
+}
+
+## Go to line number or text index in the text
+ # @parm Number textIndex - Can be line number (like 154) or text index (like 32.17)
+ # @return void
+public method goto {textIndex} {
+ if {$editor_to_use} {return}
+
+ # Check for validity of the given argument
+ if {![regexp {^\d+(\.\d+)?$} $textIndex]} {
+ return
+ }
+ # Adjust the given parameter
+ if {![regexp {\.} $textIndex]} {
+ set textIndex "$textIndex.0"
+ }
+ # Scroll to the required index and move cursor there
+ rightPanel_adjust [expr {int($textIndex)}]
+ $editor mark set insert $textIndex
+ if {!$frozen} {
+ $editor tag remove tag_current_line 1.0 end
+ $editor tag add tag_current_line \
+ [$editor index "$textIndex linestart"] \
+ [$editor index "$textIndex +1 line linestart"]
+ }
+ recalc_status_counter {} 0
+ update idle
+ $editor see insert
+}
+
+## Delete all selected characters
+ # @return Bool - Anything deleted
+public method deleteselection {{parse_lines 0}} {
+ set ranges [$editor tag ranges sel]
+ set len [llength $ranges]
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ detete_text_in_editor [lindex $ranges $i] [lindex $ranges $j]
+
+ if {$prog_language == 1} {
+ c_syntax_highlight [expr {int([lindex $ranges $i])}]
+ }
+
+ if {$parse_lines} {
+ set first [expr {int([lindex $ranges $i])}]
+ set last [expr {int([lindex $ranges $j])}]
+ set highlighted_lines [string replace $highlighted_lines \
+ $first $last [string repeat 0 [expr {$last - $first + 1}]]]
+
+ $this parse $first
+ }
+ }
+
+ return [expr {!(!$len)}]
+}
+
+## Get currently selected text
+ # @return String - content of the selected area
+public method getselection {} {
+ set data {}
+ set ranges [$editor tag ranges sel]
+ set len [llength $ranges]
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ if {$i} {
+ append data "\n"
+ }
+ append data [$editor get [lindex $ranges $i] [lindex $ranges $j]]
+ }
+ return $data
+}
+
+## Indent content of the selected area or current line
+ # @return void
+public method indent {} {
+ if {$completion_win_opened} {return}
+
+ # Determinate indexes of area to be affected
+ if {[getselection] == {}} {
+ set restore_sel 0
+ set start [expr {int([$editor index insert])}]
+ set end $start
+ } {
+ set restore_sel 1
+ set start [expr {int([$editor index sel.first])}]
+ set end_o [$editor index sel.last]
+ set end [expr {int($end_o)}]
+ if {$end == $end_o} {incr end -1}
+ }
+
+ # indent each line in the block
+ if {$spaces_no_tabs} {
+ set indent_char [string repeat { } $number_of_spaces]
+ } {
+ set indent_char "\t"
+ }
+ for {set line $start} {$line <= $end} {incr line} {
+ $editor insert $line.0 $indent_char
+ rightPanel_changeLineContent $line
+ restore_line_markers $line
+ }
+ # Restore selection shape
+ if {$restore_sel} {
+ $editor tag add sel "$start.0 linestart" "$end.0 lineend"
+ }
+ $editor tag add sel $start.0 [expr {$end + 1}].0
+}
+
+## Unindent content of the selected area or current line
+ # @return void
+public method unindent {} {
+ if {$completion_win_opened} {return}
+
+ # Determinate indexes of area to be affected
+ if {[getselection] == {}} {
+ set restore_sel 0
+ set start [expr {int([$editor index insert])}]
+ set end [expr {int([$editor index insert])}]
+ } {
+ set restore_sel 1
+ set start [expr {int([$editor index sel.first])}]
+ set end_o [$editor index sel.last]
+ set end [expr {int($end_o)}]
+ if {$end == $end_o} {incr end -1}
+ }
+ # unindent each line in the block
+ for {set line $start} {$line <= $end} {incr line} {
+ set line_data [$editor get $line.0 "$line.0 lineend"]
+ if {$spaces_no_tabs} {
+ if {[regexp {^ +} $line_data space]} {
+ set space [string length $space]
+ if {$space > $number_of_spaces} {
+ set space $number_of_spaces
+ }
+ detete_text_in_editor $line.0 $line.$space
+ } elseif {[regexp {^\t} $line_data]} {
+ detete_text_in_editor $line.0 $line.1
+ }
+ } {
+ if {[regexp {^[\t( )]} $line_data]} {
+ detete_text_in_editor $line.0 $line.1
+ }
+ }
+ rightPanel_changeLineContent $line
+ }
+ # Restore selection shape
+ if {$restore_sel} {
+ $editor tag add sel "$start.0 linestart" "$end.0 lineend"
+ }
+ $editor tag add sel $start.0 [expr {$end + 1}].0
+}
+
+## Get contents of the text widget
+ # EOL: LF
+ # Encoding: UTF-8
+ # @return String
+public method getdata {} {
+ return [regsub {\n$} [$editor get 1.0 end] {}]
+}
+
+## Get contents of the text widget
+ # EOL: $eol
+ # Encoding: $encoding
+ # @return String
+public method getdata_adjusted_ENC_and_EOL {} {
+ switch -- $eol {
+ {lf} {set eol_char "\n"}
+ {cr} {set eol_char "\r"}
+ {crlf} {set eol_char "\r\n"}
+ }
+ return [encoding convertto $encoding \
+ [regsub -all {\n} \
+ [regsub {\n$} \
+ [$editor get 1.0 end] \
+ {}] \
+ $eol_char] \
+ ] \
+}
+
+## Get MD5 of the opened file
+ # @return String - MD5 hash
+public method get_md5 {} {
+ switch -- $eol {
+ {lf} {set eol_char "\n"}
+ {cr} {set eol_char "\r"}
+ {crlf} {set eol_char "\r\n"}
+ }
+ return [md5::md5 -hex \
+ [encoding convertto $encoding \
+ [regsub -all {\n} \
+ [regsub {\n$} \
+ [$editor get 1.0 end] \
+ {}] \
+ $eol_char] \
+ ] \
+ ]
+}
+
+## Add/Remove bookmark to/from current line
+ # Directly depends on variable "bookmarks" (managed by proc. recalc_left_frame)
+ # @parm Int = NULL - target text index
+ # @return bool - 0: bookmark removed; 1: bookmark created
+public method Bookmark args {
+ if {$editor_to_use} {return}
+
+ # Determinate line number
+ if {$args != {}} {
+ set lineNumber [expr {int($args)}]
+ } {
+ set lineNumber [expr {int([$editor index insert])}]
+ }
+
+ # Check for maximum line number value
+ if {[expr {$lineNumber - [llength $bookmarks]}] > -1} {
+ recalc_left_frame
+ return
+ }
+
+ # Add or remove bookmark ?
+ if {[lindex $bookmarks $lineNumber] == 1} {set make 0} {set make 1}
+ lset bookmarks $lineNumber $make
+
+ # Adjust line number
+ set lineNumber_i [wrap_aux_idx2line $lineNumber]
+
+ ## Add/remove bookmark icon to/from iconBorder
+
+
+ $iconBorder configure -state normal ;# Enable the text widget
+ set scroll_in_progress 1 ;# Disable scrolling
+
+ # Add icon
+ if {$make} {
+ $iconBorder delete $lineNumber_i.0 $lineNumber_i.2
+
+ if {$defaultCharHeight < 9} {
+ $iconBorder insert $lineNumber_i.0 {*}
+ } elseif {$defaultCharHeight < 15} {
+ $iconBorder image create $lineNumber_i.0 \
+ -image ::ICONS::16::dot \
+ -align center
+ } {
+ if {[llength [$editor tag nextrange tag_error $lineNumber.0 [list $lineNumber.0 lineend]]]} {
+ set image {bm_ex}
+ } {
+ set image {bookmark}
+ }
+ $iconBorder image create $lineNumber_i.0 \
+ -image ::ICONS::16::$image \
+ -align center
+ }
+ # Remove icon
+ } {
+ $iconBorder delete $lineNumber_i.0 $lineNumber_i.2
+ if {
+ [llength [$editor tag nextrange tag_error $lineNumber.0 [list $lineNumber.0 lineend]]]
+ &&
+ $defaultCharHeight >= 15
+ } then {
+ $iconBorder image create $lineNumber_i.0 \
+ -image ::ICONS::16::exclamation \
+ -align center
+ }
+ }
+
+ # Disable the text widget
+ $iconBorder configure -state disabled
+
+ # Take care of bookmark tag
+ set tmp $lineNumber
+ incr tmp
+ # Add the tag
+ if {$make} {
+ $editor tag add tag_bookmark $lineNumber.0 $tmp.0
+ $parentObject rightPanel_add_bookmark $lineNumber
+ $parentObject rightPanel_bm_select $lineNumber
+ # Remove the tag
+ } {
+ $editor tag remove tag_bookmark $lineNumber.0 $tmp.0
+ $parentObject rightPanel_remove_bookmark $lineNumber
+ $parentObject rightPanel_bm_unselect
+ }
+
+ # Enable scrolling
+ update idle
+ set scroll_in_progress 0
+
+ # Done ...
+ return $make
+}
+
+## Add/Remove breapoint to/from current line
+ # Directly depends on variable "breakpoints" (managed by proc. recalc_left_frame)
+ # @parm Int = NULL - target text index
+ # @return bool - 0: breakpoint removed; 1: breakpoint created; or {}
+public method Breakpoint args {
+
+ # Determinate line number
+ if {$args != {}} {
+ set lineNumber [expr {int($args)}]
+ } {
+ set lineNumber [expr {int([$editor index insert])}]
+ }
+
+ # Check for maximum line number value
+ if {[expr {$lineNumber - [llength $breakpoints]}] > -1} {
+ recalc_left_frame
+ return
+ }
+
+ # Add or remove breakpoint ?
+ if {[lindex $breakpoints $lineNumber] == 1} {set make 0} {set make 1}
+ # Set breakpoint flag
+ lset breakpoints $lineNumber $make
+
+ # Adjust line number
+ set lineNumber_i [wrap_aux_idx2line $lineNumber]
+
+ ## Add/remove breakpoint tag to/from LineNumbers
+ set tmp $lineNumber_i
+ incr tmp
+
+ $lineNumbers configure -state normal ;# Enable the text widget
+ set scroll_in_progress 1 ;# Disable scrolling
+
+ # Add the tag
+ if {$make} {
+ $lineNumbers tag add tag_breakpoint $lineNumber_i.0 $tmp.0
+ $parentObject rightPanel_add_breakpoint $lineNumber
+ $parentObject rightPanel_bp_select $lineNumber
+ # Remove the tag
+ } {
+ $lineNumbers tag remove tag_breakpoint $lineNumber_i.0 $tmp.0
+ $parentObject rightPanel_remove_breakpoint $lineNumber
+ $parentObject rightPanel_bp_unselect
+ }
+
+ # Disable the text widget
+ $lineNumbers configure -state disabled
+
+ # Refresh breakpoint settings in simulator engine
+ if {[lindex ${::X::simulator_enabled} ${::X::actualProjectIdx}] == 1} {
+ $parentObject Simulator_import_breakpoints $fullFileName [getBreakpoints]
+ }
+
+ # Enable scrolling
+ update idle
+ set scroll_in_progress 0
+
+ # done ...
+ return $make
+}
+
+## Remove all bookmarks from the editor and from right panel
+ # @return void
+public method clear_all_bookmarks {} {
+ if {$editor_to_use} {return}
+
+ # Clear icon border
+ $iconBorder configure -state normal
+ set idx -1
+ foreach bool $bookmarks {
+ incr idx
+ if {!$bool} {continue}
+ $iconBorder delete $idx.0 $idx.1
+ }
+ $iconBorder configure -state disabled
+
+ # Clear text tags
+ $editor tag remove tag_bookmark 1.0 end
+
+ # Clear list of bookmarks
+ set len [llength $bookmarks]
+ incr len -1
+ set bookmarks 0
+ append bookmarks [string repeat { 0} $len]
+
+ # Clear list of bookmakrs in the right panel
+ $parentObject rightPanel_clear_all_bookmarks
+}
+
+## Remove all breakpoints from the editor and from right panel
+ # @return void
+public method clear_all_breakpoints {} {
+
+ # Clear breakpoints in object variable
+ set len [llength $bookmarks]
+ incr len -1
+ set breakpoints 0
+ append breakpoints [string repeat { 0} $len]
+
+ # Clear breakpoint tags from line numbers
+ $lineNumbers tag remove tag_breakpoint 1.0 end
+
+ # Clear right panel
+ $parentObject rightPanel_clear_all_breakpoints
+}
+
+## Get number of the current line
+ # @return Int - current line num.
+public method get_current_line_number {} {
+ set line [expr {int([$editor index insert])}]
+ return $line
+}
+
+## Call ::X::__show_hine_IconB
+ # @return void
+public method show_hine_IconB {} {
+ ::X::__show_hine_IconB
+}
+
+## Call ::X::__show_hine_LineN
+ # @return void
+public method show_hine_LineN {} {
+ ::X::__show_hine_LineN
+}
+
+## Show the Icon Border
+ # @return bool - result
+public method showIconBorder {} {
+ if {!$show_iconBorder} {
+ pack $left_frame_L -fill y -side left
+ set show_iconBorder 1
+ recalc_left_frame
+ return 1
+ }
+ return 0
+}
+
+## Hide the Icon Border
+ # @return bool - result
+public method hideIconBorder {} {
+ if {$show_iconBorder} {
+ pack forget $left_frame_L
+ set show_iconBorder 0
+ return 1
+ }
+ return 0
+}
+
+## Show the Line Numbers
+ # @return bool - result
+public method showLineNumbers {} {
+ if {!$show_lineNum} {
+ pack $left_frame_R -fill y -side right
+ set show_lineNum 1
+ recalc_left_frame
+ return 1
+ }
+ return 0
+}
+
+## Hide the Line Numbers
+ # @return bool - result
+public method hideLineNumbers {} {
+ if {$show_lineNum} {
+ pack forget $left_frame_R
+ set show_lineNum 0
+ return 1
+ }
+ return 0
+}
+
+## Insert given data into the text
+ # @parm String data - Data to insert
+ # @parm TextIndex position - Target text index ({} == "end")
+ # @return void
+public method insertData {data position} {
+ if {$position == ""} {
+ set position end
+ }
+ # Insert data
+ $editor insert $position [regsub -all {[\u0000-\u0008\u000B-\u000C\u000E-\u001F\u007F-\u009F]} $data {}]
+ # Highlight
+ update idle
+ parseAll
+}
+
+## Restore syntax highlight in whole text
+ # @return void
+public method parseAll {} {
+ if {$editor_to_use} {return}
+
+ # Disable this function
+ set enable_parseAll 0
+
+ # Determinate number of the last line in the editor
+ set lastEnd [expr {int([$editor index end])}]
+
+ # Initialize list of highlighted lines
+ set highlighted_lines [string repeat 0 $lastEnd]
+
+ # Reevaluate bookmarks and breakpoints
+ $lineNumbers configure -state normal
+ $lineNumbers delete 1.0 end
+ $lineNumbers insert end 1
+ $lineNumbers tag add right 1.0 end
+ import_line_markers_data [join $bookmarks {}] [join $breakpoints {}]
+
+ # Highlight all visible lines
+ highlight_visible_area
+
+ # Recalculate left frame and status bar counters
+ scrollSet [lindex [$editor yview] 0] [lindex [$editor yview] 1]
+ set lastEnd [expr {int([$editor index end])}]
+ recalc_status_counter {} 0
+
+ # Enable this function
+ set enable_parseAll 1
+}
+
+## Get content of the given line
+ # @parm Int lineNumber - number of the target line
+ # @return String - result
+public method getLineContent {lineNumber} {
+ # Check lineNumber validity
+ set end [$editor index end]
+ if {$end <= $lineNumber} {return {}}
+
+ # Return the data
+ return [$editor get $lineNumber.0 "$lineNumber.0 lineend"]
+}
+
+## Parse the current line
+ # @return void
+public method parse_current_line {} {
+ if {$editor_to_use} {return}
+ set line [expr {int([$editor index insert])}]
+ parse $line
+ set highlighted_lines [string replace $highlighted_lines $line $line 0]
+}
+
+## Get number of lines between the given indexes
+ # @parm TextIndex index0 - Start index
+ # @parm TextIndex index1 - End index
+ # @return Int - lines count
+private method get_count_of_lines {index0 index1} {
+ # Check if editor width is properly set
+ if {$editor_width <= 0} {return 1}
+
+ # Determinate text between the given indexes
+ set lineText [$editor get $index0 $index1]
+
+ # Line contains tabulators
+ if {[regexp {\t} $lineText]} {
+ # Translate tabulators to spaces
+ set idx -1
+ set cor 0
+ while 1 {
+ set idx [string first "\t" $lineText [expr {$idx + 1}]]
+ if {$idx == -1} {break}
+
+ incr cor [expr {7 - (($idx + $cor) % 8)}]
+ }
+ regsub -all {\t} $lineText { } lineText
+ # Determinate line width in pixels
+ set line_width [font measure $defaultFont_bold -displayof $editor $lineText]
+ incr line_width [expr {$cor * $defaultCharWidth}]
+ # Line doesn't contain tabulators
+ } {
+ set line_width [font measure $defaultFont_bold -displayof $editor $lineText]
+ }
+
+ # Determinate number of lines
+ set new_wrap [expr {$line_width / $editor_width}]
+ if {[expr {$line_width % $editor_width}]} {
+ incr new_wrap
+ }
+
+ # Return result
+ return $new_wrap
+}
+
+## Get data of bookmarks and breapoints
+ # @return List - {bookmarks breakpoints} (eg. {00011 10100})
+public method export_line_markers_data {} {
+ set result [join $bookmarks {}]
+ lappend result [join $breakpoints {}]
+ return $result
+}
+
+## Get total number of lines in editor
+ # @return Int - result
+public method getLinesCount {} {
+ if {$editor_to_use} {return 0}
+
+ set result [$editor index end]
+ return [expr {int($result) - 1}]
+}
+
+## Import list of bookmarks and breapoints
+ # This function also validates given input data
+ # This function does not do anything with the right panel
+ # @parm String Bookmarks - bookmakrs (eg. 00011010)
+ # @parm String Breakpoints - breakpoints (eg. 011010000000)
+ # @return void
+public method import_line_markers_data {Bookmarks Breakpoints} {
+ if {$editor_to_use} {return}
+
+ # Check validity of the given data
+ if {![regexp {^[01]*$} $Bookmarks]} {
+ puts stderr [mc "Invalid list of bookmarks -- bookmarks discarded"]
+ set Bookmarks {}
+ }
+ if {![regexp {^[01]*$} $Breakpoints]} {
+ puts stderr [mc "Invalid list of breakpoints -- bookmarks discarded"]
+ set Breakpoints {}
+ }
+
+ # Determinate number of the last line in the editor
+ set lastEnd [expr {int([$editor index end])}]
+
+ # Initialize list of highlighted lines
+ set highlighted_lines [string repeat 0 $lastEnd]
+
+ # Enable left panel
+ $iconBorder configure -state normal
+ $lineNumbers configure -state normal
+
+ # Fill in text widgets in left frame
+ $iconBorder delete 1.0 end
+ $iconBorder insert end [string repeat "\n" [expr {$lastEnd-2}]]
+ for {set i 2} {$i < $lastEnd} {incr i} {
+ $lineNumbers insert end "\n$i"
+ }
+ $lineNumbers configure -width [string length [expr {$lastEnd-1}]]
+
+ ## Import bookmarks
+ set len [string bytelength $Bookmarks] ;# Number of bookmark flags
+ set bookmarks [split $Bookmarks {}] ;# Bookmarks -> List
+ # Adjust given input data (length)
+ if {$lastEnd > $len} {
+ append bookmarks [string repeat { 0} [expr {$lastEnd - $len}]]
+ } elseif {$lastEnd < $len} {
+ set bookmarks [lrange $bookmarks 0 [expr {$lastEnd - 1}]]
+ }
+ # Determinate list of bookmarked lines
+ foreach line [lsearch -ascii -exact -all $bookmarks 1] {
+ if {!$line} {continue}
+
+ # Create bookmark image
+ if {$defaultCharHeight < 9} {
+ $iconBorder insert $line.0 {*}
+ } elseif {$defaultCharHeight < 15} {
+ $iconBorder image create $line.0 \
+ -image ::ICONS::16::dot \
+ -align center
+ } {
+ $iconBorder image create $line.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ # Create bookmark text tag
+ $editor tag add tag_bookmark $line.0 [expr {$line + 1}].0
+ parse $line
+ }
+
+ ## Import breakpoints
+ set len [string bytelength $Breakpoints] ;# Number of breakpoint flags
+ set breakpoints [split $Breakpoints {}] ;# Breakpoints -> List
+ # Adjust given input data (length)
+ if {$lastEnd > $len} {
+ set ins [string repeat { 0} [expr {$lastEnd - $len}]]
+ append breakpoints $ins
+ } elseif {$lastEnd < $len} {
+ set breakpoints [lrange $breakpoints 0 [expr {$lastEnd - 1}]]
+ }
+ # Determinate list of lines marked with bookmark
+ foreach line [lsearch -ascii -exact -all $breakpoints 1] {
+ if {!$line} {continue}
+
+ set line_1 $line
+ incr line_1
+ $lineNumbers tag add tag_breakpoint $line.0 $line_1.0
+ parse $line
+ }
+
+ # Disable left panel
+ $lineNumbers tag add right 1.0 end
+ $iconBorder tag add center 1.0 end
+ $iconBorder configure -state disabled
+ $lineNumbers configure -state disabled
+
+ reset_wraped_lines
+}
+
+## Execute any editor procedure
+ # @parm String null - anything (doesn't matter)
+ # @parm String procedure - procudure name
+ # @parm String arguments - procedure arguments
+ # @return String - procedure result
+public method editor_procedure {null procedure arguments} {
+ # call editor's procedure
+ return [eval "$procedure $arguments"]
+}
+
+## Jump to the bookmark below the current line
+ # @return Bool - result
+public method goto_next_bookmark {} {
+ if {$editor_to_use} {return}
+
+ # Local varibales
+ set line $last_cur_line ;# Current line
+ set linesMax [llength $bookmarks] ;# Maximal line number
+
+ incr line
+
+ # Search for the nearest bookmark
+ for {set i $line} {$i < $linesMax} {incr i} {
+ if {[lindex $bookmarks $i] == 1} {
+ goto $i
+ return 1
+ }
+ }
+
+ # Failed
+ return 0
+}
+
+## Jump to the bookmark above the current line
+ # @return Bool - result
+public method goto_prev_bookmark {} {
+ if {$editor_to_use} {return}
+
+ # Local varibales
+ set line $last_cur_line ;# Current line
+ set linesMax [llength $bookmarks] ;# Maximal line number
+
+ incr line -1
+
+ # Search for the nearest bookmark
+ for {set i $line} {$i > 0} {incr i -1} {
+ if {[lindex $bookmarks $i] == 1} {
+ goto $i
+ return 1
+ }
+ }
+
+ # Failed
+ return 0
+}
+
+## Set state of editor lock on status bar
+ # @parm Bool bool - 1 == Locked; 0 == Unlocked
+ # @return void
+public method set_lock {bool} {
+ if {$bool} {
+ setStatusTip -widget $Sbar_lock_file -text [mc "File switching locked"]
+ Sbar -freeze [mc "File switching locked"]
+ DynamicHelp::add $Sbar_lock_file -text [mc "Unlock file switching"]
+ $Sbar_lock_file configure \
+ -image ::ICONS::16::lock
+ } {
+ setStatusTip -widget $Sbar_lock_file -text [mc "File switching unlocked"]
+ Sbar -freeze [mc "File switching unlocked"]
+ DynamicHelp::add $Sbar_lock_file -text [mc "Lock file switching"]
+ $Sbar_lock_file configure \
+ -image ::ICONS::16::unlock
+ }
+ set auto_switching_lock $bool
+}
+
+## Invert simulator lock
+ # @retunr void
+public method invert_lock {} {
+ set_lock [expr {!$auto_switching_lock}]
+ $parentObject set_editor_lock $this $auto_switching_lock
+}
+
+## Switch from editor mode to simulator mode
+ # This operation will cause error if editor is in mode disabled
+ # @return void
+public method freeze {} {
+ if {$editor_to_use} {return}
+ close_completion_popup_window
+
+ # Adjust editor
+ $editor configure -state disabled
+ $editor tag remove tag_current_line 1.0 end
+ pack forget $Sbar_CRT_frame
+ catch {
+ pack forget $Sbar_dis_mode
+ }
+ catch {
+ pack forget $Sbar_ssim_mode
+ }
+ catch {
+ pack forget $Sbar_sim_mode
+ }
+ if {!$frozen} {
+ pack $Sbar_ssim_mode -side right
+ pack $Sbar_lock_file -side left
+ } {
+ pack $Sbar_sim_mode -side right
+ }
+ # Disable some popup menu items
+ foreach entry $freezable_menu_items {
+ $menu entryconfigure [::mc $entry] -state disabled
+ }
+ # Set mode flag
+ set frozen 1
+}
+
+## Switch from editor mode to disabled
+ # This operation will cause error if editor is in simulator mode
+ # @return void
+public method disable {} {
+ if {$editor_to_use} {return}
+ close_completion_popup_window
+
+ # Adjust editor
+ $editor configure -state disabled
+ $editor tag remove tag_current_line 1.0 end
+ pack forget $Sbar_CRT_frame
+ catch {
+ pack forget $Sbar_sim_mode
+ }
+ pack $Sbar_dis_mode -side right
+ if {!$frozen} {
+ pack $Sbar_lock_file -side left
+ }
+ # Disable some popup menu items
+ foreach entry $freezable_menu_items {
+ $menu entryconfigure [::mc $entry] -state disabled
+ }
+ # Set mode flag
+ set frozen 1
+}
+
+## Switch from simulator mode to editor mode
+ # @return void
+public method thaw {} {
+ if {$editor_to_use} {return}
+
+ # Set mode flag
+ set frozen 0
+ # Adjust editor
+ if {!$ro_mode} {
+ $editor configure -state normal
+ }
+ focus -force $editor
+ set idx [$editor index "insert linestart"]
+ $editor tag add tag_current_line $idx "$idx + 1 line"
+ pack $Sbar_CRT_frame
+ pack forget $Sbar_lock_file
+ catch {
+ pack forget $Sbar_sim_mode
+ }
+ catch {
+ pack forget $Sbar_ssim_mode
+ }
+ catch {
+ pack forget $Sbar_dis_mode
+ }
+ # Enable all popup menu items
+ if {!$ro_mode} {
+ foreach entry $freezable_menu_items {
+ $menu entryconfigure [::mc $entry] -state normal
+ }
+ }
+ # Recalculate counters
+ recalc_status_counter {} 0
+}
+
+## Move simulator line (line representing current position in simulator engine)
+ # @parm Int lineNum - target line number
+ # @return void
+public method move_simulator_line {lineNum} {
+ if {$editor_to_use} {return}
+ set lineNum_1 $lineNum
+ incr lineNum_1
+ unset_simulator_line
+ $editor tag add tag_simulator_curr $lineNum.0 $lineNum_1.0
+ $editor see $lineNum.0
+}
+
+## Unset simulator line tag and restore current line tag
+ # @return void
+public method unset_simulator_line {} {
+ $editor tag remove tag_simulator_curr 1.0 end
+}
+
+
+## IDE is now in "Simulator mode" (previous state was "Starting simulator")
+ # @return void
+public method now_frozen {} {
+ if {$editor_to_use} {return}
+ if {[winfo ismapped $Sbar_ssim_mode]} {
+ pack forget $Sbar_ssim_mode
+ pack $Sbar_sim_mode -side right
+ }
+}
+
+## Highlight lines which hasn't been highlighted yet
+ # @return void
+public method highlight_visible_area {} {
+ # Abort if the call is not relevant
+ if {!$editor_height} {
+ return
+ }
+
+ # Determinate indexes of the current view
+ set lastLine [expr {int([$editor index end])}]
+ set start [expr {int([$editor index @5,5])}]
+ set end [expr {$start + $editor_height - 1}]
+
+ # Adjust start and end index
+ if {$start < 1} {
+ set start 1
+ }
+ if {$end > $lastLine} {
+ set end $lastLine
+ }
+
+ # Abort if there is nothing to do
+ if {[string first 0 [string range $highlighted_lines $start $end]] == -1} {
+ return
+ }
+
+ # Enable editor if it's disabled
+ if {$frozen} {$editor configure -state normal}
+
+ # Highlight the current view
+ for {set line $start} {$line <= $end} {incr line} {
+ if {[string index $highlighted_lines $line] == 0} {
+ if {![parse $line]} {
+ if {$line != $start} {break}
+ }
+ }
+ }
+
+ # Restore previous editor state
+ if {$frozen} {$editor configure -state disabled}
+}
+
+
+## Save content of editor text widget
+ # note: Name of the target file should be stored in $fullFileName,
+ # if it is not then invoke procedure 'X::__save_as'
+ # @return Bool - result
+public method save {} {
+ if {$editor_to_use} {return 1}
+ if {$save_in_progress} {return 1}
+ set save_in_progress 1
+
+ # Check previously set filename
+ if {$fullFileName == {}} {
+ # Ask user for a new filename
+ set ::X::critical_procedure_in_progress 0
+ set save_in_progress 0
+ X::__save_as
+ } else {
+ # save data to file
+ if {[file exists $fullFileName]} {
+ catch {
+ file rename -force $fullFileName "$fullFileName~"
+ }
+ }
+ if {[catch {
+ set chanel [open $fullFileName w 420]
+ }]} then {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to open file:\n\"%s\"\nfor writing" $fullFileName]
+ set save_in_progress 0
+ return 0
+ }
+ fconfigure $chanel -translation $eol -encoding $encoding
+ puts -nonewline $chanel [getdata]
+ close $chanel
+ pack forget $Sbar_image
+ $editor edit modified 0
+ set modified 0
+
+ # Stop autosave timer
+ catch {
+ after cancel $autosave_timer
+ }
+ }
+
+ # Change application status
+ Sbar [mc "File %s saved" $fullFileName]
+ ::X::adjust_title
+
+ set save_in_progress 0
+ if {$fullFileName == {}} {
+ return 0
+ } {
+ return 1
+ }
+}
+
+## Set variable 'fullFileName' for later file save (method 'save')
+ # note: also change editors status bar
+ # @parm String full_filename - the full filename (including path)
+ # @parm String rootName - only filename with extension
+ # @return void
+public method set_FileName {full_filename rootName} {
+ if {$editor_to_use} {return}
+
+ # set variables
+ set fullFileName $full_filename
+ set filename $rootName
+ # change etitor status bar
+ $Sbar_fileName configure -text $filename -helptext $filename
+ # Determinate programming language
+ determinate_prog_lang 1
+}
+
+## Get current filename
+ # @return String - the filename
+public method getFileName {} {
+ return [list [file dirname $fullFileName] $filename]
+}
+
+## Change letter case acording to the given options
+ # @parm List options - list of 21 values, each must be one of {- L -U}
+ # '-' - keep case
+ # 'U' - Uppercase
+ # 'L' - Lowercase
+ # @return void
+public method change_letter_case {options} {
+
+ # Reset abort condition
+ set changeLCase_abort 0
+
+ # Initialize conter of iterations
+ set i 0
+
+ # Perform case change
+ foreach option $options \
+ tags {
+ tag_hex tag_oct
+ tag_dec tag_bin
+ tag_constant tag_unknown_base
+ tag_comment tag_control
+ tag_symbol tag_directive
+ tag_label tag_instruction
+ tag_sfr tag_indirect
+ tag_imm_hex tag_imm_oct
+ tag_imm_dec tag_imm_bin
+ tag_imm_constant tag_imm_unknown
+ tag_macro
+ } \
+ {
+ # Evaluate option
+ if {$option == {-}} {continue}
+ if {$option == {U}} {
+ set option {toupper}
+ } {
+ set option {tolower}
+ }
+
+ if {$tags == {tag_constant}} {
+ lappend tags {tag_constant_def}
+ } elseif {$tags == {tag_macro}} {
+ lappend tags {tag_macro_def}
+ }
+
+ # Iterate over tag ranges and change their letter case
+ foreach tag $tags {
+ set ranges [$editor tag ranges $tag]
+ for {set j 0} {$j < [llength $ranges]} {incr j} {
+ # Determinate string indexes
+ set firts [lindex $ranges $j]
+ incr j
+ set last [lindex $ranges $j]
+
+ # Perform letter case change
+ set string [string $option [$editor get $firts $last]]
+ $editor delete $firts $last
+ $editor insert $firts $string
+ $editor tag add $tag $firts $last
+
+ # Manage GUI
+ if {![expr {$i % 50}]} {
+ # Update progress bar
+ incr ::X::compilation_progress
+ update
+
+ # Conditional abort
+ if {$changeLCase_abort} {
+ return
+ }
+ }
+
+ # Increment counter of iterations
+ incr i
+ }
+ }
+ }
+}
+
+## Abort procedure 'change_letter_case'
+ # @return void
+public method change_letter_case_abort_now {} {
+ set changeLCase_abort 1
+}
+
+## Get maximum value for progressbar showing change letter case progress (proc. 'change_letter_case')
+ # @parm List options - same as with proc. 'change_letter_case'
+ # @return Int - Number of iterations divided by 50
+public method change_letter_case_get_count_of_iterations {options} {
+ set result 0
+ foreach option $options \
+ tag { tag_hex tag_oct
+ tag_dec tag_bin
+ tag_constant tag_unknown_base
+ tag_comment tag_control
+ tag_symbol tag_directive
+ tag_label tag_instruction
+ tag_sfr tag_indirect
+ tag_imm_hex tag_imm_oct
+ tag_imm_dec tag_imm_bin
+ tag_imm_constant tag_imm_unknown
+ tag_macro} \
+ {
+ if {$option == {-}} {continue}
+
+ incr result [llength [$editor tag ranges $tag]]
+ if {![expr {$result % 1000}]} {update}
+ }
+ return [expr {$result / 50}]
+}
+
+## Convert selected text to lowercase
+ # @retrun void
+public method lowercase {} {
+ # Nothing to do -> terminate
+ if {![llength [$editor tag nextrange sel 1.0]]} {
+ Sbar [mc "Unable to execute: nothing selected"]
+ return 0
+ }
+
+ $editor configure -autoseparators 0
+ set ranges [$editor tag ranges sel]
+ set len [llength $ranges]
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ set first [lindex $ranges $i]
+ set last [lindex $ranges $j]
+ set data [$editor get $first $last]
+ $editor tag remove $first $last
+ detete_text_in_editor $first $last
+ $editor insert $first [string tolower $data]
+ $editor tag add sel $first $last
+
+ set first [expr {int($first)}]
+ set last [expr {int($last)}]
+ set highlighted_lines [string replace $highlighted_lines \
+ $first $last [string repeat 0 [expr {$last - $first + 1}]]]
+ }
+
+ highlight_visible_area
+ $editor edit separator
+ $editor configure -autoseparators 1
+ return 1
+}
+
+## Convert selected text to uppercase
+ # @retrun void
+public method uppercase {} {
+ # Nothing to do -> terminate
+ if {![llength [$editor tag nextrange sel 1.0]]} {
+ Sbar [mc "Unable to execute: nothing selected"]
+ return 0
+ }
+
+ $editor configure -autoseparators 0
+ set ranges [$editor tag ranges sel]
+ set len [llength $ranges]
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ set first [lindex $ranges $i]
+ set last [lindex $ranges $j]
+ set data [$editor get $first $last]
+ $editor tag remove $first $last
+ detete_text_in_editor $first $last
+ $editor insert $first [string toupper $data]
+ $editor tag add sel $first $last
+
+ set first [expr {int($first)}]
+ set last [expr {int($last)}]
+ set highlighted_lines [string replace $highlighted_lines \
+ $first $last [string repeat 0 [expr {$last - $first + 1}]]]
+ }
+
+ highlight_visible_area
+ $editor edit separator
+ $editor configure -autoseparators 1
+ return 1
+}
+
+## Convert the first character of selected text to uppercase
+ # @retrun void
+public method capitalize {} {
+ # Nothing to do -> terminate
+ if {![llength [$editor tag nextrange sel 1.0]]} {
+ Sbar [mc "Unable to execute: nothing selected"]
+ return 0
+ }
+
+ $editor configure -autoseparators 0
+ set first [$editor index sel.first]
+ set last [$editor index sel.last]
+ set data [string toupper [$editor get $first $first+1c]]
+ detete_text_in_editor $first $first+1c
+ $editor insert $first $data
+ $editor tag add sel $first $last
+ parse [expr {int($first)}]
+ $editor edit separator
+ $editor configure -autoseparators 1
+ return 1
+}
+
+## Copy the selected text to the clipboard
+ # @return bool - 1: successful; 0: failed
+public method copy {} {
+ # get selected text
+ set data [getselection]
+
+ # Nothing to do -> terminate
+ if {$data == {}} {
+ Sbar [mc "Unable to execute: nothing selected"]
+ return 0
+ # Adjust clipboard content
+ } {
+ clipboard clear
+ clipboard append $data
+ return 1
+ }
+}
+
+## Paste clipboard content to the text at the cursor position
+ # @parm Bool = 0 - Use X selection instead of the clipboard
+ # @
+ # @
+ # @return bool - 1: successful; 0: failed
+public method paste args {
+ if {$critical_edit_proc} {return}
+ set critical_edit_proc 1
+
+ # Restore original cursor position in block selection mode
+ if {$selection_mode} {
+ set original_cur_pos [$editor index insert]
+ }
+
+ if {[lindex $args 0] == {1}} {
+ set cmd {selection}
+ } {
+ set cmd {clipboard}
+ }
+
+ # Get clipboard content
+ if {[catch {
+ set data [regsub -all {[\u0000-\u0008\u000B-\u000C\u000E-\u001F\u007F-\u009F]} [$cmd get] {}]
+ }]} then {
+ # Clipboard empty -> abort
+ set critical_edit_proc 0
+ return 0
+ }
+
+ if {[lindex $args 0] == {1}} {
+ set x [lindex $args 1]
+ set y [lindex $args 2]
+ $editor mark set insert @$x,$y
+ catch {
+ $editor tag remove sel 0.0 end
+ }
+ }
+
+ # delete selected block
+ $editor configure -autoseparators 0
+ deleteselection
+ recalc_left_frame
+ # insert data to the text, restore syntax hightlight and return 1
+ $editor insert [$editor index insert] $data
+ recalc_left_frame
+ recalc_status_counter {}
+ $editor see [$editor index insert]
+ update idle
+ set line [expr {int([$editor index insert])}]
+ rightPanel_adjust $line
+ parse $line
+ highlight_visible_area
+ $editor edit separator
+ $editor configure -autoseparators 1
+
+ # Reevaluate highlight on the next line if C language is used
+ if {$prog_language == 1} {
+ incr line
+ c_syntax_highlight $line
+ }
+ # Restore original cursor position in block selection mode
+ if {$selection_mode} {
+ $editor see $original_cur_pos
+ $editor mark set insert $original_cur_pos
+ }
+
+ rewrite_breakpoint_tags
+
+ update
+ set critical_edit_proc 0
+ return 1
+}
+
+## Take back last editor operation
+ # @return void
+public method undo {} {
+ if {$critical_edit_proc} {return}
+ set critical_edit_proc 1
+
+ if {![catch {$editor edit undo}]} {
+ # Inform autocompletion mechanism
+ $editor edit redo
+ parse_current_line
+ autocompletion_maybe_important_change insert insert
+ $editor edit undo
+ manage_autocompletion_list [expr {int([$editor index insert])}]
+
+ recalc_left_frame
+ recalc_status_counter {}
+ recalc_status_modified 1
+ rightPanel_adjust [expr {int([$editor index insert])}]
+ $editor see [$editor index insert]
+ set highlighted_lines [string repeat 0 [string bytelength $highlighted_lines]]
+ update
+ highlight_visible_area
+ catch {
+ $editor tag remove sel 0.0 end
+ }
+ }
+ set critical_edit_proc 0
+}
+
+## Take back last Undo operation
+ # @return void
+public method redo {} {
+ if {$critical_edit_proc} {return}
+ set critical_edit_proc 1
+ if {![catch {$editor edit redo}]} {
+ # Inform autocompletion mechanism
+ $editor edit undo
+ parse_current_line
+ autocompletion_maybe_important_change insert insert
+ $editor edit redo
+ manage_autocompletion_list [expr {int([$editor index insert])}]
+
+ recalc_left_frame
+ recalc_status_counter {}
+ recalc_status_modified 1
+ rightPanel_adjust [expr {int([$editor index insert])}]
+ $editor see [$editor index insert]
+ set highlighted_lines [string repeat 0 [string bytelength $highlighted_lines]]
+ update
+ highlight_visible_area
+ catch {
+ $editor tag remove sel 1.0 end
+ }
+ }
+ set critical_edit_proc 0
+}
+
+## Cut the selected text and put it into the clipboard
+ # @return bool - 1: successful; 0: failed
+public method cut {} {
+ if {$critical_edit_proc} {return}
+ set critical_edit_proc 1
+ # get selected text
+ set data [getselection]
+
+ # Nothing to do -> terminate
+ if {$data == {}} {
+ Sbar [mc "Unable to execute: nothing selected"]
+ set critical_edit_proc 0
+ return 0
+ # Cut
+ } {
+ # Adjust clipboard content
+ deleteselection
+ clipboard clear
+ clipboard append $data
+ $editor see insert
+ set line [expr {int([$editor index insert])}]
+ parse $line
+ update
+ recalc_left_frame
+ rightPanel_adjust $line
+ set critical_edit_proc 0
+ return 1
+ }
+}
+
+## Delete current line
+ # @return void
+public method delete_current_line {} {
+ if {
+ [$editor compare {insert linestart} == {insert lineend}]
+ &&
+ [$editor compare {insert linestart} == {end-1l}]
+ } then {
+ return
+ }
+ detete_text_in_editor {insert linestart} {insert linestart + 1l}
+ $this resetUpDownIndex
+ $this recalc_left_frame
+ $this parse [expr {int([$editor index insert])}]
+ update
+}
+
+## Insure that command line is focused
+ # @retrun void
+public method cmd_line_force_on {} {
+ if {$editor_to_use} {return}
+ if {![winfo viewable $cmd_line]} {
+ pack $cmd_line -side top -fill x
+ }
+ update
+}
+
+## Insure that command line is NOT focused
+ # @retrun void
+public method cmd_line_force_off {} {
+ if {$editor_to_use} {return}
+
+ if {!${::APPLICATION_LOADED}} {return}
+ if {[winfo viewable $cmd_line]} {
+ pack forget $cmd_line
+ focus $editor
+ }
+ update
+}
+
+## Kill child processes
+ # @return void
+public method kill_childern {} {
+ if {$editor_to_use} {
+ bind $top_frame <Destroy> {}
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no kill command on Microsoft Windows
+ catch {
+ exec -- kill $pid
+ }
+ }
+ catch {
+ file delete -force -- [file join [${::X::actualProject} cget -ProjectDir] .#special:tmp]
+ }
+ }
+}
+
+## Get ID of file type (programing language used)
+ # @return Int - 0 == Assembly language; 1 == C language
+public method get_language {} {
+ if {$prog_language == -1} {
+ set ext [string trimleft [file extension $filename] {.}]
+ if {$ext == {c} || $ext == {h} || $ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ return 1
+ } elseif {$ext == {lst}} {
+ return 2
+ } else {
+ return 0
+ }
+ } {
+ return $prog_language
+ }
+}
+
+## Set file type (programing language used)
+ # @parm Int lang - -1 == unknown; 0 == Assembly language; 1 == C language
+ # @return void
+public method force_language {lang} {
+ set prog_language_old $prog_language
+ set prog_language $lang
+
+ if {$prog_language_old != $prog_language} {
+ prog_lang_changed
+ }
+}
+
+## Document current function
+ # @return void
+public method document_current_func {} {
+ # Critical procedure
+ if {$critical_edit_proc} {return}
+ set critical_edit_proc 1
+
+ # Check if this procedure can be done
+ if {$editor_to_use || $prog_language != 1} {return}
+
+ # Determinate line content
+ set line_number [expr {int([$editor index insert])}]
+ set line_content [$editor get {insert linestart} {insert lineend}]
+ set line_n $line_number
+ for {set i 0} {$i < 50} {incr i} {
+ if {[string first {)} $line_content] != -1} {
+ break
+ }
+ incr line_n
+ append line_content { } [$editor get [list $line_n.0 linestart] [list $line_n.0 lineend]]
+ }
+
+ # Check if line content is valid function declaration
+ if {![regexp {^\s*(\w+\s+)+\w+\(.*\)} $line_content]} {
+ Sbar [mc "No function to document"]
+ set critical_edit_proc 0
+ return
+ }
+
+ # Determinate leading space to keep indention level
+ if {![regexp {^\s+} $line_content space]} {
+ set space {}
+ }
+
+ # Insert '/**'
+ $editor insert $line_number.0 "${space}/**\n"
+ incr line_number
+
+ # Document arguments
+ set args {}
+ if {[regexp {\(.*\)} $line_content args]} {
+ set args [string range $args 1 end-1]
+ foreach word [split $args {,}] {
+ set word [split [string trim $word "\t  "]]
+ if {[llength $word] < 2} {
+ continue
+ }
+ set word [lindex $word end]
+ regsub {\[.*\]$} $word {} word
+ regsub {^(\&|\*\*?)} $word {} word
+ $editor insert $line_number.0 "${space} * @param ${word}\n"
+ incr line_number
+ }
+ }
+
+ # Document return value
+ if {![regexp {^\s*void\s+} $line_content]} {
+ $editor insert $line_number.0 "${space} * @return\n"
+ incr line_number
+ }
+ $editor insert $line_number.0 "${space} */\n"
+ incr line_number
+
+ # Highlight
+ recalc_left_frame
+ recalc_status_counter {}
+ $editor see $line_number.0
+ update
+ rightPanel_adjust $line_number
+ parse $line_number
+ highlight_visible_area
+ incr line_number
+ c_syntax_highlight $line_number
+ set critical_edit_proc 0
+}
+
+## Get file statistics
+ # @return List - List of integers in this format:
+ # Index Meaning
+ # 0 Words and numbers (Characters)
+ # 1 Comments (Characters)
+ # 2 Others (Characters)
+ # 3 Total characters (Characters)
+ # 4 Words (Strings)
+ # 5 Keywords (Strings)
+ # 6 Comments (Strings)
+ # 7 Total strings (Strings)
+ # 8 Empty lines (Lines)
+ # 9 Commented lines (Lines)
+ # 10 Normal lines (Lines)
+ # 11 Total lines (Lines)
+public method getFileStatistics {} {
+ if {$editor_to_use} {return {0 0 0 0 0 0 0 0}}
+ set last_line [expr {int([$editor index end])}]
+
+ set words_and_numbers 0
+ set chars_comments 0
+ set others 0
+ set words 0
+ set keywords 0
+ set comments 0
+ set empty_lines 0
+ set commented_lines 0
+ set normal_lines 0
+
+ # List of highlighting tags related to comments
+ set comment_tags {
+ tag_comment tag_c_comment tag_c_dox_comment
+ tag_c_dox_tag tag_c_dox_word tag_c_dox_name
+ tag_c_dox_html
+ }
+ # List of highlighting tags related to keywords
+ set keyword_tags {
+ tag_directive tag_instruction tag_control
+ tag_c_keyword tag_c_directive
+ }
+
+ # Iterate over lines in editor
+ for {set line_num 1} {$line_num < $last_line} {incr line_num} {
+ # Get line length and content
+ set line [string trimright [$editor get $line_num.0 [list $line_num.0 lineend]]]
+ set len [string length $line]
+
+ # Handle empty lines
+ if {!$len} {
+ incr empty_lines
+ continue
+ }
+ # Save some values for purpose of section "Lines"
+ set last_words $words
+ set last_keywords $keywords
+ set last_comments $comments
+
+ # Iterate over characters on the line
+ set char {}
+ set found 0
+ set last_wordstart -1
+ for {set i 0} {$i < $len} {incr i} {
+ # Determinate word type
+ set found 0
+ set wordstart [$editor index [list $line_num.$i wordstart]]
+ if {$wordstart != $last_wordstart} {
+ set wordend [$editor index [list $line_num.$i wordend]]
+ set last_wordstart $wordstart
+ set tag_names [$editor tag names $line_num.$i]
+ foreach tags [list $comment_tags $keyword_tags] \
+ var {comments keywords} \
+ {
+ foreach tag $tag_names {
+ if {[lsearch $tags $tag] != -1} {
+ incr $var
+ set found 1
+ break
+ }
+ }
+ if {$found} {break}
+ }
+
+ if {!$found} {
+ incr words
+ }
+ }
+
+ # Determinate character type
+ set found 0
+ set char [string index $line $i]
+ foreach tag [$editor tag names $line_num.$i] {
+ if {[lsearch $comment_tags $tag] != -1} {
+ incr chars_comments
+ set found 1
+ break
+ }
+ }
+
+ if {$found} {continue}
+ if {[string is wordchar -strict $char]} {
+ incr words_and_numbers
+ } {
+ incr others
+ }
+ }
+
+ # Determinate line type excluding empty lines
+ if {$last_words == $words && $last_keywords == $keywords && $last_comments < $comments} {
+ incr commented_lines
+ } {
+ incr normal_lines
+ }
+ }
+
+ # Composite and return results
+ return [list \
+ $words_and_numbers $chars_comments $others \
+ [expr {$words_and_numbers + $chars_comments + $others}] \
+ \
+ $words $keywords $comments \
+ [expr {$words + $keywords + $comments}] \
+ \
+ $empty_lines $commented_lines $normal_lines \
+ [expr {$empty_lines + $commented_lines + $normal_lines}] \
+ ]
+}
+
+## Set read only mode
+ # @parm Bool mode_frag - 1 == Read only; 0 = Read and write
+ # @return void
+public method change_RO_MODE {mode_frag} {
+ if {$editor_to_use} {return}
+ set ro_mode $mode_frag
+
+ # Set to read only
+ if {$ro_mode} {
+ $editor configure -state disabled
+ $ins_mode_lbl configure \
+ -bg {#DD0000} \
+ -fg {#FFFFFF} \
+ -text [mc " READ ONLY "]\
+ -cursor left_ptr
+ setStatusTip -widget $ins_mode_lbl \
+ -text [mc "This editor is only for reading, to change that press alt+v and o"]
+ bind $ins_mode_lbl <Button-1> {}
+ set state {disabled}
+
+ # Set to normal mode
+ } {
+ $editor configure -state normal
+ $ins_mode_lbl configure \
+ -bg {#DDDDDD} \
+ -cursor hand2
+ setStatusTip -widget $ins_mode_lbl \
+ -text [mc "Insertion mode -- OVR == overwrite; INS == insert"]
+ bind $ins_mode_lbl <Button-1> "$this switch_ins_ovr"
+ adjust_INS_OVR_label
+ set state {normal}
+ }
+
+ # Adjust menus and main toolbar
+ foreach entry $read_na_only_menu_items {
+ $menu entryconfigure [::mc $entry] -state $state
+ }
+ ::X::adjust_mainmenu_and_toolbar_to_editor $ro_mode {}
+}
+
+## Perform program jump
+ # @return void
+public method ljmp_this_line {} {
+ if {$editor_to_use} {return}
+ # Determinate target address
+ set address [$parentObject simulator_line2address \
+ [expr {int([$editor index insert])}] \
+ [$parentObject simulator_get_filenumber $fullFileName] \
+ ]
+ if {$address == {}} {
+ return
+ }
+
+ # Perform program jump
+ $parentObject setPC $address
+ set lineNum [$parentObject simulator_getCurrentLine]
+ if {$lineNum != {}} {
+ $parentObject move_simulator_line $lineNum
+ } {
+ $parentObject editor_procedure {} unset_simulator_line {}
+ }
+ $parentObject Simulator_sync_PC_etc
+}
+
+## Perform subprogram call
+ # @return void
+public method lcall_this_line {} {
+ if {$editor_to_use} {return}
+ # Determinate target address
+ set address [$parentObject simulator_line2address \
+ [expr {int([$editor index insert])}] \
+ [$parentObject simulator_get_filenumber $fullFileName] \
+ ]
+ if {$address == {}} {
+ return
+ }
+
+ # Perform subprogram call
+ $parentObject simulator_subprog_call $address
+ set lineNum [$parentObject simulator_getCurrentLine]
+ if {$lineNum != {}} {
+ $parentObject move_simulator_line $lineNum
+ } {
+ $parentObject editor_procedure {} unset_simulator_line {}
+ }
+ $parentObject Simulator_sync_PC_etc
+} \ No newline at end of file
diff --git a/lib/environment.tcl b/lib/environment.tcl
new file mode 100755
index 0000000..33af4a3
--- /dev/null
+++ b/lib/environment.tcl
@@ -0,0 +1,3184 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# * Defines some settings and procedures
+# * Defines basic GUI environment:
+# - Main menubar
+# - Main toolbar
+# - Status bar
+# --------------------------------------------------------------------------
+
+
+# PRE-INITIALIZATION
+# ----------------------------------------
+
+# Restore last session
+set show_welcome_dialog 0
+if {![X::restore_session]} {
+ set show_welcome_dialog 1
+}
+
+# Some key shortcuts for main window
+bind . <Control-Key-1> {manipulate_panel {sim} ; break}
+bind . <Control-Key-2> {manipulate_panel {graph} ; break}
+bind . <Control-Key-3> {manipulate_panel {mess} ; break}
+bind . <Control-Key-4> {manipulate_panel {todo} ; break}
+bind . <Control-Key-5> {manipulate_panel {calc} ; break}
+
+# bind . <Alt-Control-Key-1> {manipulate_panel {lsh} ; break}
+# bind . <Alt-Control-Key-2> {manipulate_panel {open} ; break}
+# bind . <Alt-Control-Key-3> {manipulate_panel {proj} ; break}
+# bind . <Alt-Control-Key-4> {manipulate_panel {fsb} ; break}
+# bind . <Alt-Control-Key-5> {manipulate_panel {sfr} ; break}
+
+bind . <Control-Key-6> {manipulate_panel {book} ; break}
+bind . <Control-Key-7> {manipulate_panel {brk} ; break}
+bind . <Control-Key-8> {manipulate_panel {ins} ; break}
+bind . <Control-Key-9> {manipulate_panel {wtch} ; break}
+bind . <Control-Key-0> {manipulate_panel {sub} ; break}
+# bind . <Alt-Key-5> {manipulate_panel {rsh} ; break}
+
+# General widget bindings
+bind Menu <Button> {+catch {%W configure -cursor left_ptr}}
+bind Text <Control-d> {}
+bind Text <Control-b> {}
+bind Text <Control-a> {}
+bind Text <Control-o> {}
+bind Text <Control-i> {}
+bind Text <Control-f> {}
+bind Text <F3> {}
+bind Text <Insert> {}
+bind Text <KP_Enter> "[bind Text <Return>]; break"
+bind Text <Control-Key-z> {catch {%W edit undo}; break}
+bind Text <Control-Key-Z> {catch {%W edit redo}; break}
+bind Text <Control-Key-c> {tk_textCopy %W; break}
+bind Text <Control-Key-x> {tk_textCut %W; break}
+bind Text <Control-Key-v> {
+ catch {
+ %W delete sel.first sel.last
+ }
+ tk_textPaste %W
+}
+bind Text <<Paste>> {
+ catch {
+ %W delete sel.first sel.last
+ }
+ catch {
+ %W insert insert [clipboard get]
+ }
+ break
+}
+bind Text <Control-Key-a> {%W tag add sel 1.0 end; break}
+bind Entry <<Paste>> {
+ catch {
+ %W delete sel.first sel.last
+ }
+ catch {
+ %W insert insert [clipboard get]
+ }
+ break
+}
+bind Entry <Control-Key-a> {%W selection range 0 end; break}
+bind TEntry <Control-Key-a> {%W selection range 0 end; break}
+
+# Dynamic help (Bwidget)
+DynamicHelp::configure -font [font create -size -14 -family {helvetica}] -delay 500 -background {#FFFFDD}
+
+# General purpose fonts
+set smallfont_color {#5599DD}
+set smallfont [font create -size -10 -family {helvetica} -weight normal]
+set smallfont_bold [font create -size -10 -family {helvetica} -weight bold]
+
+# LOAD PROGRAM ICONS
+# -----------------------------
+foreach directory {16x16 22x22 32x32} ns {16 22 32} {
+ namespace eval ::ICONS::${ns} {}
+ foreach filename [glob "${::LIB_DIRNAME}/../icons/${directory}/*.png"] {
+ set filename [file normalize $filename]
+ set iconname [file tail $filename]
+ regexp {^\w+} $iconname iconname
+ if {[catch {
+ image create photo ::ICONS::${ns}::${iconname} -format png -file $filename
+ } result]} then {
+ puts stderr {}
+ puts -nonewline stderr $result
+ image create photo ::ICONS::${ns}::${iconname}
+ }
+ }
+}
+
+# WM and Tk options
+tk appname "mcu8051ide"
+wm command . "mcu8051ide $argv"
+wm client . [info hostname]
+tk scaling 1.0
+tk_setPalette \
+ activeBackground {#EEEEEE} \
+ foreground {#000000} \
+ selectColor {#FFFFFF} \
+ activeForeground {#0000DD} \
+ highlightBackground {#EEEEEE} \
+ selectBackground {#9999BB} \
+ background {#EEEEEE} \
+ highlightColor {#000000} \
+ selectForeground {#FFFFFF} \
+ disabledForeground {#888888} \
+ insertBackground {#000000} \
+ troughColor {#EEEEEE}
+
+wm title . "MCU 8051 IDE"
+wm state . normal
+wm geometry . $::CONFIG(WINDOW_GEOMETRY)
+if {!$::MICROSOFT_WINDOWS} {
+ # There is no such thing on Windows OS
+ wm attributes . -zoomed $::CONFIG(WINDOW_ZOOMED)
+}
+wm protocol . WM_DELETE_WINDOW {::X::__exit}
+wm iconphoto . ::ICONS::16::mcu8051ide
+. configure -bg {#EEEEEE}
+
+# Dynamic Data Exchange on Microsoft Windows
+if {$::MICROSOFT_WINDOWS} {
+ dde servername -force -- [tk appname]
+}
+
+ttk::style theme use clam
+
+# - ttk
+set TTK_COMMON_BG {#E0E0E0}
+ttk::style configure TFrame \
+ -background {#EEEEEE}
+
+ttk::style configure TNotebook \
+ -background {#EEEEEE} \
+ -fieldbackground {red}
+ttk::style map TNotebook \
+ -background [list \
+ active red \
+ pressed blue \
+ pressed green \
+ ]
+
+font configure TkTextFont -family {helvetica} -size -12 -weight {normal}
+font configure TkDefaultFont -family {helvetica} -size -12 -weight {normal}
+
+ttk::style configure StringNotFound.TEntry \
+ -fieldbackground {#FFDDDD}
+ttk::style configure StringFound.TEntry \
+ -fieldbackground {#DDFFDD}
+
+ttk::style configure Simulator.TEntry
+ttk::style map Simulator.TEntry \
+ -fieldbackground [list readonly {#F8F8F8}] \
+ -foreground [list readonly {#888888}]
+ttk::style configure Simulator_HG.TEntry \
+ -foreground {#CC8800}
+ttk::style configure Simulator_WhiteBg.TEntry \
+ -fieldbackground {#FFFFFF} \
+ -fielddisabledbackground {#FFFFFF}
+ttk::style configure Simulator_WhiteBg_HG.TEntry \
+ -fieldbackground {#FFFFFF} \
+ -fielddisabledbackground {#FFFFFF} \
+ -foreground {#CC8800}
+ttk::style configure Simulator_WhiteBg_Sel.TEntry \
+ -fieldbackground {#DDDDFF} \
+ -fielddisabledbackground {#DDDDFF}
+ttk::style configure Simulator_WhiteBg_HG_Sel.TEntry \
+ -foreground {#CC8800} \
+ -fieldbackground {#DDDDFF} \
+ -fielddisabledbackground {#DDDDFF}
+
+ttk::style configure Simulator_watchdogEntry_0.TEntry \
+ -fieldbackground {#88FF88} \
+ -fielddisabledbackground {#66DD66}
+ttk::style map Simulator_watchdogEntry_0.TEntry \
+ -foreground [list readonly {#888888}]
+
+ttk::style configure Simulator_watchdogEntry_1.TEntry \
+ -fieldbackground {#FFFF55} \
+ -fielddisabledbackground {#DDDD33}
+ttk::style map Simulator_watchdogEntry_1.TEntry \
+ -foreground [list readonly {#888888}]
+
+ttk::style configure Simulator_watchdogEntry_2.TEntry \
+ -fieldbackground {#FF5555} \
+ -fielddisabledbackground {#DD3333}
+ttk::style map Simulator_watchdogEntry_2.TEntry \
+ -foreground [list readonly {#888888}]
+
+ttk::style configure TLabelframe \
+ -background {#EEEEEE}
+ttk::style configure TLabel \
+ -background {#EEEEEE}
+
+ttk::style configure TButton \
+ -background $TTK_COMMON_BG \
+ -padding 0
+ttk::style configure RedBg.TButton \
+ -padding 0
+ttk::style map RedBg.TButton \
+ -background [list \
+ active {#FFBBBB} \
+ !active {#FF8888} \
+ ] \
+ -foreground [list \
+ active {#FF0000} \
+ !active {#000000} \
+ ]
+ttk::style configure GreenBg.TButton \
+ -padding 0
+ttk::style map GreenBg.TButton \
+ -background [list \
+ active {#BBFFBB} \
+ !active {#88FF88} \
+ ] \
+ -foreground [list \
+ active {#00FF00} \
+ !active {#000000} \
+ ]
+
+ttk::style configure Flat.TButton \
+ -background {#EEEEEE} \
+ -padding 0 \
+ -borderwidth 1 \
+ -relief flat
+ttk::style map Flat.TButton \
+ -relief [list active raised] \
+ -background [list disabled {#EEEEEE}]
+
+ttk::style configure TMenubutton \
+ -padding 0 \
+ -background $TTK_COMMON_BG
+ttk::style configure Flat.TMenubutton \
+ -padding 0 \
+ -background {#EEEEEE} \
+ -borderwidth 1 \
+ -relief flat
+ttk::style map Flat.TMenubutton \
+ -relief [list active raised] \
+ -background [list disabled {#EEEEEE}]
+
+ttk::style configure FlatWhite.TButton \
+ -padding 0 \
+ -background {#FFFFFF} \
+ -borderwidth 1 \
+ -relief flat
+ttk::style map FlatWhite.TButton \
+ -relief [list active raised] \
+ -background [list disabled {#FFFFFF}]
+
+ttk::style configure ToolButton.TButton \
+ -background {#EEEEEE} \
+ -padding 1 \
+ -borderwidth 1 \
+ -relief flat
+ttk::style map ToolButton.TButton \
+ -relief [list active raised] \
+ -background [list disabled {#EEEEEE}]
+
+ttk::style configure TCombobox \
+ -background $TTK_COMMON_BG \
+ -fieldfont [font create -family {helvetica} -size -12 -weight {normal}]
+ttk::style map TCombobox \
+ -foreground [list disabled {#888888}] \
+ -fieldbackground [list \
+ readonly $TTK_COMMON_BG \
+ disabled {#EEEEEE} \
+ {!readonly !disabled} {#FFFFFF} \
+ ]
+
+ttk::style configure TScrollbar \
+ -background $TTK_COMMON_BG \
+ -troughcolor {#F8F8F8}
+
+ttk::style configure TScale \
+ -background $TTK_COMMON_BG
+ttk::style map TScale \
+ -troughcolor [list \
+ disabled $TTK_COMMON_BG \
+ !disabled {#F8F8F8} \
+ ]
+
+ttk::style configure TProgressbar \
+ -background $TTK_COMMON_BG \
+ -troughcolor {#F8F8F8}
+
+update idle
+
+## Widget styles
+ # Load images for checkbuttons and radiobuttons
+foreach i {raoff raon choff chon} {
+ if {[catch {
+ image create photo ::ICONS::$i -file "${::LIB_DIRNAME}/../icons/other/$i.png" -format png
+ } result]} then {
+ puts stderr {}
+ puts -nonewline stderr $result
+ image create photo ::ICONS::$i
+ }
+}
+ # - Menu
+option add *Menu.activeForeground {#FFFFFF} userDefault
+option add *Menu.activeBackground {#8888DD} userDefault
+option add *Menu.activeBorderWidth 1 userDefault
+option add *Menu.cursor left_ptr userDefault
+option add *Menu.tearOff 0 userDefault
+option add *Menu.borderWidth 1 userDefault
+option add *Menu.relief raised userDefault
+option add *Menu.background {#F8F8F8} userDefault
+option add *Menu.font [font create -family {helvetica} -size -12 -weight {normal}] userDefault
+ # - Label
+option add *Label.highlightThickness 0 userDefault
+ # - Entry
+option add *Entry.highlightThickness 0 userDefault
+option add *Entry.BorderWidth 1 userDefault
+option add *Entry.font [font create -family {helvetica} -size -12 -weight {normal}] userDefault
+ # - Text
+option add *Text.Background {#FFFFFF} userDefault
+option add *Text.highlightThickness 0 userDefault
+option add *Text.BorderWidth 1 userDefault
+option add *Text.Relief sunken userDefault
+option add *Text.font [font create -family {helvetica} -size -12 -weight {normal}] userDefault
+ # - Spinbox
+option add *Spinbox.Background {#FFFFFF} userDefault
+option add *Spinbox.highlightThickness 0 userDefault
+ # - Scrollbar
+option add *Scrollbar.activeBackground {#8888FF} userDefault
+option add *Scrollbar.BorderWidth 1 userDefault
+option add *Scrollbar.Background {#EEEEEE} userDefault
+option add *Scrollbar.troughColor {#EEEEEE} userDefault
+option add *Scrollbar.Relief sunken userDefault
+option add *Scrollbar.activeRelief raised userDefault
+option add *Scrollbar.elementBorderWidth 1 userDefault
+ # - Button
+option add *Button.activeForeground {#0000DD} interactive
+option add *Button.font [font create -family {helvetica} -size -12 -weight {normal}] userDefault
+ # - Radiobutton
+option add *Radiobutton.BorderWidth 0 userDefault
+option add *Radiobutton.Image ::ICONS::raoff userDefault
+option add *Radiobutton.SelectImage ::ICONS::raon userDefault
+option add *Radiobutton.selectColor {#EEEEEE} userDefault
+option add *Radiobutton.Compound left userDefault
+option add *Radiobutton.IndicatorOn 0 userDefault
+option add *Radiobutton.font [font create -family {helvetica} -size -12 -weight {normal}] userDefault
+ # - Checkbutton
+option add *Checkbutton.BorderWidth 0 userDefault
+option add *Checkbutton.Image ::ICONS::choff userDefault
+option add *Checkbutton.SelectImage ::ICONS::chon userDefault
+option add *Checkbutton.selectColor {#EEEEEE} userDefault
+option add *Checkbutton.Compound left userDefault
+option add *Checkbutton.IndicatorOn 0 userDefault
+option add *Radiobutton.font [font create -family {helvetica} -size -12 -weight {normal}] userDefault
+ # - Scale
+option add *Scale.activeBackground {#8888FF} userDefault
+ # - NoteBook
+option add *NoteBook.font [font create -family {helvetica} -size -12 -weight {normal}] userDefault
+option add *NoteBook.Background {#EEEEEE} userDefault
+option add *NoteBook.ActiveBackground {#EEEEEE} userDefault
+ # - TopLevel and Frame
+option add *Toplevel.Background {#EEEEEE} userDefault
+option add *Frame.Background {#EEEEEE} userDefault
+option add *PagesManager.Background {#EEEEEE} userDefault
+ # - Others ...
+option add *Panedwindow.Background {#EEEEEE} userDefault
+option add *Listbox.Background {#EEEEEE} userDefault
+option add *Button.Background {#EEEEEE} userDefault
+option add *Label.Background {#EEEEEE} userDefault
+option add *Canvas.Background {#EEEEEE} userDefault
+
+
+# MEMORY CELL HELP WINDOW
+# -------------------------------
+
+set help_window_for_bit 0 ;# Bool: Current help window is representing a bit not byte
+set help_window_variable_address 0 ;# Bool: Help window with variable address (intended for register watches)
+set HELPWINDOW {} ;# Widget: Help window
+# Objects in canvas widget in the bit help window
+array set help_window_bit {
+ 0 {} 1 {} 2 {} 3 {} 4 {} 5 {} 6 {} 7 {}
+ R {} B {} A {}
+}
+
+## Create memory cell help window for future use
+ # @parm Widget root - parent GUI object (eg. '.')
+ # @parm String val - hexadecimal representation of cell value
+ # @parm String addr - hexadecimal representation of cell address
+ # @return void
+proc create_help_window {root val addr} {
+ global help_window_variable_address
+ global help_window_for_bit
+
+ # Set parent and detroy previous help window
+ set ::HELPWINDOW_ROOT $root
+ catch {destroy ${::HELPWINDOW}}
+ set ::HELPWINDOW {}
+
+ # Normalize root name
+ if {![regexp {\.$} $root]} {
+ append root {.}
+ }
+
+ # Create logical frame structure
+ set ::HELPWINDOW [frame ${root}help_window -bd 0 -bg {#BBBBFF} -padx 2 -pady 2]
+ pack [frame ${::HELPWINDOW}.top] -fill x -expand 1
+ pack [label ${::HELPWINDOW}.top.img -bg {#BBBBFF}] -side left
+ pack [label ${::HELPWINDOW}.top.tit -bg {#BBBBFF}] -side left -fill x -expand 1
+ pack [frame ${::HELPWINDOW}.msg -bg {#FFFFFF}] -fill both -expand 1
+
+ # Create window header
+ ${::HELPWINDOW}.top.img configure -image ::ICONS::16::kcmmemory
+ set haddr $addr
+ if {[string length [lindex $haddr 0]] == 3} {
+ set haddr [string replace $haddr 0 0]
+ }
+ ${::HELPWINDOW}.top.tit configure -text "0x$haddr"
+
+ if {[lindex $addr 1] == {BIT}} {
+ set help_window_for_bit 1
+ create_help_window_bit [lindex $addr 0]
+ } {
+ set help_window_for_bit 0
+ create_help_window_byte $val
+ }
+
+ set help_window_variable_address 0 ;# Bool: Help window with variable address
+}
+
+## Create memory cell help window for bit value -- auxiliary procedure for create_help_window
+ # @parm String addr - hexadecimal representation of the bit address
+ # @return void
+proc create_help_window_bit {addr} {
+ global help_window_bit ;# Array: Canvas rectanges representing bits
+
+ # Create and pack canvas widget where the bits will be shown
+ set canvas [canvas ${::HELPWINDOW}.msg.c \
+ -width 150 -height 50 -bg white -bd 0 \
+ -relief flat -highlightthickness 0 \
+ ]
+ pack $canvas -pady 2 -padx 3
+
+ # Determinate bit address and bit number in the register
+ set bit_addr [expr {"0x$addr"}]
+ set reg_addr [${::X::actualProject} getRegOfBit $bit_addr]
+ set bit_number [expr {$bit_addr % 8}]
+ set bit_addr [expr {$bit_addr - $bit_number + 8}]
+
+ set x0 40
+
+ set y0 0
+ set y1 11
+
+ # Create 8 bit rectangles in the canvas
+ for {set i 7} {$i >= 0} {incr i -1} {
+ incr bit_addr -1
+
+ # Determinate rectangle color
+ if {[${::X::actualProject} getBit $bit_addr]} {
+ set fill $::BitMap::one_fill
+ set outline $::BitMap::one_outline
+ } {
+ set fill $::BitMap::zero_fill
+ set outline $::BitMap::zero_outline
+ }
+
+ # Create label for the bit
+ $canvas create text [expr {$x0 + 6}] $y0 \
+ -text $i -anchor n -font $::Simulator_GUI::smallfont \
+ -fill $::Simulator_GUI::small_color
+
+
+ # Create bit rectagle
+ set help_window_bit($i) [$canvas create \
+ rectangle $x0 $y1 \
+ [expr {$x0 + 12}] \
+ [expr {$y1 + 12}] \
+ -fill $fill -outline $outline \
+ ]
+
+ # Adjust X position for the next rectagle
+ incr x0 12
+ incr x0 2
+ }
+
+ # Create text with register address
+ set help_window_bit(R) [$canvas create text 0 12 \
+ -font ${::Simulator_GUI::entry_font} \
+ -anchor w -text "0x[format %X $reg_addr]" \
+ ]
+
+ # Create text with bit address
+ set help_window_bit(B) [$canvas create text 0 45 \
+ -font ${::Simulator_GUI::entry_font} \
+ -anchor w -text "0x$addr" \
+ ]
+
+ # Create arrow pointing to the bit
+ set arr_pos [expr {47 + ((7 - $bit_number) * 14)}]
+ set help_window_bit(A) [$canvas create line \
+ 40 45 $arr_pos 45 $arr_pos 24 \
+ -arrow last -fill black \
+ ]
+}
+
+## Create memory cell help window for bit value -- auxiliary procedure for create_help_window
+ # @parm String val - hexadecimal representation of the bit value
+ # @parm String addr - hexadecimal representation of the bit address
+ # @return void
+proc create_help_window_byte {val} {
+ # Normalize cell value
+ set len [string length $val]
+ if {$len == 0} {
+ set val {00}
+ } elseif {$len == 1} {
+ set val "0$val"
+ }
+
+ ## Conver hexadecimal cell value to other representations
+ # Octal
+ set oct [NumSystem::hex2oct $val]
+ # Decimal
+ set dec [NumSystem::hex2dec $val]
+ # Character
+ if {$dec > 31 && $dec < 127} {
+ set char [subst "\\u00$val"]
+ } {
+ set char {}
+ }
+ # Binary
+ set bin [NumSystem::hex2bin $val]
+ set bin_len [string length $bin]
+ if {$bin_len < 8} {
+ set bin "[string repeat {0} [expr {8 - $bin_len}]]$bin"
+ }
+
+ ## Create table of cell values (GUI)
+ # Header "DEC"
+ grid [label ${::HELPWINDOW}.msg.dec_l \
+ -text {DEC} \
+ -font ${::smallfont} \
+ -fg ${::smallfont_color} \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ] -column 1 -row 1
+ # Header "HEX"
+ grid [label ${::HELPWINDOW}.msg.hex_l \
+ -text {HEX} \
+ -font ${::smallfont} \
+ -fg ${::smallfont_color} \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ] -column 2 -row 1
+ # Header "OCT"
+ grid [label ${::HELPWINDOW}.msg.oct_l \
+ -text {OCT} \
+ -font ${::smallfont} \
+ -fg ${::smallfont_color} \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ] -column 3 -row 1
+ # Values
+ grid [label ${::HELPWINDOW}.msg.dec_v -text $dec -pady 0 -bg {#FFFFFF}] -column 1 -row 2 ;# Decimal
+ grid [label ${::HELPWINDOW}.msg.hex_v -text $val -pady 0 -bg {#FFFFFF}] -column 2 -row 2 ;# Hexadecimal
+ grid [label ${::HELPWINDOW}.msg.oct_v -text $oct -pady 0 -bg {#FFFFFF}] -column 3 -row 2 ;# Octal
+ # Header "BIN"
+ grid [label ${::HELPWINDOW}.msg.bin_l \
+ -text {BIN} \
+ -font ${::smallfont} \
+ -fg ${::smallfont_color} \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ] -column 1 -row 3
+ # Header "CHAR"
+ grid [label ${::HELPWINDOW}.msg.char_l \
+ -text {CHAR} \
+ -font ${::smallfont} \
+ -fg ${::smallfont_color} \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ] -column 3 -row 3
+ # Values
+ grid [label ${::HELPWINDOW}.msg.bin_v -text $bin -pady 0 -bg {#FFFFFF}] -column 1 -row 4 -columnspan 2 ;# Binary
+ grid [label ${::HELPWINDOW}.msg.char_c -text $char -pady 0 -bg {#FFFFFF}] -column 3 -row 4 ;# Character
+}
+
+## Set the last created help window as window with variable address
+ # That means you can use procedure 'help_window_update_addr'
+ # @return void
+proc help_window_variable_addr {} {
+ global help_window_variable_address ;# Bool: Help window with variable address
+ set help_window_variable_address 1
+}
+
+## Update address in the help window
+ # @parm String old_addr - hexadecimal representation of old address
+ # @parm String new_addr - hexadecimal representation of new address
+ # @return Bool - result
+proc help_window_update_addr {old_addr new_addr} {
+ global help_window_variable_address ;# Bool: Help window with variable address
+
+ # Translate bit address in format ".AA" to "AA BIT"
+ if {[string index $old_addr 0] == {.}} {
+ set old_addr [string replace $old_addr 0 0]
+ append old_addr { BIT}
+ }
+ if {[string index $new_addr 0] == {.}} {
+ set addr [string replace $new_addr 0 0]
+ append addr { BIT}
+ }
+
+ # Check for address variability flag
+ if {!$help_window_variable_address} {return}
+
+ if {[catch {
+ # Check for existence of the help window
+ if {![winfo exists ${::HELPWINDOW}]} {
+ return 0
+ }
+
+ # Is the current help window that which should be affected ?
+ if {![string equal "0x$old_addr" [${::HELPWINDOW}.top.tit cget -text]]} {
+ return 0
+ }
+ }]} then {
+ return 0
+ }
+
+ # Change window title
+ ${::HELPWINDOW}.top.tit configure -text "0x$new_addr"
+ return 1
+}
+
+## Update values in the help window
+ # @parm String addr - hexadecimal representation of register address
+ # @parm String new_value - hexadecimal representation of the new value
+ # @return Bool - result
+proc help_window_update {addr new_value} {
+ global help_window_for_bit
+
+ # Translate bit address in format ".AA" to "AA BIT"
+ if {[string index $addr 0] == {.}} {
+ set addr [string replace $addr 0 0]
+ append addr { BIT}
+ }
+
+ # Handle empty input value
+ if {![string is xdigit -strict $new_value]} {
+ return 0
+ }
+
+ if {[catch {
+ # Check for existence of the help window
+ if {![winfo exists ${::HELPWINDOW}]} {
+ return 0
+ }
+
+ # Is the current help window that which should be affected ?
+ if {![string equal "0x$addr" [${::HELPWINDOW}.top.tit cget -text]]} {
+ return 0
+ }
+ }]} then {
+ return 0
+ }
+
+ if {$help_window_for_bit} {
+ help_window_update_bit [lindex $addr 0] $new_value
+ } {
+ help_window_update_byte $addr $new_value
+ }
+}
+
+## Update values in the help window for bit -- auxiliary procedure for help_window_update
+ # @parm String addr - hexadecimal representation of bit address
+ # @parm String new_value - hexadecimal representation of the new value
+ # @return Bool - result
+proc help_window_update_bit {addr new_value} {
+ global help_window_bit
+
+ # Adjust bit address to point to the firts bit in the register
+ set bit_addr [expr {"0x$addr"}]
+ set bit_addr [expr {$bit_addr - ($bit_addr % 8)}]
+
+ # Determinate value for each bit in the register
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate color
+ if {[${::X::actualProject} getBit $bit_addr]} {
+ set fill $::BitMap::one_fill
+ set outline $::BitMap::one_outline
+ } {
+ set fill $::BitMap::zero_fill
+ set outline $::BitMap::zero_outline
+ }
+
+ # Set color
+ ${::HELPWINDOW}.msg.c itemconfigure \
+ $help_window_bit($i) -fill $fill -outline $outline
+
+ # Shift to the next bit
+ incr bit_addr
+ }
+}
+
+## Update values in the help window for byte -- auxiliary procedure for help_window_update
+ # @parm String addr - hexadecimal representation of register address
+ # @parm String new_value - hexadecimal representation of the new value
+ # @return Bool - result
+proc help_window_update_byte {addr new_value} {
+ ## Conver hexadecimal cell value to other representations
+ # Octal
+ set oct [NumSystem::hex2oct $new_value]
+ # Decimal
+ set dec [NumSystem::hex2dec $new_value]
+ # Character
+ if {$dec > 31 && $dec < 127} {
+ set char [subst "\\u00$new_value"]
+ } {
+ set char {}
+ }
+ # Binary
+ set bin [NumSystem::hex2bin $new_value]
+ set bin_len [string length $bin]
+ if {$bin_len < 8} {
+ set bin "[string repeat {0} [expr {8 - $bin_len}]]$bin"
+ }
+
+ # Change values in label widgets
+ ${::HELPWINDOW}.msg.dec_v configure -text $dec
+ ${::HELPWINDOW}.msg.hex_v configure -text $new_value
+ ${::HELPWINDOW}.msg.oct_v configure -text $oct
+ ${::HELPWINDOW}.msg.bin_v configure -text $bin
+ ${::HELPWINDOW}.msg.char_c configure -text $char
+
+ # Done ...
+ return 1
+}
+
+## Unmap memory cell help window
+ # @return void
+proc help_window_hide {} {
+ catch {
+ place forget ${::HELPWINDOW}
+ }
+}
+
+## Show memory cell help window
+ # @parm Int X - absolute X coordinate
+ # @parm Int Y - absolute Y coordinate
+ # @return void
+proc help_window_show {X Y} {
+ global help_window_for_bit
+
+ if {${::HELPWINDOW} == {}} {
+ return
+ }
+ set X [expr $X]
+ set Y [expr $Y]
+
+ # Determinate main window geometry
+ set geometry [split [wm geometry ${::HELPWINDOW_ROOT}] {+}]
+ set limits [split [lindex $geometry 0] {x}]
+
+ # Adjust X and Y
+ set x_lim [lindex $limits 0]
+ set y_lim [lindex $limits 1]
+ set x_coord [expr {$X + 5 - [lindex $geometry 1]}]
+ set y_coord [expr {$Y + 5 - [lindex $geometry 2]}]
+
+ # Ensure than help window wont exceed boundaries of the main window
+ if {$help_window_for_bit} {
+ if {$x_coord > ($x_lim - 160)} {incr x_coord -170}
+ } {
+ if {$x_coord > ($x_lim - 100)} {incr x_coord -110}
+ }
+ if {$y_coord > ($y_lim - 100)} {incr y_coord -110}
+
+ # Show the window
+ catch {
+ place ${::HELPWINDOW} -anchor w -x $x_coord -y $y_coord
+ raise ${::HELPWINDOW}
+ }
+}
+
+
+# GENERAL PURPOSE PROCEDURES
+# -----------------------------
+
+##
+ #
+ # @return void
+proc create_progress_bar {window_path transient textvariable text variable maximum title iconphoto abort_text abort_command} {
+ toplevel $window_path
+ pack [label $window_path.image \
+ -image ::ICONS::32::user_away \
+ ] -side left -anchor n -padx 10 -pady 15
+ pack [frame $window_path.f] -side right -fill both
+ if {$textvariable != {}} {
+ pack [label $window_path.f.label \
+ -textvariable $textvariable \
+ ] -anchor w -padx 5 -pady 5
+ } {
+ pack [label $window_path.f.label \
+ -text $text \
+ ] -anchor w -padx 5 -pady 5
+ }
+ pack [ttk::progressbar $window_path.f.progressbar \
+ -mode determinate \
+ -length 330 \
+ -maximum $maximum \
+ -variable $variable \
+ ] -fill x -padx 5 -pady 5
+ if {$abort_command != {}} {
+ pack [ttk::button $window_path.f.button \
+ -compound left \
+ -image ::ICONS::16::cancel \
+ -text $abort_text \
+ -command $abort_command \
+ ] -padx 5 -pady 5 -anchor e
+ }
+
+ wm title $window_path $title
+ wm transient $window_path $transient
+ wm iconphoto $window_path $iconphoto
+ update
+ catch {
+ raise $window_path
+ }
+}
+
+## Translate encoding name to short description
+ # @return String - Encoding description
+proc enc2name {enc} {
+ switch -- $enc {
+ {utf-8} {return {Unicode}}
+ {iso8859-1} {return {Western European}}
+ {iso8859-2} {return {Central European}}
+ {iso8859-3} {return {Central European}}
+ {iso8859-4} {return {Baltic}}
+ {iso8859-5} {return {Cyrillic}}
+ {iso8859-6} {return {Arabic}}
+ {iso8859-7} {return {Greek}}
+ {iso8859-8} {return {Hebrew}}
+ {iso8859-9} {return {Turkish}}
+ {iso8859-10} {return {Northern European}}
+ {iso8859-13} {return {Baltic}}
+ {iso8859-14} {return {Western European}}
+ {iso8859-15} {return {Western European}}
+ {iso8859-16} {return {South-Eastern Europe}}
+ {cp1250} {return {Central European}}
+ {cp1251} {return {Cyrillic}}
+ {cp1252} {return {Western European}}
+ {cp1253} {return {Greek}}
+ {cp1254} {return {Turkish}}
+ {cp1255} {return {Hebrew}}
+ {cp1256} {return {Arabic}}
+ {cp1257} {return {Baltic}}
+ {cp1258} {return {Vietnamese}}
+ }
+}
+
+## Load global configuration
+ # @return void
+proc loadApplicationConfiguration {} {
+ # Load configuration file
+ if {$::CLI_OPTION(config_file) == {}} {
+ Settings settings ${::CONFIG_DIR} "config.conf"
+ } {
+ Settings settings \
+ [file dirname $::CLI_OPTION(config_file)] \
+ [file tail $::CLI_OPTION(config_file)]
+ }
+
+ # If configuration file is unavaliable -> invoke error message
+ if {![settings isReady]} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to save config file"]
+ }
+
+ # Reset settings to defaults
+ if {$::CLI_OPTION(reset_settings) || [settings isEmpty]} {
+ puts [mc " * Restoring default settings"]
+ # Insure that the current configuration is empty
+ settings clear
+
+ # Editor configuration
+ configDialogs::editor::getSettings
+ configDialogs::editor::save_config
+ # Right panel settings
+ configDialogs::rightPanel::getSettings
+ configDialogs::rightPanel::save_config
+ # Compiler configuration
+ configDialogs::compiler::getSettings
+ configDialogs::compiler::save_config
+ # Main tool bar
+ set ::ICONBAR_CURRENT ${::ICONBAR_DEFAULT}
+ configDialogs::toolbar::save_config
+ # Custom commands
+ configDialogs::custom_commands::save_config
+ # Shortcuts
+ configDialogs::shortcuts::load_config
+ configDialogs::shortcuts::getSettings
+ configDialogs::shortcuts::save_config
+ # Simulator configuration
+ configDialogs::simulator::getSettings
+ configDialogs::simulator::save_config
+ # Terminal emulator
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no terminal emulator on Windows
+ configDialogs::terminal::getSettings
+ configDialogs::terminal::save_config
+ }
+
+ # Load settings
+ } {
+ configDialogs::editor::load_config ;# Editor configuration
+ configDialogs::rightPanel::load_config ;# Right panel settings
+ configDialogs::compiler::load_config ;# Compiler configuration
+ configDialogs::toolbar::load_config ;# Main tool bar
+ configDialogs::custom_commands::load_config ;# Custom commands
+ configDialogs::shortcuts::load_config ;# Shortcuts
+ configDialogs::simulator::load_config ;# Simulator
+ if {!$::MICROSOFT_WINDOWS} { ;# There is no terminal emulator on Windows
+ configDialogs::terminal::load_config ;# Terminal emulator
+ }
+ }
+}
+
+## Neutralize selection in text widgets
+ # @parm Widget widget - target widget
+ # @return void
+proc false_selection {widget} {
+ if {${::false_selection_dis}} {return}
+ set ::false_selection_dis 1
+ catch {$widget tag remove sel 1.0 end}
+ set ::false_selection_dis 0
+}
+set false_selection_dis 0
+
+## Show/Hide tab on some panel
+ # @parm String what_to_do - ID of tab to activate
+ # @return void
+proc manipulate_panel {what_to_do} {
+ if {![llength ${X::openedProjects}] || ${X::actualProject} == {}} {
+ return
+ }
+ switch -- $what_to_do {
+ {sim} { ;# "Bottom / Simulator"
+ ${X::actualProject} bottomNB_show_up Simulator
+ }
+ {graph} { ;# "Bottom" / "Graph"
+ ${X::actualProject} bottomNB_show_up Graph
+ }
+ {mess} { ;# "Bottom / Messages"
+ ${X::actualProject} bottomNB_show_up Messages
+ }
+ {todo} { ;# "Bottom / Todo"
+ ${X::actualProject} bottomNB_show_up Todo
+ }
+ {calc} { ;# "Bottom / Calculator"
+ ${X::actualProject} bottomNB_show_up Calculator
+ }
+ {bsh} { ;# "Bottom / Show_Hide"
+ ${X::actualProject} bottomNB_show_hide
+ }
+
+ {book} { ;# "Right / Bookmarks"
+ ${X::actualProject} rightPanel_show_up Bookmarks
+ }
+ {brk} { ;# "Right / Breakpoints"
+ ${X::actualProject} rightPanel_show_up Breakpoints
+ }
+ {wtch} { ;# "Right / Watches"
+ ${X::actualProject} rightPanel_show_up Watches
+ }
+ {ins} { ;# "Right / Instruction details"
+ ${X::actualProject} rightPanel_show_up Instruction
+ }
+ {sub} { ;# "Right / Subprograms"
+ ${X::actualProject} rightPanel_show_up Subprograms
+ }
+ {rsh} { ;# "Right / Show_Hide"
+ ${X::actualProject} right_panel_show_hide
+ }
+
+ {lsh} { ;# "Left / Show_Hide"
+ ${X::actualProject} filelist_show_hide
+ }
+ {open} { ;# "Left / Opened files"
+ ${X::actualProject} filelist_show_up opened_files
+ }
+ {proj} { ;# "Left / Project files"
+ ${X::actualProject} filelist_show_up project_files
+ }
+ {fsb} { ;# "Left / Filesystem browser"
+ ${X::actualProject} filelist_show_up fs_browser
+ }
+ {sfr} { ;# "Left / Filesystem browser"
+ ${X::actualProject} filelist_show_up sfr_watches
+ }
+ }
+}
+
+##
+ # @parm List pattern - menu definition {
+ # {separator}
+ # {command label accelerator underline command image [statusTip]}
+ # {radiobutton label accelerator variable value command underline [statusTip]}
+ # {checkbutton label accelerator variable onvalue offvalue underline command [statusTip]}
+ # {cascade label underline image submenuID tearoff shortcuts pattern_list}
+ # }
+ # @parm String path - menu root
+ # @parm Bool tearoff - tearoff menu on/off (default: false)
+ # @return Bool - return code
+proc menuFactory {pattern path tearoff cmdPrefix shortcuts options} {
+
+ # Create menu widget
+ eval "menu $path -tearoff $tearoff $options"
+
+ # Iterate over menu definition list
+ foreach menuitem $pattern {
+ # Create array of options
+ for {set i 0} {$i < 9} {incr i} {
+ set menu($i) [lindex $menuitem $i]
+ }
+ # Determinate kind of operation
+ switch $menu(0) {
+ {command} {
+ # Item icon
+ if {$menu(5) != {}} {
+ set menu(5) "::ICONS::16::$menu(5)"
+ }
+
+ # Adjust accelerator value
+ set menu(2) [adjust_menu_accelerator $menu(2)]
+
+ # Create menu command
+ $path add command \
+ -label [mc $menu(1)] \
+ -accelerator $menu(2) \
+ -underline $menu(3) \
+ -command "$cmdPrefix$menu(4)" \
+ -image $menu(5) -compound left
+
+ # Status bar tip
+ if {$menu(6) != {}} {
+ set itemIndex [$path index end]
+ menu_Sbar_add $path $itemIndex [mc $menu(6)]
+ bind $path <<MenuSelect>> "menu_Sbar $path \[%W index active\]"
+ bind $path <Leave> {Sbar {}}
+ }
+ }
+ {separator} {$path add separator}
+ {radiobutton} {
+ # Adjust command
+ if {$menu(5) != {}} {
+ set menu(5) "${cmdPrefix}$menu(5)"
+ }
+
+ # Adjust accelerator value
+ set menu(2) [adjust_menu_accelerator $menu(2)]
+
+ # Create radio button item
+ $path add radiobutton \
+ -label [mc $menu(1)] \
+ -accelerator $menu(2) \
+ -variable $menu(3) \
+ -value $menu(4) \
+ -command $menu(5) \
+ -underline $menu(6) \
+ -compound left \
+ -indicatoron 0 \
+ -image ::ICONS::raoff \
+ -selectimage ::ICONS::raon \
+ -selectcolor {#EEEEEE}
+
+ # Status bar tip
+ if {$menu(7) != {}} {
+ set itemIndex [$path index end]
+ menu_Sbar_add $path $itemIndex [mc $menu(7)]
+ bind $path <<MenuSelect>> "menu_Sbar $path \[%W index active\]"
+ bind $path <Leave> {Sbar {}}
+ }
+ }
+ {checkbutton} {
+ # Adjust command
+ if {$menu(7) != {}} {
+ set menu(7) "${cmdPrefix}$menu(7)"
+ }
+ # Adjust accelerator value
+ set menu(2) [adjust_menu_accelerator $menu(2)]
+
+ # Create checkbutton item
+ $path add checkbutton \
+ -label [mc $menu(1)] \
+ -accelerator $menu(2) \
+ -variable $menu(3) \
+ -onvalue $menu(4) \
+ -offvalue $menu(5) \
+ -underline $menu(6) \
+ -command $menu(7) \
+ -compound left \
+ -image ::ICONS::choff \
+ -indicatoron 0 \
+ -selectimage ::ICONS::chon \
+ -selectcolor {#EEEEEE}
+ # Status bar tip
+ if {$menu(8) != {}} {
+ set itemIndex [$path index end]
+ menu_Sbar_add $path $itemIndex [mc $menu(8)]
+ bind $path <<MenuSelect>> "menu_Sbar $path \[%W index active\]"
+ bind $path <Leave> {Sbar {}}
+ }
+ }
+ {cascade} {
+ # Adjust menu name
+ set menu(4) "$path$menu(4)"
+ # Create new menu for cascade
+ if {$menu(7) != {}} {
+ menuFactory $menu(7) $menu(4) $menu(5) $cmdPrefix $menu(6) $options
+ }
+ # Item icon
+ if {$menu(3) != {}} {
+ set menu(3) "::ICONS::16::$menu(3)"
+ }
+ # Add cascade to this menu
+ $path add cascade -label [mc $menu(1)] -underline $menu(2) \
+ -image $menu(3) -menu $menu(4) -compound left
+ }
+ {} {return}
+ default {
+ error "Menu creation failed -- unknown type: $menu(0)"
+ return -code 1
+ }
+ }
+ }
+}
+
+## Disable or enable particular buttons in main menu
+ # @parm Bool EnaDis - 1: enable; 0: disable
+ # @parm List pattern - list of entries to affect, format:
+ # {
+ # {?path?
+ # {?Label_or_index? ...}
+ # }
+ # }
+ # @parm void
+proc ena_dis_menu_buttons {EnaDis pattern} {
+ # Determinate state
+ if {$EnaDis} {
+ set state normal
+ } {
+ set state disabled
+ }
+ # Set state
+ foreach option $pattern {
+ set path [lindex $option 0]
+ foreach entry [lindex $option 1] {
+ $path entryconfigure [::mc $entry] -state $state
+ }
+ }
+}
+
+## Enable or disable buttons on iconbar
+ # @parm Bool EnaDis - 1 == enable; 0 == disable
+ # @parm Widget pathPrefix - path prefix for buttons
+ # @parm List buttonList - list of buttons to affect
+ # @return void
+proc ena_dis_iconBar_buttons {EnaDis pathPrefix buttonList} {
+ # Determinate state
+ if {$EnaDis} {
+ set state normal
+ } {
+ set state disabled
+ }
+ # Set state
+ foreach button $buttonList {
+ catch {
+ $pathPrefix$button configure -state $state
+ }
+ }
+}
+
+## Create icon bar
+ # @parm String container - target container (some frame)
+ # @parm String pathPrefix - path prefix for buttons
+ # @parm String imageNS - namespace where the images references are located (eg. ::img::large::)
+ # @parm List pattern - icon bar pattern -- must look like this: {
+ # {?name? ?helptext? ?imageName? ?command? [?statusTip?]}
+ # {separator}
+ # }
+ # @return void
+set iconBarFactory_sep_index 0 ;# Separator index
+proc iconBarFactory {container cmdPrefix pathPrefix imageNS pattern} {
+ global iconBarFactory_sep_index ;# Separator index
+
+ # Parse pattern
+ foreach button $pattern {
+ # Create array of button parameters
+ for {set i 0} {$i < 4} {incr i} {
+ set parm($i) [lindex $button $i]
+ }
+
+ # Separator
+ if {$parm(0) == {separator}} {
+ pack [ttk::separator \
+ .${pathPrefix}iconBarSeparator$iconBarFactory_sep_index \
+ -orient vertical \
+ ] -in $container -side left -padx 2 -fill y -expand 1
+ incr iconBarFactory_sep_index
+
+ # Button
+ } else {
+ # Create button
+ set buttonWidget [ttk::button .$pathPrefix$parm(0) \
+ -command "$cmdPrefix$parm(3)" \
+ -image "$imageNS$parm(2)" \
+ -style ToolButton.TButton \
+ ]
+ DynamicHelp::add $buttonWidget -text $parm(1)
+ # Pack it
+ pack $buttonWidget -in $container -side left -padx 2
+ # Set status bar tip
+ if {[llength $button] == 5} {
+ setStatusTip -widget $buttonWidget -text [lindex $button 4]
+ }
+ }
+ }
+}
+
+## Show statusbar history
+ # @return void
+proc show_statusbar_history {} {
+ global status_bar_history ;# Sbar history
+
+ if {[winfo exists .status_bar_history_win]} {
+ grab release .status_bar_history_win
+ destroy .status_bar_history_win
+ return
+ }
+
+ set win [frame .status_bar_history_win \
+ -background {#000000} \
+ ]
+ set main_frame [frame $win.main_frame]
+
+ pack [text $main_frame.text \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ -bg white -cursor left_ptr \
+ -width 0 -height 0 -bd 0 \
+ ] -side left -fill both -expand 1
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -command "$main_frame.text yview" \
+ -orient vertical \
+ ] -side right -fill y -after $main_frame.text
+ foreach line $status_bar_history {
+ $main_frame.text insert end $line
+ $main_frame.text insert end "\n"
+ }
+ $main_frame.text configure -state disabled
+
+ pack $main_frame -fill both -expand 1 -padx 1 -pady 1
+ place $win \
+ -x [winfo rootx .statusbarL] \
+ -y [expr {[winfo rooty .statusbarL] - 250}] \
+ -width [expr {[winfo width .statusbarL] - 20}] \
+ -height 200
+ bind $win <Button> "
+ grab release .status_bar_history_win
+ destroy .status_bar_history_win
+ "
+ update
+ grab -global $win
+ focus $win
+}
+
+## Create status bar
+ # @parm String txt - initial text
+ # @return void
+proc makeStatusbar {txt} {
+ pack [frame .statusbarF -height 30p] -fill x -expand 0 -side bottom
+ pack [ttk::button .statusbarVB \
+ -style TButton \
+ -image ::ICONS::16::spellcheck \
+ -compound left \
+ -width 6 \
+ ] -in .statusbarF -side left
+ DynamicHelp::add .statusbarVB -text [mc "Change validation level"]
+ bind .statusbarVB <Button-3> {change_validation_level {down}; break}
+ bind .statusbarVB <Button-1> {change_validation_level {up}; break}
+
+ pack [ArrowButton .statusbarF.arr_but \
+ -dir top -clean 2 -bd 0 \
+ -helptext [mc "Show statusbar history"] \
+ -command {show_statusbar_history} \
+ -height 14 -width 14 -bg {#eeeeee} \
+ ] -side left -padx 7
+ setStatusTip -widget .statusbarF.arr_but -text [mc "Show statusbar history"]
+ pack [label .statusbarL -text $txt -anchor w -justify left] \
+ -in .statusbarF -side left -fill x -expand 1
+}
+set sbarAfterId {} ;# Sbar timer ID
+set status_bar_history {} ;# Sbar history
+
+## Change current validation lvel
+ # @parm String arg - on of {up down 0 1 2}
+ # 0 : Validation disabled
+ # 1 : Basic validation enabled
+ # 2 : Basic and advanced validtions enabled
+ # up : Move to upper validation level (for instance form 0 to 1)
+ # down : Move to lower validation level (for instance form 1 to 0)
+ # @return void
+proc change_validation_level {arg} {
+
+ # Parse parameter
+ if {$arg == {up}} {
+ if {$::CONFIG(VALIDATION_LEVEL) == 2} {return}
+ incr ::CONFIG(VALIDATION_LEVEL)
+
+ } elseif {$arg == {down}} {
+ if {!$::CONFIG(VALIDATION_LEVEL)} {return}
+ incr ::CONFIG(VALIDATION_LEVEL) -1
+
+ } elseif {$arg == 0 || $arg == 1 || $arg == 2} {
+ set ::CONFIG(VALIDATION_LEVEL) $arg
+
+ } else {
+ puts stderr "Invalid call 'change_validation_level {$arg}'"
+ return
+ }
+
+ ## Change content of button "Validation level" and SH-NS variables validation_L0 and validation_L1
+ if {!$::CONFIG(VALIDATION_LEVEL)} {
+ .statusbarVB configure -text {OFF}
+ .statusbarVB configure -style RedBg.TButton
+ setStatusTip -widget .statusbarVB -text [mc "Syntax validation disabled"]
+ if {$arg == {up} || $arg == {down}} {
+ Sbar -freeze [mc "Syntax validation disabled"]
+ }
+
+ set ::CsyntaxHighlight::validation_L0 0 ;# Bool: Basic validation enabled
+ set ::CsyntaxHighlight::validation_L1 0 ;# Bool: Basic validation enabled
+ set ::ASMsyntaxHighlight::validation_L0 0 ;# Bool: Basic validation enabled
+ set ::ASMsyntaxHighlight::validation_L1 0 ;# Bool: Advancet validation enabled
+ } {
+ .statusbarVB configure -text " $::CONFIG(VALIDATION_LEVEL)"
+ .statusbarVB configure -style TButton
+ setStatusTip -widget .statusbarVB -text [mc "Current validation level: %s" $::CONFIG(VALIDATION_LEVEL)]
+ if {$arg == {up} || $arg == {down}} {
+ Sbar -freeze [mc "Current validation level: %s" $::CONFIG(VALIDATION_LEVEL)]
+ }
+
+ set ::CsyntaxHighlight::validation_L0 1 ;# Bool: Basic validation enabled
+ set ::ASMsyntaxHighlight::validation_L0 1 ;# Bool: Basic validation enabled
+ if {$::CONFIG(VALIDATION_LEVEL) == 2} {
+ set ::ASMsyntaxHighlight::validation_L1 1 ;# Bool: Advancet validation enabled
+ set ::CsyntaxHighlight::validation_L1 1 ;# Bool: Basic validation enabled
+ } {
+ set ::ASMsyntaxHighlight::validation_L1 0 ;# Bool: Advancet validation enabled
+ set ::CsyntaxHighlight::validation_L1 0 ;# Bool: Basic validation enabled
+ }
+ }
+}
+
+## Show message on status bar
+ # @parm String arg0 - '-freeze' (OPTIONAL) - do not set timer to clear the message
+ # @parm String arg1 - text of message to display
+ # @return void
+proc Sbar args {
+ global sbarAfterId ;# ID of Sbar timer
+ global status_bar_history ;# Sbar history
+
+ # Local variables
+ set freeze 0 ;# Freeze timer
+ set argsLength [llength $args] ;# Number of arguments
+
+ # Check for allowed number of arguments
+ if {$argsLength > 2} {
+ error "Too many arguments."
+
+ } elseif {$argsLength == 0} {
+ error "Too few arguments"
+
+ }
+
+ # Handle optional argument '-freeze'
+ set idx [lsearch $args "-freeze"]
+ if {$idx != -1} {
+ if {$argsLength == 1} {
+ error "Expected text"
+ }
+ set freeze 1
+ set args [lreplace $args $idx $idx]
+
+ } elseif {$argsLength == 2} {
+ error "Invalid argument set"
+
+ }
+
+ # Show message text
+ set text [string trim $args {\{\}}]
+ .statusbarL configure -text $text
+ # Cancel previous timer
+ if {$sbarAfterId != {}} {
+ after cancel $sbarAfterId
+ }
+ # Set new timer
+ if {!$freeze} {
+ set sbarAfterId [after 5000 {.statusbarL configure -text {}}]
+ if {$text != {}} {
+ lappend status_bar_history $text
+ if {[llength $status_bar_history] > 25} {
+ set status_bar_history [lrange $status_bar_history end-25 end]
+ }
+ }
+ }
+}
+
+## Show message on status bar for simulator
+ # @parm String txt - Text of the message
+ # @parm Int mode - Message type
+ # 0 - Normal message
+ # 1 - Interrupt
+ # @return void
+proc simulator_Sbar {txt mode object} {
+ catch {destroy .simulator_Sbar}
+ if {![string length $txt]} {
+ return
+ }
+ pack [label .simulator_Sbar -text $txt -fg {#DD8800} -cursor hand1] -in .statusbarF -side right
+ if {$mode} {
+ bind .simulator_Sbar <Enter> {%W configure -fg {#0000DD}}
+ bind .simulator_Sbar <Leave> {%W configure -fg {#DD8800}}
+ }
+ set command {}
+ switch -- $mode {
+ 0 { ;# Normal message
+ }
+ 1 { ;# Interrupt
+ set command "::X::__interrupt_monitor $object"
+ }
+ }
+ bind .simulator_Sbar <Button-1> $command
+}
+
+# Variables related to status tips for notebook tabs
+set notebookSbar_IDs {} ;# List of registered NoteBooks (not widgets)
+array set notebookSbar_texts {} ;# Array of Lists of status tip texts ({tab_ID text tab_ID text ...})
+
+## Register NoteBook for dynamic help on statusbar
+ # @parm String notebook_ID - Any string which identifies the NoteBook
+ # @parm List status_tips - List of helptexts (format: {tab_ID text tab_ID text ...})
+ # @return void
+proc notebook_Sbar_set {notebook_ID status_tips} {
+ if {[lsearch $::notebookSbar_IDs $notebook_ID] != -1} {return}
+ lappend ::notebookSbar_IDs $notebook_ID
+ set ::notebookSbar_texts($notebook_ID) $status_tips
+}
+
+## Unregister NoteBook for dynamic help on statusbar
+ # @parm String notebook_ID - Any string which identifies the NoteBook
+ # (must be the same as used in notebook_Sbar_set)
+ # @return void
+proc notebook_Sbar_unset {notebook_ID} {
+ set idx [lsearch $::notebookSbar_IDs $notebook_ID]
+ if {$idx == -1} {return}
+ set ::notebookSbar_IDs [lreplace $::notebookSbar_IDs $idx $idx]
+ unset ::notebookSbar_texts($notebook_ID)
+}
+
+## Display dinamic help for NoteBook tab
+ # @parm String notebook_ID - Any string which identifies the NoteBook
+ # (must be the same as used in notebook_Sbar_set)
+ # @parm String tab_ID - Tab identifier (NB insert index tab_ID option ...)
+ # @return void
+proc notebook_Sbar {notebook_ID tab_ID} {
+ # Check for notebook regisration
+ set idx [lsearch $::notebookSbar_IDs $notebook_ID]
+ if {$idx == -1} {
+ Sbar {}
+ return
+ }
+
+ # Check for tab registration
+ set idx [lsearch $::notebookSbar_texts($notebook_ID) $tab_ID]
+ if {$idx == -1} {
+ Sbar {}
+ return
+ }
+
+ # Display the text
+ Sbar -freeze [lindex $::notebookSbar_texts($notebook_ID) [expr {$idx + 1}]]
+}
+
+# Variables realted to status bar tips for menus
+set menuSbar_menus {} ;# List of menus with registred status bar tips
+array set menuSbar_items {} ;# Registered menu items (menuSbar_items($menu_widget) == {item item ...})
+array set menuSbar_texts {} ;# Status tips (menuSbar_texts($menu_widget,$item) == text)
+
+## Set status bar tip for menu item
+ # @parm Widget menu - ID of the menu
+ # @parm Int item - Index of the item
+ # @parm String text - Help text
+ # @return void
+proc menu_Sbar_add {menu item text} {
+ # Register menu ID
+ if {[lsearch ${::menuSbar_menus} $menu] == -1} {
+ lappend ::menuSbar_menus $menu
+ set ::menuSbar_items($menu) {}
+ }
+ # Register menu item index
+ lappend ::menuSbar_items($menu) $item
+ # Set help text
+ set ::menuSbar_texts(${menu},${item}) $text
+}
+
+## Unset status bar tip for menu item
+ # @parm Widget menu - ID of the menu
+ # @return void
+proc menu_Sbar_remove {menu} {
+ # Determinate menu index
+ set idx [lsearch ${::menuSbar_menus} $menu]
+ if {$idx == -1} {
+ puts stderr "Unable to remove menu $menu from help db, menu does not exist"
+ }
+ # Discart help
+ set ::menuSbar_menus [lreplace ${::menuSbar_menus} $idx $idx]
+ catch {
+ foreach item $::menuSbar_items($menu) {
+ unset ::menuSbar_texts(${menu},${item})
+ }
+ }
+ catch {
+ unset ::menuSbar_items($menu)
+ }
+}
+
+## Show help text (on status bar) related to menu given item
+ # @parm Widget - Menu ID
+ # @parm Int item - Menu item index
+ # @return void
+proc menu_Sbar {menu item} {
+ if {[lsearch ${::menuSbar_menus} $menu] == -1} {
+ return
+ }
+ if {[lsearch $::menuSbar_items($menu) $item] != -1} {
+ Sbar -freeze $::menuSbar_texts(${menu},${item})
+ } {
+ Sbar {}
+ }
+}
+
+# Advanced geometry management variables
+set ::last_WIN_GEOMETRY_width 0 ;# Last width of the main window
+set ::last_WIN_GEOMETRY_height 0 ;# Last height of the main window
+
+## Refersh variables last_WIN_GEOMETRY_width and last_WIN_GEOMETRY_height
+ # @return void
+proc evaluate_new_window_geometry {} {
+ set geometry [split [wm geometry .] {+}]
+ set geometry [split [lindex $geometry 0] {x}]
+ set ::WIN_GEOMETRY_width [lindex $geometry 0]
+ set ::WIN_GEOMETRY_height [lindex $geometry 1]
+}
+
+# KEY SHORTCUTS
+# -----------------------------
+
+## Database of current key shortcuts
+ # Usage: $SHORTCUTS_DB(category:item) == key_sequence
+array set SHORTCUTS_DB {}
+
+## Shortcuts definition list
+ # Format: {
+ # {category_ID category_name hardcoded_shortcuts
+ # {item_ID} {key_sequence command icon item_name}
+ # ...
+ # }
+ # ...
+ # }
+set SHORTCUTS_LIST {
+ {main {Main} {}
+ {quit} {Control-Key-q ::X::__exit exit
+ {Exit program}}
+ {savesession} {{} ::X::save_session {}
+ {Save session}}
+ {statistics} {{} ::X::__statistics {}
+ {File statistics}}
+ {fullscreen} {{Control-Key-XF86_Switch_VT_11} ::X::__toggle_fullscreen window_fullscreen
+ {Toggle fullscreen mode}}
+ } {project {Project management} {}
+ {proj_new} {{} ::X::__proj_new filenew
+ {New project}}
+ {proj_open} {{} ::X::__proj_open project_open
+ {Open project}}
+ {proj_save} {{} ::X::__proj_save filesave
+ {Save project}}
+ {proj_edit} {{} ::X::__proj_edit configure
+ {Edit project}}
+ {proj_close} {{} ::X::__proj_close fileclose
+ {Save and close project}}
+ {proj_clsimm} {{} ::X::__proj_close_imm no
+ {Close project}}
+ } {sim {Simulator} {}
+ {initiate_sim} {{Key-F2} ::X::__initiate_sim launch
+ {Start simulator}}
+ {initiate_sim0} {{} {::X::__initiate_sim 1} launch_this
+ {Debug this file only}}
+ {sfrmap} {{} ::X::__sfr_map kcmmemory_S
+ {Show SFR map}}
+ {bitmap} {{} ::X::__bitmap kcmmemory_BA
+ {Bit addressable array}}
+ {show_code_mem} {{} ::X::__show_code_mem kcmmemory_C
+ {Show Code memory}}
+ {show_ext_mem} {{} ::X::__show_ext_mem kcmmemory_E
+ {Show XDATA memory}}
+ {show_exp_mem} {{} ::X::__show_exp_mem kcmmemory_E
+ {Show ERAM }}
+ {show_eeprom} {{} ::X::__show_eeprom kcmmemory_P
+ {Show Data EEPROM}}
+ {show_eem_wb} {{} ::X::__show_eeprom_write_buffer kcmmemory_B
+ {Show EEPROM write buffer}}
+ {stack_mon} {{} ::X::__stack_monitor kcmmemory_ST
+ {Invoke MCU stack monitor}}
+ {reset-} {{Key-F4} {::X::__reset -} rebuild
+ {Reset - Only SFR}}
+ {reset0} {{} {::X::__reset 0} rebuild
+ {Reset - All zeros}}
+ {reset1} {{} {::X::__reset 1} rebuild
+ {Reset - All ones}}
+ {resetr} {{} {::X::__reset r} rebuild
+ {Reset - Random}}
+ {step} {{Key-F7} ::X::__step goto
+ {Simulator: Step}}
+ {stepback} {{Alt-Key-F7} ::X::__stepback undo
+ {Simulator: Step Back}}
+ {stepover} {{Key-F8} ::X::__stepover goto
+ {Simulator: Step over}}
+ {animate} {{Key-F6} ::X::__animate 1rightarrow
+ {Simulator: Animate}}
+ {run} {{Key-F9} ::X::__run 2rightarrow
+ {Simulator: Run}}
+ {allow_BP} {{} ::X::__invert_allow_breakpoints {}
+ {Allow/Deny breakpoints}}
+ {clear_hg} {{} ::X::__sim_clear_highlight editclear
+ {Clear highlight}}
+ {find_cur} {{Key-F3} ::X::__see_sim_cursor forward
+ {Find cursor}}
+ {line2addr} {{Control-g} ::X::__simulator_set_PC_by_line 2_rightarrow
+ {Jump to line}}
+ {hiberante} {{} ::X::__hibernate bar5
+ {Simulator: Hibernate}}
+ {resume} {{} ::X::__resume resume
+ {Simulator: Resume}}
+ {intrmon} {{} ::X::__interrupt_monitor kcmdf
+ {Interrupt monitor}}
+ {stopwatch} {{} ::X::__stopwatch_timer player_time
+ {Stopwatch}}
+ } {virtual_hw {Virtual HW} {}
+ {ledpanel} {{} {::X::__vhw_LED_panel} ledpanel
+ {LED panel}}
+ {leddisplay} {{} {::X::__vhw_LED_display} leddisplay
+ {LED display}}
+ {ledmatrix} {{} {::X::__vhw_LED_matrix} ledmatrix
+ {LED matrix}}
+ {mleddisplay} {{} {::X::__vhw_M_LED_display} mleddisplay
+ {Multiplexed LED display}}
+ {simplekeypad} {{} {::X::__vhw_keys} simplekeypad
+ {Simple keypad}}
+ {matrixkeypad} {{} {::X::__vhw_matrix_keypad} matrixkeypad
+ {Matrix keypad}}
+ {vhw_open} {{} {::X::__open_VHW} fileopen
+ {Open}}
+ {vhw_load} {{} {::X::__load_VHW} fileimport
+ {Load}}
+ {vhw_save} {{} {::X::__save_VHW} filesave
+ {Save}}
+ {vhw_saveas} {{} {::X::__save_as_VHW} filesaveas
+ {Save as}}
+ {vhw_remove_all} {{} {::X::__remove_all_VHW} editdelete
+ {Remove all}}
+ } {tools {Tools} {}
+ {assemble} {{Key-F11} {::X::__compile 0} compfile
+ {Compile}}
+ {assemble0} {{} {::X::__compile 0 {} 1} compfile_this
+ {Compile this file only}}
+ {disasm} {{} ::X::__disasm disasm
+ {Disassemble}}
+ {auto_indent} {{} ::X::__reformat_code filter
+ {Auto indent}}
+ {change_case} {{} ::X::__change_letter_case change_case
+ {Change letter case}}
+ {cleanup} {{} ::X::__cleanup emptytrash
+ {Cleanup dialog}}
+ {toHTML} {{} ::X::__toHTML html
+ {Export as XHTML}}
+ {toLaTeX} {{} ::X::__toLaTeX tex
+ {Export as LaTeX}}
+ {doc_cur_f} {{Control-e} ::X::__document_current_func {}
+ {Document current function}}
+ {doxywizard} {{} ::X::__run_doxywizard {}
+ {Run doxywizard}}
+ {doxygen} {{} ::X::__generate_documentation {}
+ {Build C API documentation}}
+ {clr_doc} {{} ::X::__clear_documentation {}
+ {Clear C API documentation}}
+ {custom0} {{} {::X::__exec_custom_cmd 0} gear0
+ {Custom command 0}}
+ {custom1} {{} {::X::__exec_custom_cmd 1} gear1
+ {Custom command 1}}
+ {custom2} {{} {::X::__exec_custom_cmd 2} gear2
+ {Custom command 2}}
+ } {utilities {Utilities} {}
+ {hex2bin} {{} ::X::__hex2bin hb
+ {Hex -> Bin}}
+ {bin2hex} {{} ::X::__bin2hex bh
+ {Bin -> Hex}}
+ {sim2hex} {{} ::X::__sim2hex sh
+ {Sim -> Hex}}
+ {sim2bin} {{} ::X::__sim2bin sb
+ {Sim -> Bin}}
+ {normalize_hex} {{} ::X::__normalize_hex hh
+ {Normalize IHEX8}}
+ {hexeditor} {{} ::X::__hexeditor ascii
+ {Hex Editor}}
+ {symb_view} {{} ::X::__symb_view symbol
+ {Symbol table}}
+ {8seg} {{} ::X::__eightsegment 8seg
+ {8-segment editor}}
+ {ascii_c} {{} ::X::__ascii_chart math_matrix
+ {ASCII chart}}
+ {notes} {{} ::X::__notes pencil
+ {Scribble notepad}}
+ {bc} {{} ::X::__base_convertor kaboodleloop
+ {Base Convertor}}
+ {rs232} {{} ::X::__rs232debugger chardevice
+ {UART/RS232 Debugger}}
+ } {help {Help} {}
+ {about} {{} ::X::__about mcu8051ide
+ {About dialog}}
+ {welcome} {{} ::X::__welcome_dialog {}
+ {Welcome dialog}}
+ {tips} {{} ::X::__tip_of_the_day help
+ {Tip of the day}}
+ } {messages {Messages text} {Control-Key-c Control-Key-a}
+ {clear_mess} {{} {$this clear_messages_text} editdelete
+ {Clear messages}}
+ {mess_find} {Control-Key-f {$this messages_text_find_dialog} find
+ {Find}}
+ {mess_find_n} {Key-F3 {$this messages_text_find_next} down0
+ {Find next}}
+ {mess_find_p} {XF86_Switch_VT_3 {$this messages_text_find_prev} up0
+ {Find previous}}
+ } {todo {Notes} {
+ Control-Key-v Control-Key-x Control-Key-c
+ Control-Key-a Control-Key-z Control-Key-Z
+ }
+ {bold} {Control-Key-b {$this TodoProc_bold} text_bold
+ {Bold text}}
+ {italic} {Control-Key-i {$this TodoProc_italic} text_italic
+ {Italic text}}
+ {strike} {Control-Key-q {$this TodoProc_strike} text_strike
+ {Striketrought text}}
+ {under} {Control-Key-u {$this TodoProc_under} text_under
+ {Underline text}}
+ {edrase} {Control-Key-e {$this TodoProc_eraser} eraser
+ {Erase tags}}
+ {insert} {Control-Key-p {$this TodoProc_bookmark} ok
+ {Insert OK image}}
+ {todo_find} {Control-Key-f {$this TodoProc_find_dialog} find
+ {Find}}
+ {todo_find_n} {Key-F3 {$this TodoProc_find_next} down0
+ {Find next}}
+ {todo_find_p} {XF86_Switch_VT_3 {$this TodoProc_find_prev} up0
+ {Find previous}}
+ } {watches {Register watches} {
+ Control-Key-v Control-Key-x Control-Key-c Control-Key-a
+ }
+ {top} {{} {$this rightPanel_watch_move_top} top
+ {Move to top}}
+ {up} {{Alt-Key-Up} {$this rightPanel_watch_move_up} 1uparrow
+ {Move up}}
+ {down} {{Alt-Key-Down} {$this rightPanel_watch_move_down} 1downarrow
+ {Move down}}
+ {bottom} {{} {$this rightPanel_watch_move_bottom} bottom
+ {Move to bottom}}
+ {remove} {{Control-Delete} {$this rightPanel_watch_remove} button_cancel
+ {Remove}}
+ {remove_all} {{} {$this rightPanel_watch_clear} editdelete
+ {Remove all}}
+ } {edit {Editor} {
+ Control-Key-Next Control-Key-Prior Control-Shift-Key-Right
+ Control-Key-Right Control-Key-Left Control-Shift-Key-Left
+ Control-Key-Down Control-Key-Up}
+ {readonly} {{} ::X::switch_editor_RO_MODE {}
+ {Read only mode}}
+ {new} {Control-Key-n ::X::__new filenew
+ {New}}
+ {open} {Control-Key-o ::X::__open fileopen
+ {Open}}
+ {save} {Control-Key-s ::X::__save filesave
+ {Save}}
+ {save_as} {Control-Key-S ::X::__save_as filesaveas
+ {Save as}}
+ {save_all} {Control-Key-l ::X::__save_all save_all
+ {Save all}}
+ {close} {Control-Key-w ::X::__close fileclose
+ {Close}}
+ {close_all} {{} ::X::__close_all cancel
+ {Close all}}
+ {icon_border} {{} ::X::__show_hine_IconB view_choose
+ {Show/Hide icon border}}
+ {line_numbers} {{} ::X::__show_hine_LineN view_choose
+ {Show/Hide line numbers}}
+ {reload} {Key-F5 ::X::__reload reload
+ {Reload}}
+ {next} {Alt-Key-Right ::X::__next_editor 1rightarrow
+ {Next editor}}
+ {prev} {Alt-Key-Left ::X::__prev_editor 1leftarrow
+ {Previous editor}}
+ {breakpoint} {Control-Key-B {$this Breakpoint} flag
+ {Breakpoint}}
+ {bookmark} {Control-Key-b {$this Bookmark} bookmark
+ {Bookmark}}
+ {undo} {Control-Key-z ::X::__undo undo
+ {Undo}}
+ {redo} {Control-Key-Z ::X::__redo redo
+ {Redo}}
+ {copy} {Control-Key-c ::X::__copy editcopy
+ {Copy}}
+ {cut} {Control-Key-x ::X::__cut editcut
+ {Cut}}
+ {paste} {Control-Key-v ::X::__paste editpaste
+ {Paste}}
+ {select_all} {Control-Key-a ::X::__select_all {}
+ {Select all}}
+ {find} {Control-Key-f ::X::__find find
+ {Find}}
+ {find_next} {Key-F3 ::X::__find_next 1downarrow
+ {Find next}}
+ {find_prev} {XF86_Switch_VT_3 ::X::__find_prev 1uparrow
+ {Find previous}}
+ {replace} {Control-Key-r ::X::__replace {}
+ {Replace}}
+ {goto} {Control-Key-g ::X::__goto goto
+ {Go to line}}
+ {comment} {Control-Key-d ::X::__comment {}
+ {Comment}}
+ {uncomment} {Control-Key-D ::X::__uncomment {}
+ {Uncomment}}
+ {indent} {Control-Key-i ::X::__indent indent
+ {Indent}}
+ {unindent} {Control-Key-I ::X::__unindent unindent
+ {Unindent}}
+ {uppercase} {Control-Key-u {$this uppercase} up0
+ {Uppercase}}
+ {lowercase} {Control-Key-U {$this lowercase} down0
+ {Lowercase}}
+ {capitalize} {Control-Alt-u {$this capitalize} {}
+ {Capitalize}}
+ {next_bookmark} {Alt-Key-Next {$this goto_next_bookmark} {}
+ {Go to next bookmark}}
+ {prev_bookmark} {Alt-Key-Prior {$this goto_prev_bookmark} {}
+ {Go to previous bookmark}}
+ {jmp} {{} {$this ljmp_this_line} {exec}
+ {Program jump}}
+ {call} {{} {$this lcall_this_line} {exec}
+ {Call subprogram}}
+ {cmd_line} {Key-F10 {} {}
+ {Editor command line}}
+ {split_v} {Control-L ::X::__split_vertical view_left_right
+ {Split vertical}}
+ {split_h} {Control-T ::X::__split_horizontal view_top_bottom
+ {Split horizontal}}
+ {close_cv} {Control-R ::X::__close_current_view view_remove
+ {Close current view}}
+ {block_sel} {Control-Alt-b ::X::__block_selection_mode {}
+ {Block selection mode}}
+ }
+}
+
+## Traslate menu accelerator string to human readable key sequence
+ # @parm String value - string to translate (for instance: $main:quit)
+ # @return String - resulting key sequence or empty string
+proc adjust_menu_accelerator {value} {
+ # Check if input value is variable
+ if {[string index $value 0] != {$}} {
+ return $value
+ }
+
+ # Adjust input value and search shortcuts database
+ set value [string replace $value 0 0]
+ if {![llength [array names ::SHORTCUTS_DB -exact $value]]} {
+ return {}
+ }
+
+ # Get new value from shortcuts database
+ set value $::SHORTCUTS_DB($value)
+ if {$value == {}} {
+ return {}
+ }
+
+ # Convert value to human readable string
+ return [simplify_key_seq $value]
+}
+
+## Translate Tk key sequence string to something like human readable string
+ # @parm String value - string to translate
+ # @return String - result
+proc simplify_key_seq {value} {
+ if {$value == {}} {
+ return {}
+ }
+
+ # Adjust the given string
+ set lastchar [string index $value end]
+ if {[string index $value end-1] == {-}} {
+ if {[string is lower -strict $lastchar]} {
+ set value [string replace $value \
+ end end [string toupper $lastchar]]
+ } elseif {[string is upper -strict $lastchar]} {
+ set value [string replace $value end end \
+ "Shift-[string toupper $lastchar]"]
+ }
+ }
+ regsub {((Key)|(KeyPress)|(KeyRelease))\-} $value {} value
+ regsub -all {\-} $value {+} value
+ regsub {Control} $value {Ctrl} value
+
+ # Translate special strings
+ regsub -all {XF86_Switch_VT_} $value {Shift+F} value
+ regsub -all {ISO_Left_Tab$} $value {Shift+Tab} value
+
+ # Return result
+ return $value
+}
+
+## Shortcut configuration related to main window
+ # Key shortcut categories related to this segment
+set SHORTCUT_CATEGORIES {main project sim tools help}
+ # Unredefinable key sequences
+set HARDCODED_SHORTCUTS {
+ Control-Key-1 Control-Key-2 Control-Key-3 Control-Key-4 Control-Key-5
+ Control-Key-6 Control-Key-7 Control-Key-8 Control-Key-9 Control-Key-0
+}
+ # Currently set bindigs
+set SET_SHORTCUTS {}
+
+## Create bindings for defined key shortcuts
+ # @return void
+proc shortcuts_reevaluate {} {
+ # Unset previous configuration
+ foreach key ${::SET_SHORTCUTS} {
+ bind . <$key> {}
+ }
+ set ::SET_SHORTCUTS {}
+
+ # Iterate over shortcuts definition
+ foreach block ${::SHORTCUTS_LIST} {
+ # Determinate category
+ set category [lindex $block 0]
+ if {[lsearch ${::SHORTCUT_CATEGORIES} $category] == -1} {continue}
+
+ # Determinate definition list and its length
+ set block [lreplace $block 0 2]
+ set len [llength $block]
+
+ # Iterate over definition list and create bindings
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ # Determinate key sequence
+ set key [lindex $block $i]
+ if {[catch {
+ set key $::SHORTCUTS_DB($category:$key)
+ }]} then {
+ continue
+ }
+ if {$key == {}} {continue}
+
+ # Create and register new binding
+ lappend ::SET_SHORTCUTS $key
+ set cmd [lindex $block [list $j 1]]
+ append cmd {;break}
+ bind . <$key> $cmd
+ }
+ }
+}
+
+
+# CREATE MAIN MENU BAR
+# -----------------------------
+
+# Definition of main menu bar
+set MAINMENU {
+ {cascade "File" 0 "" .file false 1 {
+ {command "New" "$edit:new" 0 {X::__new}
+ "filenew" "Create new file"}
+ {separator}
+ {command "Open" "$edit:open" 0 {X::__open}
+ "fileopen" "Open an existing file"}
+ {cascade "Open recent" 5 "fileopen" .open_recent false 1 {
+ }}
+ {separator}
+ {command "Save" "$edit:save" 0 {X::__save}
+ "filesave" "Save the current file"}
+ {command "Save as" "$edit:save_as" 1 {X::__save_as}
+ "filesaveas" "Save under a different name"}
+ {command "Save all" "$edit:save_all" 2 {X::__save_all}
+ "save_all" "Save the current file under a different name"}
+ {separator}
+ {command "Close" "$edit:close" 0 {X::__close}
+ "fileclose" "Close the current file"}
+ {command "Close all" "$edit:close_all" 1 {X::__close_all}
+ "cancel" "Close all opened files"}
+ {separator}
+ {command "File statistics" "$main:statistics" 0 {X::__statistics}
+ "" "Display file statistics"}
+ {separator}
+ {command "Save session" "$main:savesession" 3 {X::save_session}
+ "" "Save current session. Session file contains list of opened project, sizes of panels, etc."}
+ {separator}
+ {command "Quit" "$main:quit" 0 {X::__exit}
+ "exit" "Exit program"}
+ }}
+ {cascade "Edit" 0 "" .edit false 0 {
+ {command "Undo" "$edit:undo" 0 {X::__undo} "undo"
+ "Take back last operation"}
+ {command "Redo" "$edit:redo" 2 {X::__redo} "redo"
+ "Take back last undo"}
+ {separator}
+ {command "Cut" "$edit:cut" 2 {X::__cut} "editcut"
+ "Move selected text into the clipboard"}
+ {command "Copy" "$edit:copy" 0 {X::__copy} "editcopy"
+ "Copy selected text into the clipboard"}
+ {command "Paste" "$edit:paste" 0 {X::__paste} "editpaste"
+ "Paste text from clipboard"}
+ {separator}
+ {command "Select all" "$edit:select_all" 7 {X::__select_all} ""
+ "Select all text in the editor"}
+ {separator}
+ {command "Find" "$edit:find" 0 {X::__find} "find"
+ "Find a string in the text"}
+ {command "Find next" "$edit:find_next" 5 {X::__find_next} "1downarrow"
+ "Find next occurence of search string"}
+ {command "Find previous" "$edit:find_prev" 10 {X::__find_prev} "1uparrow"
+ "Find previous occurence of search string"}
+ {separator}
+ {command "Replace" "$edit:replace" 0 {X::__replace} ""
+ "Replace some string with another"}
+ {separator}
+ {command "Go to line" "$edit:goto" 0 {X::__goto} "goto"
+ "Jump to line"}
+ {separator}
+ {command "Comment" "$edit:comment" 2 {X::__comment} ""
+ "Comment selected text"}
+ {command "Uncomment" "$edit:uncomment" 6 {X::__uncomment} ""
+ "Uncomment selected text"}
+ {separator}
+ {command "Indent" "$edit:indent" 0 {X::__indent} "indent"
+ "Indent selected text"}
+ {command "Unindent" "$edit:unindent" 6 {X::__unindent} "unindent"
+ "Unindent selected text"}
+ }}
+ {cascade "View" 0 "" .display false 1 {
+ {checkbutton "Read only mode" "$sim:readonly" {::editor_RO_MODE} 1 0 5
+ {::X::switch_editor_RO_MODE}
+ "Set current editor to readonly/normal mode"}
+ {command "Switch to command line" "$edit:cmd_line" 7 {X::__switch_to_cmd_line}
+ "" "Switch to editor command line"}
+ {separator}
+ {command "Show/Hide icon border" "$edit:icon_border" 10 {X::__show_hine_IconB}
+ "view_choose" "Show/Hide editor's icon border (bookmark icons)"}
+ {command "Show/Hide line numbers" "$edit:line_numbers" 10 {X::__show_hine_LineN}
+ "view_choose" "Show/Hide editor's line numbers"}
+ {command "Reload" "$edit:reload" 0 {X::__reload}
+ "reload" "Reload current file"}
+ {cascade "Highlight" 0 "" .highlight false 1 {
+ {radiobutton "None" {} ::editor_SH -1
+ ::X::highlight_pattern_changed 0
+ ""}
+ {radiobutton "Assembly language" {} ::editor_SH 0
+ ::X::highlight_pattern_changed 0
+ ""}
+ {radiobutton "Assembler ASX8051" {} ::editor_SH 3
+ ::X::highlight_pattern_changed 12
+ "Reallocable assembler from SDCC project"}
+ {radiobutton "C language" {} ::editor_SH 1
+ ::X::highlight_pattern_changed 0
+ ""}
+ {radiobutton "Code listing" {} ::editor_SH 2
+ ::X::highlight_pattern_changed 5
+ ""}
+ }}
+ {separator}
+ {command "Fullscreen mode" "$main:fullscreen" 0 {X::__toggle_fullscreen}
+ "window_fullscreen" "Toggle fullscreen mode"}
+ {separator}
+ {command "Clear messages panel" "$messages:clear_mess" 0 {X::__clear_messages_text}
+ "editdelete" "Clear messages panel"}
+ }}
+ {cascade "Project" 0 "" .project false 0 {
+ {command "New" "$project:proj_new" 0 {X::__proj_new}
+ "filenew" "Create new project"}
+ {separator}
+ {command "Open" "$project:proj_open" 0 {X::__proj_open}
+ "project_open" "Open an existing project"}
+ {cascade "Open recent" 5 "project_open" .open_recent false 1 {
+ }}
+ {separator}
+ {command "Save" "$project:proj_save" 0 {X::__proj_save}
+ "filesave" "Save the current project"}
+ {separator}
+ {command "Edit project" "$project:proj_edit" 0 {X::__proj_edit}
+ "configure" "Edit project details"}
+ {separator}
+ {command "Save and close" "$project:proj_close" 1 {X::__proj_close}
+ "fileclose" "Save the current project and close it"}
+ {command "Close without saving" "$project:proj_clsimm" 0 {X::__proj_close_imm}
+ "no" "Close current project"}
+ }}
+ {cascade "Simulator" 0 "" .simulator false 1 {
+ {command "Start / Shutdown" "$sim:initiate_sim" 0 {X::__initiate_sim}
+ "launch" "Start simulator engine"}
+ {command "Debug this file only" "$sim:initiate_sim0" 6 {X::__initiate_sim 1}
+ "launch_this" "Start simulator engine and load current file only"}
+ {separator}
+ {command "Step back" "$sim:stepback" 5 {X::__stepback}
+ "undo" "Step program back by 1 inctruction"}
+ {command "Step" "$sim:step" 3 {X::__step}
+ "goto" "Step program by 1 inctruction"}
+ {command "Step over" "$sim:stepover" 5 {X::__stepover}
+ "goto2" "Step program by 1 line of code"}
+ {command "Animate" "$sim:animate" 0 {X::__animate}
+ "1rightarrow" "Run program and show results after each change"}
+ {command "Run" "$sim:run" 2 {X::__run}
+ "2rightarrow" "Run program and show results periodicaly in some interval"}
+ {separator}
+ {command "Hiberante program" "$sim:hiberante" 0 {X::__hibernate}
+ "bar5" "Save current state of simulator engine to a file for future resumption"}
+ {command "Resume hibernated program" "$sim:resume" 4 {X::__resume}
+ "resume" "Resume hibernated program"}
+ {separator}
+ {command "Interrupt monitor" "$sim:intrmon" 6 {X::__interrupt_monitor}
+ "kcmdf" "Dialog in which you can controll MCU interrupts"}
+ {command "Stopwatch" "$sim:stopwatch" 4 {X::__stopwatch_timer}
+ "player_time" "Configurable stopwatch timer which can stop simulation on various conditions"}
+ {separator}
+ {command "Find cursor" "$sim:find_cur" 0 {X::__see_sim_cursor}
+ "forward" "Find simulator cursor in the editor"}
+ {command "Jump to line" "$sim:line2addr" 0 {X::__simulator_set_PC_by_line}
+ "2_rightarrow" "Translate line number to address in program memory and set PC to that address"}
+ {command "Clear highlight" "$sim:clear_hg" 7 {X::__sim_clear_highlight}
+ "editclear" "Clear highlight for changed values"}
+ {checkbutton "Allow breakpoints" "$sim:allow_BP" {::CONFIG(BREAKPOINTS_ALLOWED)} 1 0 1 {}
+ "Enable simulator breakpoints (marks, where to stop program in animate or run mode)"}
+ }}
+ {cascade "Virtual MCU" 8 "" .virtual_mcu false 1 {
+ {command "Show SFR map" "$sim:sfrmap" 5 {X::__sfr_map}
+ "kcmmemory_S" "Show map of special function registers area"}
+ {command "Show bit area" "$sim:bitmap" 5 {X::__bitmap}
+ "kcmmemory_BA" "Show bit addressable area"}
+ {command "Show stack" "$sim:stack" 5 {X::__stack_monitor}
+ "kcmmemory_ST" "Invoke MCU stack monitor"}
+ {command "Show Code memory" "$sim:show_code_mem" 5 {X::__show_code_mem}
+ "kcmmemory_C" "Invoke hex editor with program code"}
+ {command "Show XDATA memory" "$sim:show_ext_mem" 5 {X::__show_ext_mem}
+ "kcmmemory_X" "Invoke hex editor with external data memory"}
+ {command "Show ERAM" "$sim:show_exp_mem" 5 {X::__show_exp_mem}
+ "kcmmemory_E" "Invoke hex editor with expanded RAM"}
+ {command "Show Data EEPROM" "$sim:show_eeprom" 5 {X::__show_eeprom}
+ "kcmmemory_P" "Invoke hex editor with data EEPROM"}
+ {command "Show EEPROM write buffer" "$sim:show_eem_wb" 14 {X::__show_eeprom_write_buffer}
+ "kcmmemory_B" "Invoke hexeditor editor with data EEPROM write buffer"}
+ {separator}
+ {cascade "Reset" 0 "rebuild" .virtual_mcu_reset false 1 {
+ {command "Only SFR" "$sim:reset-" 0 {X::__reset -}
+ "rebuild" "Reset Special Function Registers only"}
+ {command "All zeros" "$sim:reset0" 0 {X::__reset 0}
+ "rebuild" "Reset all internal registers to zeroes"}
+ {command "All ones" "$sim:reset1" 1 {X::__reset 1}
+ "rebuild" "Reset all internal registers to ones (0xFF)"}
+ {command "Random values" "$sim:resete" 0 {X::__reset r}
+ "rebuild" "Reset all internal registers to random values"}
+ }}
+ }}
+ {cascade "Virtual HW" 8 "" .virtual_hw false 1 {
+ {command "LED panel" "$virtual_hw:ledpanel" 2 {X::__vhw_LED_panel}
+ "ledpanel" ""}
+ {command "LED display" "$virtual_hw:leddisplay" 10 {X::__vhw_LED_display}
+ "leddisplay" ""}
+ {command "LED matrix" "$virtual_hw:ledmatrix" 4 {X::__vhw_LED_matrix}
+ "ledmatrix" ""}
+ {command "Multiplexed LED display" "$virtual_hw:mleddisplay" 1 {X::__vhw_M_LED_display}
+ "mleddisplay" ""}
+ {command "Simple keypad" "$virtual_hw:simplekeypad" 1 {X::__vhw_keys}
+ "simplekeypad" ""}
+ {command "Matrix keypad" "$virtual_hw:matrixkeypad" 7 {X::__vhw_matrix_keypad}
+ "matrixkeypad" ""}
+ {separator}
+ {command "Open" "$virtual_hw:vhw_open" 0 {X::__open_VHW}
+ "fileopen" "Load VHW connections from a file"}
+ {cascade "Open recent" 1 "fileopen" .open_recent false 1 {
+ }}
+ {separator}
+ {command "Load" "$virtual_hw:vhw_load" 0 {X::__load_VHW}
+ "fileimport" "Import VHW connections from a file"}
+ {cascade "Load recent" 9 "fileimport" .load_recent false 1 {
+ }}
+ {separator}
+ {command "Save" "$virtual_hw:vhw_save" 0 {X::__save_VHW}
+ "filesave" "Save current VHW connections to a file"}
+ {command "Save as" "$virtual_hw:vhw_saveas" 1 {X::__save_as_VHW}
+ "filesaveas" "Save current VHW connections under a different name"}
+
+ {separator}
+ {command "Remove all" "$virtual_hw:vhw_remove_all" 0 {X::__remove_all_VHW}
+ "editdelete" "Remove all VHW"}
+ }}
+ {cascade "Tools" 0 "" .tools false 1 {
+ {command "Compile" "$tools:assemble" 0 {X::__compile 0}
+ "compfile" "Compile the source code"}
+ {command "Compile this file" "$tools:assemble0" 10 {X::__compile 0 {} 1}
+ "compfile_this" "Compile current file only"}
+ {command "Disassemble" "$tools:disasm" 0 {X::__disasm}
+ "disasm" "Disassemble object code and open new editor with the result"}
+ {separator}
+ {cascade "Encoding" 1 "" .encoding false 1 {
+ }}
+ {cascade "End of line" 4 "" .eol false 1 {
+ {radiobutton "Unix" "LF" {::editor_EOL} {lf} {::X::change_EOL} 0}
+ {radiobutton "DOS" "CRLF" {::editor_EOL} {crlf} {::X::change_EOL} 0}
+ {radiobutton "Macintosh" "CR" {::editor_EOL} {cr} {::X::change_EOL} 0}
+ }}
+ {separator}
+ {command "Auto indent" "$tools:auto_indent" 1 {X::__reformat_code}
+ "filter" "Reformat source code (Indention level etc.)"}
+ {command "Change letter case" "$tools:change_case" 7 {X::__change_letter_case}
+ "change_case" "Change letter case in source code (with options)"}
+ {separator}
+ {command "Export as XHTML" "$tools:toHTML" 0 {X::__toHTML}
+ "html" "Export highlighted code as XHTML file"}
+ {command "Export as LaTeX" "$tools:toLaTeX" 1 {X::__toLaTeX}
+ "tex" "Export highlighted code as LaTeX source, using package color"}
+ {separator}
+ {command "Document current function" "$tools:doc_cur_f" 4 {X::__document_current_func}
+ "" "Create doxygen documentation for function on current line"}
+ {command "Run doxywizard" "$tools:doxywizard" 7 {X::__run_doxywizard}
+ "" "Run doxygen frondend"}
+ {command "Clear C API documentation" "$tools:clr_doc" 8 {X::__clear_documentation}
+ "" "Remove C API documentation created by doxygen"}
+ {command "Build C API documentation" "$tools:doxygen" 9 {X::__generate_documentation}
+ "" "Run doxygen to create C API documentation"}
+ {separator}
+ {command "Clean up project folder" "$tools:cleanup" 17 {X::__cleanup}
+ "emptytrash" "Invoke dialog to remove needless files the project directory"}
+ {separator}
+ {command "Custom command 0" "$tools:custom0" 15 {X::__exec_custom_cmd 0}
+ "gear0" ""}
+ {command "Custom command 1" "$tools:custom1" 15 {X::__exec_custom_cmd 1}
+ "gear1" ""}
+ {command "Custom command 2" "$tools:custom2" 15 {X::__exec_custom_cmd 2}
+ "gear2" ""}
+ }}
+ {cascade "Utilities" 0 "" .utilities false 0 {
+ {command "Hex -> Bin" "$utilities:hex2bin" 0 {X::__hex2bin}
+ "hb" "Convert Intel HEX 8 file to binary file"}
+ {command "Bin -> Hex" "$utilities:bin2hex" 0 {X::__bin2hex}
+ "bh" "Convert binary file to Intel HEX 8 file"}
+ {command "Sim -> Hex" "$utilities:sim2hex" 0 {X::__sim2hex}
+ "sh" "Convert simulator file to Intel HEX 8 file"}
+ {command "Sim -> Bin" "$utilities:sim2bin" 1 {X::__sim2bin}
+ "sb" "Convert simulator file to binary file"}
+ {command "Normalize Intel 8 hex file" "$utilities:normalize_hex" 0 {X::__normalize_hex}
+ "hh" "Reformat the given IHEX8"}
+ {separator}
+ {command "Hex editor" "$utilities:hexeditor" 1 {X::__hexeditor}
+ "ascii" "Invoke project independent hexadecimal editor with capacity of 64KB"}
+ {command "Symbol table" "$utilities:symb_view" 7 {X::__symb_view}
+ "symbol" "Assembly language symbol table viewer"}
+ {command "8-segment editor" "$utilities:8seg" 4 {X::__eightsegment}
+ "8seg" "8-segment LED display editor"}
+ {command "ASCII chart" "$utilities:ascii_c" 0 {X::__ascii_chart}
+ "math_matrix" "ASCII chart"}
+ {separator}
+ {command "Scribble notepad" "$utilities:notes" 10 {X::__notes}
+ "pencil" ""}
+ {command "Base convertor" "$utilities:bc" 5 {X::__base_convertor}
+ "kaboodleloop" ""}
+ {command "Special calculator" "" 1 {X::__spec_calc}
+ "xcalc" ""}
+ {separator}
+ {command "UART/RS232 Debugger" "$utilities:rs232" 2 {X::__rs232debugger}
+ "chardevice" ""}
+ }}
+ {cascade "Configure" 0 "" .configure false 0 {
+ {command "Configure Editor" "" 0 {::configDialogs::editor::mkDialog}
+ "configure"
+ "Editor configuration (colors, fonts, highlighting, etc.)"}
+ {command "Configure Compiler" "" 1 {::configDialogs::compiler::mkDialog}
+ "configure"
+ "Various compilation options"}
+ {command "Configure Simulator" "" 12 {::configDialogs::simulator::mkDialog}
+ "configure"
+ "Opens simulator configuration dialog"}
+ {command "Configure Right Panel" "" 2 {::configDialogs::rightPanel::mkDialog}
+ "configure"
+ "Right panel configration (instruction details colors)"}
+ {command "Configure Main Toolbar" "" 3 {::configDialogs::toolbar::mkDialog}
+ "configure_toolbars"
+ "Adjust content of the main toolbar (under main menu)"}
+ {command "Edit custom commands" "" 3 {::configDialogs::custom_commands::mkDialog}
+ "configure"
+ "Set or modify user defined commads"}
+ {command "Configure shortcuts" "" 10 {::configDialogs::shortcuts::mkDialog}
+ "configure_shortcuts"
+ "Set or modify key shortcuts"}
+ {command "Configure terminal emulator" "" 12 {::configDialogs::terminal::mkDialog}
+ "terminal"
+ "Configure embedded terminal emulator -- RXVT-UNICODE"}
+ {command "Configure MCU 8051 IDE" "" 4 {::configDialogs::global::mkDialog}
+ "mcu8051ide"
+ "Invoke global configuration dialog"}
+ }}
+ {cascade "Help" 0 "" .help false 1 {
+ {command "About" "$help:about" 0 {X::__about}
+ "kcmmemory" "About MCU 8051 IDE"}
+ {command "Welcome dialog" "$help:welcome" 0 {X::__welcome_dialog}
+ "" "Invoke dialog which you have seen on the first start"}
+ {command "Tip of the day" "$help:tips" 0 {X::__tip_of_the_day}
+ "" "Some tips about how to use this program more efficiently"}
+ }}
+}
+# This belongs to the "Virtual MCU"
+# {separator}
+# {cascade "Functional diagrams" 0 "blockdevice" .virtual_mcu_fd false 1 {
+# {command "Timer/Counter 0" "" 14 {X::__functional_diagram 0}
+# "player_time" ""}
+# {command "Timer/Counter 1" "" 14 {X::__functional_diagram 1}
+# "player_time" ""}
+# {command "Timer/Counter 2" "" 14 {X::__functional_diagram 2}
+# "player_time2" ""}
+# {command "Baud rate generator" "" 0 {X::__functional_diagram b}
+# "fsview" ""}
+# {command "UART" "" 0 {X::__functional_diagram u}
+# "_blockdevice" "Universal asynchronous receiver transmitter"}
+# {command "SPI" "" 0 {X::__functional_diagram s}
+# "blockdevice" "Serial peripheral interface"}
+# {command "PCA" "" 0 {X::__functional_diagram s}
+# "kservices" "Programable counter array"}
+# {command "Watchdog timer" "" 0 {X::__functional_diagram w}
+# "flag" ""}
+# }}
+# {separator}
+# {command "Virtual UART termnal" "" 8 {X::__virtual_terminal u}
+# "chardevice" ""}
+# {command "Virtual SPI termnal" "" 9 {X::__virtual_terminal s}
+# "chardevice" ""}
+#
+#
+
+
+## (Re)Draw main menu
+ # @return void
+proc mainmenu_redraw {} {
+ global editor_EOL
+ global editor_encoding
+ global MAINMENU
+
+ # Destroy main menu
+ if {[winfo exists .mainMenu]} {
+ destroy .mainMenu
+ }
+ # Create main menu
+ . configure -menu .mainMenu
+ menuFactory $MAINMENU .mainMenu 0 {} 0 {}
+ .mainMenu configure -bd 0 -bg {#EEEEEE} -activeforeground {#6666FF} -activebackground {#EEEEEE} -activeborderwidth 1
+
+ # Restore lists of recent files
+ for {set i 0} {$i < 3} {incr i} {
+ ::X::refresh_recent_files $i
+ }
+
+ ## CREATE MENU "Encoding" and set default ENCODING and EOL
+ set editor_EOL {lf} ;# Current EOL
+ set editor_encoding {utf-8} ;# Current encoding
+
+ # Major encodings
+ foreach enc {
+ utf-8 iso8859-1 iso8859-2
+ iso8859-3 iso8859-4 iso8859-5
+ iso8859-6 iso8859-7 iso8859-8
+ iso8859-9 iso8859-10 iso8859-13
+ iso8859-14 iso8859-15 iso8859-16
+ } {
+ .mainMenu.tools.encoding add radiobutton \
+ -label [enc2name $enc] \
+ -value $enc \
+ -accelerator [string toupper $enc] \
+ -variable ::editor_encoding \
+ -command {::X::change_encoding} \
+ -indicatoron 0 \
+ -compound left \
+ -image ::ICONS::raoff \
+ -selectimage ::ICONS::raon \
+ -selectcolor {#EEEEEE}
+ }
+ .mainMenu.tools.encoding entryconfigure 0 -foreground {#0000FF} -underline 0
+
+ # Shit encodings
+ set menu [menu .mainMenu.tools.encoding.shit_encodings]
+ .mainMenu.tools.encoding add cascade -label "CP125x" -menu $menu
+ foreach enc {cp1250 cp1251 cp1252 cp1253 cp1254 cp1255 cp1256 cp1257 cp1258} {
+ $menu add radiobutton \
+ -label $enc \
+ -value $enc \
+ -variable ::editor_encoding \
+ -command {::X::change_encoding} \
+ -indicatoron 0 \
+ -compound left \
+ -image ::ICONS::raoff \
+ -selectimage ::ICONS::raon \
+ -selectcolor {#EEEEEE}
+ }
+
+ # Window geometry correction
+ wm geometry . $::CONFIG(WINDOW_GEOMETRY)
+ update idle
+
+ # Enable / Disable menu items
+ if {${::X::project_menu_locked}} {
+ ::X::Lock_project_menu
+ } {
+ ::X::disena_simulator_menu ${::X::actualProject}
+ if {![lindex ${::X::simulator_enabled} ${::X::actualProjectIdx}]} {
+ ::X::Lock_simulator_menu
+ }
+ }
+
+ # Remove menu items which access features are not available on MS Windows
+ if {$::MICROSOFT_WINDOWS} {
+ .mainMenu.configure delete [::mc "Configure terminal emulator"]
+ .mainMenu.configure delete [::mc "Edit custom commands"]
+ .mainMenu.tools delete [::mc "Custom command 0"]
+ .mainMenu.tools delete [::mc "Custom command 1"]
+ .mainMenu.tools delete [::mc "Custom command 2"]
+ .mainMenu.tools delete [::mc "Run doxywizard"]
+ .mainMenu.tools delete [::mc "Clear C API documentation"]
+ .mainMenu.tools delete [::mc "Build C API documentation"]
+ }
+
+ # Disable menu items which are not avaliable when external editor used
+ ::X::adjust_mm_and_tb_ext_editor
+}
+
+# MAIN ICON BAR
+# ----------------------
+
+# Create main toolbar frames
+set TOOLBAR_FRAME [frame .mainToolbar]
+pack $TOOLBAR_FRAME -side top -anchor nw -pady 5 -fill x
+frame .mainIconBar
+
+# Create toolbar popup menu
+menuFactory {
+ {command "Hide Toolbar" "" 0 {
+ set ::CONFIG(TOOLBAR_VISIBLE) 0
+ show_hide_main_toolbar
+ } "2uparrow" "Hide main toolbar"}
+ {command "Configure Toolbar" "" 0
+ {::configDialogs::toolbar::mkDialog}
+ "configure_toolbars" "Configure main toolbar"}
+} $TOOLBAR_FRAME.menu 0 {} 0 {}
+bind .mainIconBar <ButtonRelease-3> "tk_popup $TOOLBAR_FRAME.menu %X %Y"
+
+# Create popup menu for custom commands
+menuFactory {
+ {command "Hide Toolbar" "" 0
+ {set ::CONFIG(TOOLBAR_VISIBLE) 0; show_hide_main_toolbar}
+ "2uparrow" "Hide main toolbar"}
+ {command "Configure Toolbar" "" 0
+ {::configDialogs::toolbar::mkDialog}
+ "configure_toolbars" "Configure main toolbar"}
+ {separator}
+ {command "Configure cutom commands" "" 1
+ {::configDialogs::custom_commands::mkDialog ${::CUTOM_CMD_MENU_CMD_INDEX}}
+ "configure" "Invoke cutom commands configuration dialog"}
+} $TOOLBAR_FRAME.cutom_cmd_menu 0 {} 0 {}
+
+# Create show button
+Label $TOOLBAR_FRAME.show_label \
+ -bd 0 -highlightthickness 0 \
+ -image ::ICONS::22::bar1 \
+ -helptext [mc "Show toolbar"]
+bind $TOOLBAR_FRAME.show_label <Button-1> {
+ set ::CONFIG(TOOLBAR_VISIBLE) 1
+ show_hide_main_toolbar
+}
+
+# Help variable for 'cutom_cmd_menu' -- index of selected command
+set CUTOM_CMD_MENU_CMD_INDEX 0
+
+## Definition of all possoble items for main icon bar
+ # format: {
+ # {item_ID} {item_name icon_22x22 icon_16x16 command_postfix statusTip}
+ # ....
+ # }
+ # note: command prefix is '::X::__' so if command_postfix == 'new' then the whole command is '::X::__new'
+set ICONBAR_ICONS {
+ {new} { "Create new file" {filenew} {filenew}
+ {new} {Create new file}}
+ {open} { "Open file" {fileopen} {fileopen}
+ {open} {Open file}}
+ {save} { "Save" {filesave} {filesave}
+ {save} {Save the current file}}
+ {save_as} { "Save as" {filesaveas} {filesaveas}
+ {save_as} {Save the current file under a different name}}
+ {save_all} { "Save all" {save_all} {save_all}
+ {save_all} {Save all opened files (in this project)}}
+ {close} { "Close" {fileclose} {fileclose}
+ {close} {Close the current file}}
+ {close_all} { "Close all" {stop} {cancel}
+ {close_all} {Close all opened files}}
+ {exit} { "Exit" {exit} {exit}
+ {exit} {Exit application}}
+ {undo} { "Undo" {undo} {undo}
+ {undo} {Take back last operation}}
+ {redo} { "Redo" {redo} {redo}
+ {redo} {Take back last undo}}
+ {cut} { "Cut" {editcut} {editcut}
+ {cut} {Move selected text into the clipboard}}
+ {copy} { "Copy" {editcopy} {editcopy}
+ {copy} {Copy selected text into the clipboard}}
+ {paste} { "Paste" {editpaste} {editpaste}
+ {paste} {Paste text from clipboard}}
+ {find} { "Find a string in the text" {find} {find}
+ {find} {Find a string in the text}}
+ {findnext} { "Find next" {1downarrow} {1downarrow}
+ {find_next} {Find next occurence of search string}}
+ {findprev} { "Find previous" {1uparrow} {1uparrow}
+ {find_prev} {Find previous occurence of search string}}
+ {replace} { "Replace" {find} {find}
+ {replace} "Replace some string with another"}
+ {goto} { "Jump to line" {goto} {goto}
+ {goto} {Jump to line}}
+ {reload} { "Reload" {reload} {reload}
+ {reload} "Reload the current file"}
+ {clear} { "Clear messages panel" {editdelete} {editdelete}
+ {clear_messages_text} "Clear messages panel"}
+ {project_new} { "Create new project" {filenew} {filenew}
+ {proj_new} {Create new project}}
+ {project_open} { "Open project" {project_open} {project_open}
+ {proj_open} {Open an existing project}}
+ {proj_save} { "Save project" {filesave} {filesave}
+ {proj_save} "Save the current project"}
+ {proj_edit} { "Edit project" {configure} {configure}
+ {proj_edit} "Edit project details"}
+ {proj_close} { "Save and close project" {fileclose} {fileclose}
+ {proj_close} "Save the current project and close it"}
+ {proj_close_imm} { "Close project without saving" {stop} {no}
+ {proj_close_imm} "Close current project"}
+ {sfrmap} { "Show SFR map" {memory_S} {kcmmemory_S}
+ {sfr_map} "Show map of special function registers area"}
+ {bitmap} { "Show bit area" {memory_BA} {kcmmemory_BA}
+ {bitmap} "Show bit addressable area"}
+ {show_code_mem} { "Show CODE memory" {memory_C} {kcmmemory_C}
+ {show_code_mem} "Invoke hex editor with program code"}
+ {show_ext_mem} { "Show XDATA memory" {memory_X} {kcmmemory_X}
+ {show_ext_mem} "Invoke hex editor with external data memory"}
+ {show_exp_mem} { "Show ERAM" {memory_E} {kcmmemory_E}
+ {show_exp_mem} "Invoke hex editor with expanded RAM"}
+ {show_eeprom} { "Show data EEPROM" {memory_P} {kcmmemory_P}
+ {show_eeprom} "Invoke hex editor with data EEPROM"}
+ {show_eem_wr_b} { "Show EEPROM write buffer" {memory_B} {kcmmemory_B}
+ {show_eeprom_write_buffer} "Invoke hexeditor editor with data EEPROM write buffer"}
+ {start_sim} { "Start / Shutdown simulator" {fork} {launch}
+ {initiate_sim} {Load debug file into simulator engine}}
+ {start_sim0} { "Debug this file only" {fork_this} {launch_this}
+ {initiate_sim 1} {Start simulator engine and load current file only}}
+ {reset} { "Reset" {rebuild} {rebuild}
+ {reset -} "Perform HW reset"}
+ {step} { "Step program" {goto} {goto}
+ {step} "Step by 1 instruction"}
+ {stepover} { "Step over" {goto2} {goto2}
+ {stepover} "Step by 1 line of code"}
+ {animate} { "Animate program" {1rightarrow} {1rightarrow}
+ {animate} "Run program and show results after each instruction"}
+ {run} { "Run program" {2rightarrow} {2rightarrow}
+ {run} "Run program in simulator"}
+ {hibernate} { "Hibernate program" {bar5} {bar5}
+ {hibernate} "Hibernate running program to a file"}
+ {resume} { "Resume program" {resume} {resume}
+ {resume} "Resume hibernated program"}
+ {intrmon} { "Interrupt monitor" {kcmdf} {kcmdf}
+ {interrupt_monitor} "Dialog in which you can controll MCU interrupts"}
+ {stopwatch} { "Stopwatch" {history} {player_time}
+ {stopwatch_timer} "Configurable stopwatch timer which stop simulation on various conditions"}
+ {clear_hg} { "Clear highlight" {editclear} {editclear}
+ {sim_clear_highlight} "Clear highlight for changed values"}
+ {assemble} { "Compile source code" {compfile} {compfile}
+ {compile 0} {Compile source code}}
+ {assemble0} { "Compile this file" {compfile_this} {compfile_this}
+ {compile 0 {} 1} {Compile current file only}}
+ {disasm} { "Disassemble" {disasm} {disasm}
+ {disasm} "Disassemble object code and open new editor with the result"}
+ {hexeditor} { "Hex Editor" {binary} {ascii}
+ {hexeditor} "Invoke project independent hexadecimal editor with capacity of 64KB"}
+ {symbol_tbl} { "Symbol table" {symbol} {symbol}
+ {symb_view} "Assembly language symbol table viewer"}
+ {8seg} { "8-segment editor" {8seg} {8seg}
+ {eightsegment} "8-segment LED display editor"}
+ {ascii_c} { "ASCII chart" {math_matrix} {math_matrix}
+ {ascii_chart} "ASCII chart"}
+ {reformat_code} { "Auto indent" {filter} {filter}
+ {reformat_code} "Reformat source code (Indention level ...)"}
+ {change_case} { "Change letter case" {change_case} {change_case}
+ {change_letter_case} "Change letter case in source code (with options)"}
+ {cleanup} { "Clean up project folder" {emptytrash} {emptytrash}
+ {cleanup} "Invoke dialog to remove needless files the project directory"}
+ {toHTML} { "Export as XHTML" {html} {html}
+ {toHTML} "Export highlighted code as XHTML file"}
+ {toLaTeX} { "Export as LaTeX" {tex} {tex}
+ {toLaTeX} "Export highlighted code as LaTeX source, using package color"}
+ {custom0} { "Custom command 0" {gear0} {gear0}
+ {exec_custom_cmd 0} {}}
+ {custom1} { "Custom command 1" {gear1} {gear1}
+ {exec_custom_cmd 1} {}}
+ {custom2} { "Custom command 2" {gear2} {gear2}
+ {exec_custom_cmd 2} {}}
+ {about} { "About" {mcu8051ide} {mcu8051ide}
+ {about} "About MCU 8051 IDE"}
+ {forward} { "Forward" {forward} {1rightarrow}
+ {next_editor} "Switch to the next editor"}
+ {back} { "Back" {back} {1leftarrow}
+ {prev_editor} "Switch to the previous editor"}
+ {tip_otd} { "Tip of the day" {help} {help}
+ {tip_of_the_day} "Some tips about how to use this program more efficiently"}
+ {find_sim_cur} { "Find cursor" {forward} {forward}
+ {see_sim_cursor} "Find simulator cursor in the editor"}
+ {line2addr} { "Jump to line" {goto} {goto}
+ {simulator_set_PC_by_line} "Translate line number to address in program memory and set PC to that address"}
+ {stepback} { "Step back" {undo} {undo}
+ {stepback} "Step program back by 1 inctruction"}
+ {notes} { "Scribble notepad" {pencil} {pencil}
+ {notes} "Scribble notepad"}
+ {ledpanel} { "LED panel" {ledpanel} {ledpanel}
+ {vhw_LED_panel} "LED panel"}
+ {leddisplay} { "LED display" {leddisplay} {leddisplay}
+ {vhw_LED_display} "LED display"}
+ {ledmatrix} { "LED matrix" {ledmatrix} {ledmatrix}
+ {vhw_LED_matrix} "LED matrix"}
+ {mleddisplay} { "Multiplexed LED display" {mleddisplay} {mleddisplay}
+ {vhw_M_LED_display} "Multiplexed LED display"}
+ {simplekeypad} { "Simple keypad" {simplekeypad} {simplekeypad}
+ {vhw_keys} "Simple keypad"}
+ {matrixkeypad} { "Matrix keypad" {matrixkeypad} {matrixkeypad}
+ {vhw_matrix_keypad} "Matrix keypad"}
+ {vhw_open} { "VHW Open" {fileopen} {fileopen}
+ {open_VHW} "Load VHW connections from a file"}
+ {vhw_load} { "VHW Load" {fileimport} {fileimport}
+ {load_VHW} "Import VHW connections from a file"}
+ {vhw_save} { "VHW Save" {filesave} {filesave}
+ {save_VHW} "Save current VHW connections to a file"}
+ {vhw_saveas} { "VHW Save as" {filesaveas} {filesaveas}
+ {save_as_VHW} "Save current VHW connections under a different name"}
+ {vhw_remove_all} { "VHW Remove all" {editdelete} {editdelete}
+ {remove_all_VHW} "Remove all VHW"}
+ {bc} { "Base Convertor" {kaboodleloop} {kaboodleloop}
+ {base_convertor} "Base Convertor"}
+ {fullscreen} { "Toggle fullscreen mode" {window_fullscreen} {window_fullscreen}
+ {toggle_fullscreen} "Fullscreen mode"}
+ {spec_calc} { "Special calculator" {xcalc} {xcalc}
+ {spec_calc} "Special calculator"}
+ {stack} { "Show stack" {memory_ST} {kcmmemory_ST}
+ {stack_monitor} "Invoke MCU stack monitor"}
+ {rs232} { "UART/RS232 Debugger" {_chardevice} {chardevice}
+ {rs232debugger} "UART/RS232 Debugger"}
+}
+
+## Definition of default main icon bar
+ # format: {
+ # item_ID item_ID ...
+ # }
+set ICONBAR_DEFAULT {
+ new open | save save_as save_all | close exit | fullscreen |
+ project_new project_open | find goto | hibernate resume |
+ custom0 custom1 | leddisplay matrixkeypad | notes | assemble |
+ start_sim step stepback
+}
+
+## Definition of icons current main icon bar
+ # format: {
+ # item_ID item_ID ...
+ # }
+set ICONBAR_CURRENT {}
+
+## (Re)draw icon bar acording to $ICONBAR_CURRENT
+ # @return void
+proc iconbar_redraw {} {
+ ::toolbar::iconbar_redraw
+}
+namespace eval toolbar {
+ proc iconbar_redraw {} {
+ global ICONBAR_CURRENT ;# Definition of icons current main icon bar
+ global ICONBAR_ICONS ;# Definition of all possoble items for main icon bar
+
+ # Destroy current content of the icon bar
+ foreach wdg [pack slaves .mainIconBar] {
+ destroy $wdg
+ }
+
+ # Create hide button
+ pack [Label .mainIconBar.hide_label \
+ -bd 0 -highlightthickness 0 \
+ -image ::ICONS::22::bar0 \
+ -helptext [mc "Hide toolbar"] \
+ ] -side left -padx 4
+ bind .mainIconBar.hide_label <Button-1> {
+ set ::CONFIG(TOOLBAR_VISIBLE) 0
+ show_hide_main_toolbar
+ }
+
+ set separator_idx 0 ;# Separator index (to keep unique widget names)
+
+ # Iterate over icon bar definition
+ foreach key $ICONBAR_CURRENT {
+
+ # Skip items which access features are not available on MS Windows
+ if {$::MICROSOFT_WINDOWS} {
+ if {[lsearch -ascii -exact {custom0 custom1 custom2} $key] != -1} {
+ continue
+ }
+ }
+
+ # Insert regular item
+ if {$key != {|}} {
+ # Find detail definition
+ set idx [lsearch $ICONBAR_ICONS $key]
+ if {$idx == -1} {
+ puts stderr "iconbar_redraw: Invalid key in definition of Main Tool Bar '$key'"
+ continue
+ }
+ set def [lindex $ICONBAR_ICONS [expr {$idx+1}]]
+
+ # Create button
+ set button [ttk::button .mainIconBar.$key \
+ -image ::ICONS::22::[lindex $def 1] \
+ -command X::__[lindex $def 3] \
+ -style ToolButton.TButton \
+ ]
+ DynamicHelp::add .mainIconBar.$key -text [mc [lindex $def 0]]
+ pack $button -side left -padx 0
+
+ ## Set status tip
+ # For custom commands
+ if {[regexp {^custom\d+$} $key]} {
+ regexp {\d+} $key num
+ setStatusTip -widget $button -text [mc "Custom command %s: %s" $num $::X::custom_command_desc($num)]
+ bind $button <ButtonRelease-3> [subst {
+ set CUTOM_CMD_MENU_CMD_INDEX $num
+ tk_popup $::TOOLBAR_FRAME.cutom_cmd_menu %X %Y
+ }]
+ # For normal commands
+ } {
+ setStatusTip -widget $button -text [mc [lindex $def 4]]
+ bind $button <ButtonRelease-3> {tk_popup $::TOOLBAR_FRAME.menu %X %Y}
+ }
+
+ # Insert separator
+ } else {
+ # Create vertical separator widget
+ pack [ttk::separator .mainIconBar.sep$separator_idx \
+ -orient vertical \
+ ] -side left -padx 3 -fill y
+ incr separator_idx
+ }
+ }
+
+ # Disable some buttons if the toolbar is locked
+ if {${::X::project_menu_locked}} {
+ ena_dis_iconBar_buttons 0 .mainIconBar. ${::X::toolbar_project_dependent_buttons}
+ }
+ }
+}
+
+## Show/Hide main toolbar acording to value of config variable TOOLBAR_VISIBLE
+ # @return void
+proc show_hide_main_toolbar {} {
+ # Show the toolbar
+ if {$::CONFIG(TOOLBAR_VISIBLE)} {
+ catch {
+ ${::X::actualProject} bottomNB_move_pane_up 11
+ }
+ pack .mainIconBar -in $::TOOLBAR_FRAME -fill x
+ catch {
+ pack forget $::TOOLBAR_FRAME.show_label
+ }
+ # Hide the toolbar
+ } {
+ catch {
+ ${::X::actualProject} bottomNB_move_pane_up -11
+ }
+ pack $::TOOLBAR_FRAME.show_label -side left -anchor w -padx 4
+ catch {
+ pack forget .mainIconBar
+ }
+ }
+
+ # Restore position of bottom pane
+ foreach project ${::X::openedProjects} {
+ $project bottomNB_redraw_pane
+ update
+ $project editor_procedure {} Configure {}
+ }
+}
+
+
+# GLOBAL POPUP MENUS (entry and text widgets)
+# -------------------------------
+
+# Set event bindings
+bind Entry <ButtonPress-3> {break}
+bind Entry <ButtonRelease-3> {GPM_entry_popup %X %Y %x %y %W; break}
+bind Entry <Key-Menu> {GPM_entry_key_menu %W; break}
+bind TEntry <ButtonPress-3> {break}
+bind TEntry <ButtonRelease-3> {GPM_entry_popup %X %Y %x %y %W; break}
+bind TEntry <Key-Menu> {GPM_entry_key_menu %W; break}
+bind Text <ButtonRelease-3> {GPM_text_popup %X %Y %x %y %W; break}
+bind Text <Key-Menu> {GPM_text_key_menu %W; break}
+
+## Create popup menus
+ # Menu for entry widgets
+menuFactory {
+ {command {Cut} {Ctrl+X} 2 "GPM_entry_cut" {editcut} {}}
+ {command {Copy} {Ctrl+C} 0 "GPM_entry_copy" {editcopy} {}}
+ {command {Paste} {Ctrl+V} 0 "GPM_entry_paste" {editpaste} {}}
+ {command {Clear} {} 1 "GPM_entry_clear" {editdelete} {}}
+ {separator}
+ {command {Select all} {Ctrl+A} 0 "GPM_entry_selall" {} {}}
+} .gpm_entry_menu 0 {} 0 {}
+ # Menu for text widgets
+menuFactory {
+ {command {Undo} {Ctrl+Z} 0 "GPM_text_undo" {undo} {}}
+ {command {Redo} {Ctrl+Shift+Z} 0 "GPM_text_redo" {redo} {}}
+ {separator}
+ {command {Cut} {Ctrl+X} 2 "GPM_text_cut" {editcut} {}}
+ {command {Copy} {Ctrl+C} 0 "GPM_text_copy" {editcopy} {}}
+ {command {Paste} {Ctrl+V} 0 "GPM_text_paste" {editpaste} {}}
+ {command {Clear} {} 1 "GPM_text_clear" {editdelete} {}}
+ {separator}
+ {command {Select all} {Ctrl+A} 0 "GPM_text_selall" {} {}}
+} .gpm_text_menu 0 {} 0 {}
+
+# Widget identifiers
+set GPM_entry_widget {} ;# Entry widget
+set GPM_text_widget {} ;# Text widget
+
+## Invoke entry widget popup menu -- event <ButtonRelease-3>
+ # @parm Int X - absolute X coordinate
+ # @parm Int Y - absolute Y coordinate
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative Y coordinate
+ # @parm Widget Widget - Entry widget
+ # @return void
+proc GPM_entry_popup {X Y x y Widget} {
+ global GPM_entry_widget
+
+ set GPM_entry_widget $Widget
+ GPM_entry_menu_disena
+ tk_popup .gpm_entry_menu $X $Y
+}
+
+## Invoke entry widget popup menu -- event <Key-Menu>
+ # @parm Widget Widget - Entry widget
+ # @return void
+proc GPM_entry_key_menu {Widget} {
+ global GPM_entry_widget
+
+ set GPM_entry_widget $Widget
+ GPM_entry_menu_disena
+ set bbox [$Widget bbox [$Widget index insert]]
+ tk_popup .gpm_entry_menu \
+ [expr {[winfo rootx $Widget] + [lindex $bbox 0] + 10}] \
+ [expr {[winfo rooty $Widget] + [lindex $bbox 1] + 10}]
+}
+
+## Enable/Disable popup menu items acording to state of the widget
+ # For entry widgets. Auxiliary procedure for 'GPM_entry_popup' and 'GPM_entry_key_menu'
+ # @return void
+proc GPM_entry_menu_disena {} {
+ global GPM_entry_widget
+
+ set state [$GPM_entry_widget cget -state]
+ if {$state != {normal}} {
+ set state {disabled}
+ }
+ if {[$GPM_entry_widget selection present]} {
+ if {$state != {disabled}} {
+ .gpm_entry_menu entryconfigure [::mc "Cut"] -state normal
+ }
+ .gpm_entry_menu entryconfigure [::mc "Copy"] -state normal
+ } {
+ .gpm_entry_menu entryconfigure [::mc "Cut"] -state disabled
+ .gpm_entry_menu entryconfigure [::mc "Copy"] -state disabled
+ }
+ .gpm_entry_menu entryconfigure [::mc "Paste"] -state $state
+ .gpm_entry_menu entryconfigure [::mc "Clear"] -state $state
+}
+
+## Invoke text widget popup menu -- event <ButtonRelease-3>
+ # @parm Int X - absolute X coordinate
+ # @parm Int Y - absolute Y coordinate
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative Y coordinate
+ # @parm Widget Widget - Text widget
+ # @return void
+proc GPM_text_popup {X Y x y Widget} {
+ global GPM_text_widget
+
+ set GPM_text_widget $Widget
+ GPM_text_menu_disena
+ tk_popup .gpm_text_menu $X $Y
+}
+
+## Invoke text widget popup menu -- event <Key-Menu>
+ # @parm Widget Widget - Text widget
+ # @return void
+proc GPM_text_key_menu {Widget} {
+ global GPM_text_widget
+
+ set GPM_text_widget $Widget
+ GPM_text_menu_disena
+ $Widget see insert
+ set bbox [$Widget bbox [$Widget index insert]]
+ tk_popup .gpm_text_menu \
+ [expr {[winfo rootx $Widget] + [lindex $bbox 0] + 10}] \
+ [expr {[winfo rooty $Widget] + [lindex $bbox 1] + 10}]
+}
+
+## Enable/Disable popup menu items acording to state of the widget
+ # For text widgets. Auxiliary procedure for 'GPM_text_popup' and 'GPM_text_key_menu'
+ # @return void
+proc GPM_text_menu_disena {} {
+ global GPM_text_widget
+
+ set state [$GPM_text_widget cget -state]
+ if {[llength [$GPM_text_widget tag nextrange sel 1.0]]} {
+ if {$state != {disabled}} {
+ .gpm_text_menu entryconfigure [::mc "Cut"] -state normal
+ }
+ .gpm_text_menu entryconfigure [::mc "Copy"] -state normal
+ } else {
+ .gpm_text_menu entryconfigure [::mc "Cut"] -state disabled
+ .gpm_text_menu entryconfigure [::mc "Copy"] -state disabled
+ }
+ foreach entry {Undo Redo Paste Clear} {
+ .gpm_text_menu entryconfigure [::mc $entry] -state $state
+ }
+}
+## Cut selected text -- entry widget
+ # @return void
+proc GPM_entry_cut {} {
+ global GPM_entry_widget
+
+ # Check for widget existence
+ if {![winfo exists $GPM_entry_widget]} {return}
+ # Check if there is selected text
+ if {![$GPM_entry_widget selection present]} {return}
+
+ # Copy selected text to clipboard
+ set data [$GPM_entry_widget get]
+ set data [string range $data \
+ [$GPM_entry_widget index sel.first] \
+ [expr {[$GPM_entry_widget index sel.last] - 1}] \
+ ]
+ clipboard clear
+ clipboard append $data
+
+ # Remove the selected text
+ $GPM_entry_widget delete sel.first sel.last
+}
+
+## Copy selected text to clipboard -- entry widget
+ # @return void
+proc GPM_entry_copy {} {
+ global GPM_entry_widget
+
+ # Check for widget existence
+ if {![winfo exists $GPM_entry_widget]} {return}
+ # Check if there is selected text
+ if {![$GPM_entry_widget selection present]} {return}
+
+ # Copy selected text to clipboard
+ set data [$GPM_entry_widget get]
+ set data [string range $data \
+ [$GPM_entry_widget index sel.first] \
+ [expr {[$GPM_entry_widget index sel.last] - 1}] \
+ ]
+ clipboard clear
+ clipboard append $data
+}
+
+## Paste text from clipboard -- entry widget
+ # @return void
+proc GPM_entry_paste {} {
+ global GPM_entry_widget
+
+ # Check for widget existence
+ if {![winfo exists $GPM_entry_widget]} {return}
+ # Check if clipboard is not empty
+ set data [clipboard get]
+ if {$data == {}} {return}
+
+ # Paste text from clipboard
+ catch {
+ $GPM_entry_widget delete sel.first sel.last
+ }
+ $GPM_entry_widget insert insert $data
+}
+
+## Clear all text -- entry widget
+ # @return void
+proc GPM_entry_clear {} {
+ if {![winfo exists $::GPM_entry_widget]} {return}
+ $::GPM_entry_widget delete 0 end
+}
+
+## Select all text -- entry widget
+ # @return void
+proc GPM_entry_selall {} {
+ if {![winfo exists $::GPM_entry_widget]} {return}
+ $::GPM_entry_widget selection range 0 end
+}
+
+## Take back last operation -- text widget
+ # @return void
+proc GPM_text_undo {} {
+ catch {
+ $::GPM_text_widget edit undo
+ }
+}
+
+## Take back last undo -- text widget
+ # @return void
+proc GPM_text_redo {} {
+ catch {
+ $::GPM_text_widget edit redo
+ }
+}
+
+## Cut selected text -- text widget
+ # @return void
+proc GPM_text_cut {} {
+ global GPM_text_widget
+
+ # Check for widget existence
+ if {![winfo exists $GPM_text_widget]} {return}
+ # Check if there is selected text
+ if {![llength [$GPM_text_widget tag nextrange sel 1.0]]} {return}
+
+ # Copy selected text to clipboard
+ clipboard clear
+ clipboard append [$GPM_text_widget get sel.first sel.last]
+
+ # Remove the selected text
+ $GPM_text_widget delete sel.first sel.last
+}
+
+## Copy selected text to clipboard -- text widget
+ # @return void
+proc GPM_text_copy {} {
+ global GPM_text_widget
+
+ # Check for widget existence
+ if {![winfo exists $GPM_text_widget]} {return}
+ # Check if there is selected text
+ if {![llength [$GPM_text_widget tag nextrange sel 1.0]]} {return}
+
+ # Copy selected text to clipboard
+ clipboard clear
+ clipboard append [$GPM_text_widget get sel.first sel.last]
+}
+
+## Paste text from clipboard -- text widget
+ # @return void
+proc GPM_text_paste {} {
+ global GPM_text_widget
+
+ # Check for widget existence
+ if {![winfo exists $GPM_text_widget]} {return}
+ # Check if clipboard is not empty
+ set data [clipboard get]
+ if {$data == {}} {return}
+
+ # Paste text from clipboard
+ catch {
+ $GPM_text_widget delete sel.first sel.last
+ }
+ $GPM_text_widget insert insert $data
+}
+
+## Clear all text -- text widget
+ # @return void
+proc GPM_text_clear {} {
+ catch {
+ $::GPM_text_widget delete 1.0 end
+ }
+}
+
+## Select all text -- text widget
+ # @return void
+proc GPM_text_selall {} {
+ catch {
+ $::GPM_text_widget tag add sel 1.0 end
+ }
+}
+
+# FINALIZE BASIC ENVIROMENT INITIALIZATION
+# -----------------------------------------
+show_hide_main_toolbar ;# Show/Hide Main toolbar
+pack [frame .mainFrame] -fill both -expand 1 ;# Frame for central widget
+makeStatusbar {} ;# Create status bar
+change_validation_level $::CONFIG(VALIDATION_LEVEL) ;# Restore previous validation level
+::X::initialize ;# Intialize X NS
+::KIFSD::FSD::load_config_array $::CONFIG(KIFSD_CONFIG) ;# Restore configuration of file selection dialog
+::HexEditDlg::loadConfig $::CONFIG(HEXEDIT_CONFIG) ;# Restore hexaeditor configuration
+::KIFSD::FSD::set_bookmark_change_command {::X::refresh_bookmarks_in_fs_browsers}
+
+# SHOW TIP OF THE DAY
+# -----------------------------------------
+if {$show_welcome_dialog} {
+ set X::critical_procedure_in_progress 0
+ X::__welcome_dialog
+ set X::critical_procedure_in_progress 1
+} elseif {${GLOBAL_CONFIG(tips)}} {
+ X::__tip_of_the_day
+}
+
+# Create project notebook
+# -----------------------------------------
+NoteBook .mainFrame.mainNB -side top -arcradius 4 -bd 1 -bg {#EEEEEE}
+
+# Project details window
+.mainFrame.mainNB bindtabs <Enter> {::X::create_project_details}
+.mainFrame.mainNB bindtabs <Motion> {::X::project_details_move}
+.mainFrame.mainNB bindtabs <Leave> {::X::close_project_details}
+.mainFrame.mainNB bindtabs <ButtonRelease-3> {::X::invoke_project_menu %X %Y}
diff --git a/lib/external_command.tcl b/lib/external_command.tcl
new file mode 100755
index 0000000..959cd29
--- /dev/null
+++ b/lib/external_command.tcl
@@ -0,0 +1,143 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Send input read from strandard input to certain Tk application via
+# send command
+#
+# USAGE:
+# set pid [exec -- some_command ?args? |& tclsh external_command.tcl [tk appname] final_cmd line_cmd &]
+# * pid - Process indentifier of $some_command
+# * some_command - Command which output should be couth
+# * args - Arguments for $some_command
+# * final_cmd - Command in local Tcl program to execute once when $some_command finish
+# * line_cmd - Command in local Tcl program to execute everytime when $some_command outputs one line
+# --------------------------------------------------------------------------
+
+# Initialize
+package require Tk
+wm withdraw .
+wm command . "$argv0 $argv"
+wm client . [info hostname]
+
+# Partse agruments
+set target_app [lindex $argv 0]
+set final_cmd [lindex $argv 1]
+set line_cmd [lindex $argv 2]
+unset argv
+
+## Determinate the host OS
+set ::MICROSOFT_WINDOWS 0
+if {[string first {Windows} ${tcl_platform(os)}] != -1} {
+ # Note:
+ # Microsoft Windows is NOT a POSIX system and because of that we need
+ # to do some workarounds here in order to make the IDE functional there.
+ set ::MICROSOFT_WINDOWS 1
+}
+
+# Load dde - Dynamic Data Exchange on Microsoft Windows
+if {$::MICROSOFT_WINDOWS} {
+ package require dde
+}
+
+## Perform secure send command
+ # Secure means that it will not crash or something like that in case of any errors.
+ # But instead it will popup an error message to the user (Tk dialog).
+ # @parm List args - Arguments for the send command
+ # @return void
+proc secure_send args {
+ if {[catch {
+ eval "send $args"
+ } result]} {
+ puts "Unknown IO Error :: $result"
+ tk_messageBox \
+ -title "Unknown IO Error" \
+ -icon error \
+ -type ok \
+ -message "$result"
+
+ if {[ \
+ tk_messageBox \
+ -title "X server security workaround" \
+ -icon warning \
+ -type yesno \
+ -message "If the error was related to X server security, it is possible to temporarily workaround it by running this command: \"/bin/sh << 'for i in `xhost`; do xhost -\$i; done'\"\n\nDo you want to do it ?"
+ ] == {yes}} then {
+ catch {
+ exec -- /bin/sh << {xhost -; for i in `xhost`; do xhost -$i; done}
+ }
+ } else {
+ exit 1
+ }
+
+ if {[catch {
+ eval "send $args"
+ }]} {
+ tk_messageBox \
+ -title "Workaround failed" \
+ -icon error \
+ -type ok \
+ -message "Sorry this doesn't work ...\nIt's a strange bug somewhere in your operating system"
+ exit 1
+ }
+
+ return 1
+
+ } else {
+ return 1
+ }
+}
+
+## Read standard input
+ # All output will be sended at once
+if {$line_cmd == {}} {
+ set result {}
+ while {![eof stdin]} {
+ append result [gets stdin] "\n"
+ }
+
+ if {!${::MICROSOFT_WINDOWS}} {
+ secure_send $target_app $final_cmd "{" [regsub -all {[\{\}]} $result {\\&}] "}"
+ } {
+ dde eval $target_app $final_cmd "{ [regsub -all {[\{\}]} $result {\\&}] }"
+ }
+
+ # Output will be sended line by line as executed command generates it
+} else {
+ while {![eof stdin]} {
+ if {!${::MICROSOFT_WINDOWS}} {
+ secure_send $target_app $line_cmd "{" [regsub -all {[\{\}]} [gets stdin] {\\&}] "}"
+ } {
+ dde eval $target_app $line_cmd "{ [regsub -all {[\{\}]} [gets stdin] {\\&}] }"
+ }
+ }
+
+ if {!${::MICROSOFT_WINDOWS}} {
+ secure_send $target_app $final_cmd
+ } {
+ dde eval $target_app $final_cmd
+ }
+}
+
+exit 0
diff --git a/lib/leftpanel/filelist.tcl b/lib/leftpanel/filelist.tcl
new file mode 100755
index 0000000..c5f5c14
--- /dev/null
+++ b/lib/leftpanel/filelist.tcl
@@ -0,0 +1,4824 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides:
+# - List of opened files
+# - List of project files
+# - Filesystem browser
+# - Management of opened files, project files and code editors
+# --------------------------------------------------------------------------
+
+# Import nesesary sources
+source "${::LIB_DIRNAME}/leftpanel/fsbrowser.tcl" ;# File system browser
+source "${::LIB_DIRNAME}/leftpanel/sfrwatches.tcl" ;# SRF Watches
+
+class FileList {
+ # Inherit content of some other clases
+ inherit RightPanel SFRWatches FSBrowser
+
+ ## COMMON
+ # String: Textvariable for dialog "Open with ..."
+ common open_with ${::CONFIG(OPEN_WITH_DLG)}
+ common open_with_cnfr 0 ;# Bool: Confirm dialog "Open with ..."
+ common count 0 ;# Instances counter
+ common file_indexes {} ;# List of line indexes (auxiliary variable for opening multiple files)
+ common ac_index_in_fl ;# Index of actual editor filelist
+ common default_encoding {utf-8} ;# Default encoding
+ common default_eol {lf} ;# Default EOL
+ common bookmark 0 ;# Auxiliary variable for popup menu for Icon Borders
+ common pmenu_cline 0 ;# Auxiliary variable for popup menu for Icon Borders
+ # Menu items to disable when entering simulator mode
+ common freezable_menu_items {
+ {New} {Close} {Close All} {Open}
+ }
+ # Font for opened file in project files list
+ common opened_file_font [font create \
+ -weight bold \
+ -slant roman \
+ -size -12 \
+ -family $::DEFAULT_FIXED_FONT \
+ ]
+ # Font for closed file in project files list
+ common closed_file_font [font create \
+ -weight normal \
+ -slant italic \
+ -size -12 \
+ -family $::DEFAULT_FIXED_FONT \
+ ]
+ # Font for icon borders
+ common icon_border_font [font create \
+ -size -12 \
+ -family $::DEFAULT_FIXED_FONT \
+ ]
+
+ common filelist {} ;# List of files to open
+ common open_files_cur_file {} ;# Name of file currently being opened
+ common open_files_progress 0 ;# True if opening files in progress
+ common open_files_abort 0 ;# Abort variable for open files ProgressDialog
+ common filedetails_visible 0 ;# Bool: Is file details window visible
+ common filedetails_after_ID ;# ID of timeout for show window "file details"
+
+ # Definition of popup menu for listbox of opened files
+ common OPENEDFILESMENU {
+ {command {Append to project} {} 0 "filelist_append_to_prj" {add}
+ "Append this file to the current project"}
+ {separator}
+ {command {New} {$edit:new} 0 "editor_new" {filenew}
+ "Create new file and open its editor"}
+ {separator}
+ {command {Open} {$edit:open} 0 "editor_open" {fileopen}
+ "Open an existing file"}
+ {separator}
+ {command {Save} {$edit:save} 0 "editor_save" {filesave}
+ "Save this file"}
+ {command {Save as} {$edit:save_as} 5 "editor_save_as" {filesaveas}
+ "Save this file under different name"}
+ {command {Save all} {$edit:save_all} 6 "editor_save_all" {save_all}
+ "Save all file in the list"}
+ {separator}
+ {command {Close} {$edit:close} 0 "editor_close 1 {}" {fileclose}
+ "Close this file"}
+ {command {Close All} {$edit:close_all} 4 "editor_close_all 1 0" {cancel}
+ "Close all files in the list"}
+ {separator}
+ {command {Bookmark} {} 4 "filelist_o_bookmark" {bookmark_add}
+ "Add/Remove bookmark for this file"}
+ {separator}
+ {command {Move up} {} 5 "filelist_move_up" {1uparrow}
+ "Move this file up in the list"}
+ {command {Move down} {} 5 "filelist_move_down" {1downarrow}
+ "Move this file down in the list"}
+ {command {Move to top} {} 8 "filelist_move_top" {top}
+ "Move this file to the top of the list"}
+ {command {Move to bottom} {} 12 "filelist_move_bottom" {bottom}
+ "Move this file to the bottom of the list"}
+ {separator}
+ {cascade "Sort items by" 11 "" .sort_by false 1 {
+ {command {Document Name} {} 9 "sort_file_list N 1" {} {}}
+ {command {File URL} {} 5 "sort_file_list U 1" {} {}}
+ {command {File Size in B} {} 5 "sort_file_list S 1" {} {}}
+ }}
+ {cascade "Open with" 6 "" .open_with false 1 {
+ {command {gvim} {} 1 "filelist_open_with 1 gvim" {gvim} {}}
+ {command {emacs} {} 1 "filelist_open_with 1 emacs" {emacs} {}}
+ {command {kwrite} {} 0 "filelist_open_with 1 kwrite" {kwrite} {}}
+ {command {gedit} {} 0 "filelist_open_with 1 gedit" {gedit} {}}
+ {command {other} {} 0 "filelist_open_with 1 other" {exec} {}}
+ }}
+ {separator}
+ {command {Hide the panel} {} 0 "filelist_show_hide" {2leftarrow}
+ "Hide this panel"}
+ }
+
+ # Definition of popup menu for notebook with opened files
+ common FILETABSPUMENU {
+ {command {Append to project} {} 0 "filelist_append_to_prj" {add}
+ "Append this file to the current project"}
+ {separator}
+ {command {Save} {$edit:save} 0 "editor_save" {filesave}
+ "Save this file"}
+ {command {Save as} {$edit:save_as} 5 "editor_save_as" {filesaveas}
+ "Save this file under different name"}
+ {command {Save all} {$edit:save_all} 6 "editor_save_all" {save_all}
+ "Save all file in the list"}
+ {separator}
+ {command {Close} {$edit:close} 0 "editor_close 1 {}" {fileclose}
+ "Close this file"}
+ {command {Close All} {$edit:close_all} 4 "editor_close_all 1 0" {cancel}
+ "Close all files in the list"}
+ {separator}
+ {command {Bookmark} {} 4 "filelist_o_bookmark" {bookmark_add}
+ "Add/Remove bookmark for this file"}
+ {separator}
+ {cascade "Open with" 6 "" .open_with false 1 {
+ {command {gvim} {} 1 "filelist_open_with 1 gvim" {gvim} {}}
+ {command {emacs} {} 1 "filelist_open_with 1 emacs" {emacs} {}}
+ {command {kwrite} {} 0 "filelist_open_with 1 kwrite" {kwrite} {}}
+ {command {gedit} {} 0 "filelist_open_with 1 gedit" {gedit} {}}
+ {command {other} {} 0 "filelist_open_with 1 other" {exec} {}}
+ }}
+ }
+
+ # Definition of popup menu for listbox of project files
+ common PROJECTFILESMENU {
+ {command {Remove file from the project} {} 0 "filelist_remove_file_from_project" {editdelete}
+ "Remove this file from the project"}
+ {command {Close file} {$edit:close} 0 "filelist_project_file_close"
+ {fileclose} "Close this file"}
+ {command {Open file} {} 0 "filelist_project_file_open" {fileopen}
+ "Open this file"}
+ {separator}
+ {command {Bookmark} {} 4 "filelist_p_bookmark" {bookmark_add}
+ "Add/Remove bookmark for this file"}
+ {separator}
+ {command {Move up} {} 5 "filelist_prj_move_up" {1uparrow}
+ "Move this item up"}
+ {command {Move down} {} 5 "filelist_prj_move_down" {1downarrow}
+ "Move this item down"}
+ {command {Move to top} {} 8 "filelist_prj_move_top" {top}
+ "Move this item to the top of the list"}
+ {command {Move to bottom} {} 12 "filelist_prj_move_bottom" {bottom}
+ "Move this item to the bottom of the list"}
+ {separator}
+ {cascade "Sort items by" 11 "" .sort_by false 1 {
+ {command {Document Name} {} 9 "sort_file_list N 0" {} {}}
+ {command {File URL} {} 5 "sort_file_list U 0" {} {}}
+ {command {File Size in B} {} 5 "sort_file_list S 0" {} {}}
+ }}
+ {cascade "Open with" 6 "" .open_with false 1 {
+ {command {gvim} {} 1 "filelist_open_with 0 gvim" {gvim} {}}
+ {command {emacs} {} 1 "filelist_open_with 0 emacs" {emacs} {}}
+ {command {kwrite} {} 0 "filelist_open_with 0 kwrite" {kwrite} {}}
+ {command {gedit} {} 0 "filelist_open_with 0 gedit" {gedit} {}}
+ {command {other} {} 0 "filelist_open_with 0 other" {exec} {}}
+ }}
+ {separator}
+ {command {Hide the panel} {} 0 "filelist_show_hide" {2leftarrow}
+ "Hide this panel"}
+ }
+
+ # Definition of popup menu icon border for list of of opened files
+ common OPENEDFILESIBMENU {
+ {checkbutton "Bookmark" "" {::FileList::bookmark} 1 0 0
+ {opened_files_bookmark ${::FileList::pmenu_cline}}}
+ }
+ # Definition of popup menu icon border for list of of project files
+ common PROJECTFILESIBMENU {
+ {checkbutton "Bookmark" "" {::FileList::bookmark} 1 0 0
+ {project_files_bookmark ${::FileList::pmenu_cline}}}
+ }
+
+ ## PUBLIC
+ public variable actualEditor ;# Object number of currently selected editor
+ public variable actualEditor2 -2 ;# Object number of currently selected editor in the second view
+ public variable ProjectDir ;# Reference to directory of actual project
+ public variable editors {} ;# list of editor objects
+ public variable iconBorder $::CONFIG(ICON_BORDER) ;# Bool: display Icon border
+ public variable lineNumbers $::CONFIG(LINE_NUMBERS) ;# Bool: display Line numbers
+
+ ## PRIVATE
+ # Bool: procedure switchfile will not forget its frame (cleared by procedure switchfile)
+ private variable do_not_forget_editor 0
+ private variable editor_close_in_progress 0 ;# Bool: Indicates than procedure editor_close is in progress
+ private variable pwin_orient {} ;# String multiview orientaion (horizontal or vertical)
+ private variable multiview_sash_pos 0 ;# Int: position of panedwindow sash for multiview
+ private variable selectedView 0 ;# Int: 0 == left/top view; 1 == right/bottom view
+ private variable splitted 0 ;# Bool: Editor is splitted
+ private variable main_frame ;# Widget: frame containing $multiview_paned_win or $pagesManager
+ private variable untitled_num -1 ;# Number of untitled entries in file list
+ private variable leftPanel ;# ID of the left panel
+ private variable notebook ;# ID of left panel Notebook
+ private variable parent ;# ID of parent container widget
+ private variable button_bar ;# ID of show/hide button (for listbox of files)
+ private variable lastItem ;# Descriptor of the last selected file
+ private variable obj_idx ;# Index of This object
+ private variable pagesManager ;# ID of frame for packing editors
+ private variable pagesManager2 ;# ID of frame for packing editors in second view
+ private variable multiview_paned_win ;# ID of paned window for $pagesManager and $pagesManager2
+ private variable listbox_opened_files ;# ID of ListBox of currently opened files
+ private variable listbox_opened_files_bm ;# ID of icon border for opened files
+ private variable opened_files_bookmarks {} ;# List: Bookmarks for opened files
+ private variable IB_o_menu ;# ID of popup menu for 'listbox_opened_files_bm'
+ private variable listbox_project_files ;# ID of ListBox of currently opened files
+ private variable listbox_project_files_bm ;# ID of icon border for project files
+ private variable project_files_bookmarks {} ;# List: Bookmarks for project files
+ private variable IB_p_menu ;# ID of popup menu for 'listbox_project_files_bm'
+ private variable last_sash ;# Last position of the paned window sash
+ private variable next_editor_button ;# ID of button "Next editor" -- tab "Opened files"
+ private variable prev_editor_button ;# ID of button "Prev editor" -- tab "Opened files"
+ private variable opened_files_scrollbar ;# ID of scrollbar for opened files visible
+ private variable o_scrollbar_visible 0 ;# Bool: Scrollbar for opened files visible
+ private variable project_files_scrollbar ;# ID of scrollbar for project files visible
+ private variable p_scrollbar_visible 0 ;# Bool: Scrollbar for project files visible
+ private variable opened_files_menu ;# ID of the popup menu asociated with list of opened files
+ private variable project_files_menu ;# ID of the popup menu asociated with list of project files
+ private variable filetabs_pu_menu
+ private variable frozen 0 ;# Bool: Simulator mode flag
+ private variable unsaved ;# List of editor objects with positive flag modified
+ private variable listbox_opened_files_frame ;# Frame for list of opened files
+ private variable listbox_project_files_frame ;# Frame for list of project files
+ private variable fs_browser_frame ;# Frame for file system browser
+ private variable sfr_watches_frame ;# Frame for SFR watches
+ private variable opened_files_buttonBox ;# ID of buttonBox in list of opened files
+ private variable project_files_buttonBox ;# ID of buttonBox in list of project files
+ private variable listbox_opened_files_top_frame ;# Identifier of button frame above listbox of files
+
+ private variable opened_search_entry ;# ID of search entry for opened files
+ private variable opened_search_clear_button ;# ID of button "Clear" on search panel -- opened files
+ private variable opened_files_highlighted_item {} ;# ID of currently highlighted item in opened files
+ private variable opened_files_hg_item_fg_clr {} ;# Fg. color of currently highlighted item in opened files
+ private variable project_search_entry ;# ID of search entry for project files
+ private variable project_search_clear_button ;# ID of button "Clear" on search panel -- project files
+ private variable project_files_highlighted_item {} ;# ID of currently highlighted item in project files
+ private variable project_files_hg_item_fg_clr {} ;# Fg. color of currently highlighted item in project files
+ private variable item_menu_invoked 0 ;# Bool: Item menu request
+ private variable editor_command_line_on 0 ;# Bool: Editor command line visible
+
+ private variable simulator_editor 0 ;# Int: Current file number (for simulator)
+ private variable file_switching_enabled 1 ;# Bool: Automatic file switching enabled
+ private variable simulator_editor_obj ;# Object: Code editor used by simulator
+
+ private variable active_page $::CONFIG(LEFT_PANEL_ACTIVE_PAGE) ;# Active page in the left panel
+ private variable PanelVisible $::CONFIG(LEFT_PANEL) ;# Bool: panel visible
+ private variable PanelSize $::CONFIG(LEFT_PANEL_SIZE) ;# Panel width (in pixels)
+
+ private variable editor_to_freeze_obj ;# Object: Editor to freeze after simulator startup
+ private variable filetabs_frm ;# Widget: Frame contaning the tab bar
+ private variable filetabs_nb ;# Widget: Tab bar's notebook widget
+
+ ## PROTECTED
+ protected variable file_count 0 ;# counter of opened files
+ protected variable editor_wdgs {} ;# list of editor widgets
+ protected variable file_descriptors {} ;# list of descriptors of opened files
+ protected variable file_eol {} ;# List of EOLs for opened editors
+ protected variable file_encoding {} ;# List of encodings for opened editors
+ protected variable file_ro_mode {} ;# List of read only flags for opened editors
+ protected variable file_sh {} ;# List of syntax highlight id's for opened editors
+
+ ## object constructor
+ constructor {} {
+ # increment instance counter
+ incr count
+ set obj_idx $count
+ }
+
+ ## Object destructor
+ destructor {
+ # Destroy editors
+ foreach editor $editors {
+ delete object $editor
+ }
+ # Unregister status bar tips for popup menus
+ menu_Sbar_remove $opened_files_menu
+ menu_Sbar_remove $project_files_menu
+ menu_Sbar_remove $filetabs_pu_menu
+ }
+
+ ## Initialize GUI components
+ # @parm String parentPane - Identifier of pane window in which it shoul be packed
+ # @parm String projectDir - Directory of current project
+ # @parm List filelist - List of files to open (full filenames including path)
+ # @parm Bool editor_sw_lock - Enable aoutomatic file switching during simulation
+ # @return void
+ public method initiate_FileList {parentPane projectDir FileList editor_sw_lock} {
+
+ # Object variables
+ set parent $parentPane ;# ID of parent container widget
+ set ProjectDir $projectDir ;# Reference to directory of actual project
+ set file_switching_enabled $editor_sw_lock
+
+ # Class variables
+ set filelist $FileList ;# List of files to open
+
+ # Create notebook frame
+ set leftPanel [frame $parentPane.frm_FileList_leftPanel]
+ # Create notebook
+ set notebook [NoteBook $leftPanel.nb_FileList \
+ -side top -arcradius 4 -bg {#EEEEEE} \
+ ]
+ # Create tab "Hide"
+ $notebook insert end "button_SH" -image ::ICONS::16::2leftarrow \
+ -raisecmd "$this filelist_show_hide" \
+ -helptext [mc "Hide this panel"]
+ # Create tab for list of opened files
+ set listbox_opened_files_frame [$notebook insert end "opened_files" \
+ -image ::ICONS::16::fileopen \
+ -raisecmd "$this Left_panel_set_active_page opened_files" \
+ -helptext [mc "Opened files"] \
+ ]
+ # Create tab for list of project files
+ set listbox_project_files_frame [$notebook insert end "project_files" \
+ -image ::ICONS::16::project_open \
+ -raisecmd "$this Left_panel_set_active_page project_files" \
+ -helptext [mc "Files in the project"] \
+ ]
+ # Create tab for file system browser
+ set fs_browser_frame [$notebook insert end "fs_browser" \
+ -image ::ICONS::16::exec \
+ -raisecmd "$this Left_panel_set_active_page fs_browser" \
+ -helptext [mc "Filesystem browser"] \
+ -createcmd [list $this CreateFSBrowserGUI] \
+ ]
+ # Create tab for SFR watches
+ set sfr_watches_frame [$notebook insert end "sfr_watches" \
+ -image ::ICONS::16::kcmmemory \
+ -raisecmd "$this Left_panel_set_active_page sfr_watches" \
+ -helptext [mc "List of SFR's"] \
+ -createcmd [list $this CreateSFRWatchesGUI] \
+ ]
+
+ # Prepare panel componenets but do not create GUI elements
+ PrepareFSBrowser $fs_browser_frame
+ PrepareSFRWatches $sfr_watches_frame
+
+
+ # Register notebook status bar tips
+ notebook_Sbar_set {filelist} [list \
+ button_SH [mc "Hide the panel"] \
+ opened_files [mc "Opended files"] \
+ project_files [mc "Files of the current project"] \
+ fs_browser [mc "Filesystem browser"] \
+ sfr_watches [mc "Special Function Registers"] \
+ ]
+ $notebook bindtabs <Enter> "notebook_Sbar filelist"
+ $notebook bindtabs <Leave> "Sbar {} ;#"
+
+ # Create listbox of opened files
+ set lsbox_frame [frame $listbox_opened_files_frame.lsbox_frame]
+ set listbox_opened_files_bm [text $lsbox_frame.icon_border \
+ -font $icon_border_font \
+ -cursor left_ptr \
+ -width 2 \
+ -bd 0 \
+ -pady 1 \
+ -highlightthickness 0 \
+ -bg {#DDDDDD} \
+ -exportselection 0 \
+ -takefocus 0 \
+ -cursor hand1 \
+ ]
+ $listbox_opened_files_bm tag configure center -justify center
+ $listbox_opened_files_bm delete 1.0 end
+ setStatusTip -widget $listbox_opened_files_bm \
+ -text [mc "Bookmarks for opened files"]
+ set listbox_opened_files [ListBox $lsbox_frame.listbox_opened_files \
+ -selectmode single -selectfill 0 -bg white \
+ -selectbackground white -highlightcolor {#BBBBFF} \
+ -selectforeground {#0000FF} -bd 1 \
+ -highlightthickness 0 -deltay 15 -padx 14 \
+ -yscrollcommand "$this filelist_o_scrollbar_set" \
+ ]
+ setStatusTip -widget $listbox_opened_files \
+ -text [mc "List of opened files"]
+ set opened_files_scrollbar [ttk::scrollbar \
+ $lsbox_frame.scrollbar \
+ -orient vertical \
+ -command "$this filelist_o_scroll" \
+ ]
+
+ # Create popup menu for icon border
+ set IB_o_menu $listbox_opened_files_bm.ib_o_menu
+ menuFactory $OPENEDFILESIBMENU $IB_o_menu 0 "$this " 0 {}
+
+ # Create bottom frame
+ set listbox_opened_files_bottom_frame [frame $listbox_opened_files_frame.bottom_frame]
+ set listbox_opened_files_bottom0_frame [frame $listbox_opened_files_bottom_frame.top]
+ set listbox_opened_files_bottom1_frame [frame $listbox_opened_files_bottom_frame.bottom]
+ # Create search panel
+ set opened_search_entry [ttk::entry $listbox_opened_files_bottom0_frame.entry \
+ -validatecommand "$this filelist_opened_search %P" \
+ -validate all \
+ -width 0 \
+ ]
+ DynamicHelp::add $opened_search_entry -text [mc "Search for file"]
+ setStatusTip -widget $opened_search_entry \
+ -text [mc "Search for certain file name in list of opened files"]
+ pack $opened_search_entry -side left -fill x -expand 1
+ set opened_search_clear_button [ttk::button \
+ $listbox_opened_files_bottom0_frame.clear_button \
+ -command "$opened_search_entry delete 0 end" \
+ -image ::ICONS::16::clear_left \
+ -state disabled \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $listbox_opened_files_bottom0_frame.clear_button -text [mc "Clear search entry box"]
+ setStatusTip -widget $opened_search_clear_button \
+ -text [mc "Clear search entry box"]
+ pack $opened_search_clear_button -side right -after $opened_search_entry
+ # Create buttons "Previous" and "Next"
+ set prev_editor_button [ttk::button \
+ $listbox_opened_files_bottom1_frame.prev \
+ -command {::X::__prev_editor} \
+ -image ::ICONS::16::1leftarrow \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $listbox_opened_files_bottom1_frame.prev \
+ -text [mc "Previous editor"]
+ pack $prev_editor_button -side left
+ setStatusTip -widget $prev_editor_button \
+ -text [mc "Switch to the previous editor"]
+ set next_editor_button [ttk::button \
+ $listbox_opened_files_bottom1_frame.next \
+ -command {::X::__next_editor} \
+ -image ::ICONS::16::1rightarrow \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $listbox_opened_files_bottom1_frame.next \
+ -text [mc "Next editor"]
+ pack $next_editor_button -side left
+ setStatusTip -widget $next_editor_button \
+ -text [mc "Switch to the next editor"]
+
+ # Frame for opened files
+ set listbox_opened_files_top_frame [frame \
+ $listbox_opened_files_frame.listbox_opened_files_top_frame]
+ # Button box for "Opened files"
+ set opened_files_buttonBox [frame \
+ $listbox_opened_files_top_frame.opened_files_buttonBox]
+ # Pages managers for editor(s), etc.
+ set main_frame [frame $parentPane.main_frame]
+
+ # Create filetabs notebook
+ set filetabs_frm [frame $main_frame.filetabs_frm -height 16]
+ pack [ttk::button $filetabs_frm.add_button \
+ -image ::ICONS::16::filenew \
+ -command {::X::__new} \
+ -style Flat.TButton \
+ ] -side left
+ set filetabs_nb [NoteBook $filetabs_frm.filetabs_nb \
+ -side top -arcradius 4 -bg {#EEEEEE} \
+ -font [font create -family {Helvetica} -size -12] \
+ ]
+ pack configure $filetabs_nb.c -fill x -expand 0
+ pack $filetabs_nb -fill x -anchor sw -side left -expand 1
+ $filetabs_nb bindtabs <Enter> "$this file_details_win_create_from_ftnb"
+ $filetabs_nb bindtabs <Leave> "$this file_details_win_hide"
+ $filetabs_nb bindtabs <Motion> "$this file_details_win_move"
+ $filetabs_nb bindtabs <ButtonRelease-3> "$this filetabs_nb_popup_menu %X %Y"
+ pack [ttk::button $filetabs_frm.close_button \
+ -image ::ICONS::16::fileclose \
+ -command {::X::__close} \
+ -style Flat.TButton \
+ ] -side right
+
+ set multiview_paned_win [panedwindow \
+ $main_frame.multiview_paned_win \
+ -sashwidth 2 \
+ -showhandle 0 \
+ -opaqueresize 1 \
+ -sashrelief flat \
+ ]
+ set pagesManager [frame $main_frame.pagesManager]
+ set pagesManager2 [frame $main_frame.pagesManager2]
+
+ # Create icon bar for "Opened files"
+ iconBarFactory $opened_files_buttonBox "$this " \
+ [string range $opened_files_buttonBox 1 end] ::ICONS::16:: {
+ {bookmark "Bookmark" {bookmark_add} {filelist_o_bookmark}
+ "Add/Remove bookmark"}
+ {separator}
+ {up "Move file up" {1uparrow} {filelist_move_up}
+ "Move selected file up in the list"}
+ {down "Move file down" {1downarrow} {filelist_move_down}
+ "Move selected file down in the list"}
+ {top "Move item to top" {top} {filelist_move_top}
+ "Move selected file to the top of the list"}
+ {bottom "Move item to bottom" {bottom} {filelist_move_bottom}
+ "Move selected file to the bottom of the list"}
+ }
+
+ # Pack GUI components of tab "Opened files"
+ pack $opened_files_buttonBox -side left
+ pack $listbox_opened_files_top_frame -side top -anchor w
+ pack $listbox_opened_files_bottom1_frame -side top
+ pack $listbox_opened_files_bottom0_frame -side top -fill x
+ pack $listbox_opened_files_bottom_frame -side bottom -fill x -pady 3
+ pack $lsbox_frame -side top -anchor nw -fill both -expand 1
+ pack $listbox_opened_files -side right -fill both -expand 1
+ pack $listbox_opened_files_bm -before $listbox_opened_files -fill y -side left
+
+ # Create list of project files
+ set ls_frame [frame $listbox_project_files_frame.ls_frame]
+ set listbox_project_files_bm [text $ls_frame.icon_border \
+ -font $icon_border_font \
+ -cursor left_ptr \
+ -width 2 \
+ -bd 0 \
+ -pady 1 \
+ -highlightthickness 0 \
+ -bg {#DDDDDD} \
+ -exportselection 0 \
+ -takefocus 0 \
+ -cursor hand1 \
+ ]
+ $listbox_project_files_bm delete 1.0 end
+ $listbox_project_files_bm tag configure center -justify center
+ setStatusTip -widget $listbox_project_files_bm \
+ -text [mc "Bookmarks for project files"]
+ set listbox_project_files [ListBox $ls_frame.listbox_project_files \
+ -selectmode single -highlightthickness 0 -bd 1 -padx 0 \
+ -selectbackground white -bg white -deltay 15 \
+ -selectforeground {#0000FF} -highlightcolor {#BBBBFF} \
+ -yscrollcommand "$this filelist_p_scrollbar_set" \
+ ]
+ setStatusTip -widget $listbox_project_files \
+ -text [mc "List of project files"]
+ set project_files_scrollbar [ttk::scrollbar \
+ $ls_frame.scrollbar \
+ -orient vertical \
+ -command "$this filelist_p_scroll" \
+ ]
+
+ # Create popup menu for icon border
+ set IB_p_menu $listbox_project_files.ib_o_menu
+ menuFactory $PROJECTFILESIBMENU $IB_p_menu 0 "$this " 0 {}
+
+ # Create search panel
+ set search_panel [frame $listbox_project_files_frame.search_panel]
+ set project_search_entry [ttk::entry $search_panel.entry \
+ -validatecommand "$this filelist_project_search %P" \
+ -validate all \
+ -width 0 \
+ ]
+ DynamicHelp::add $project_search_entry -text [mc "Search for file"]
+ setStatusTip -widget $project_search_entry \
+ -text [mc "Search for certain file name in list of project files"]
+ pack $project_search_entry -side left -fill x -expand 1
+ set project_search_clear_button [ttk::button \
+ $search_panel.clear_button \
+ -command "$project_search_entry delete 0 end" \
+ -image ::ICONS::16::clear_left \
+ -state disabled \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $search_panel.clear_button \
+ -text [mc "Clear search entry box"]
+ setStatusTip -widget $project_search_clear_button \
+ -text [mc "Clear search entry box"]
+ pack $project_search_clear_button -side right -after $project_search_entry
+
+ # Create header (label and icon bar) for tab "Project files"
+ set topFrame [frame $listbox_project_files_frame.listbox_project_files_top_frame]
+ pack [label $topFrame.listbox_project_files_label \
+ -text [mc "Project files:"] -anchor w \
+ ] -fill x -side top -anchor w -pady 5
+ set project_files_buttonBox [frame $topFrame.listbox_project_files_buttonBox]
+ pack $project_files_buttonBox -side bottom -anchor w -expand 0
+
+ # Create icon bar for tab "Project files"
+ iconBarFactory $project_files_buttonBox "$this " \
+ [string range $project_files_buttonBox 1 end] ::ICONS::16:: {
+ {bookmark "Bookmark" {bookmark_add}
+ {filelist_p_bookmark}
+ "Add/Remove bookmark"}
+ {separator}
+ {open "Open this file" {fileopen}
+ {filelist_project_file_open}
+ "Open this file and create its own editor"}
+ {close "Close this file" {fileclose}
+ {filelist_project_file_close}
+ "Close this file and close its editor"}
+ {separator}
+ {remove "Remove this file from the project" {editdelete}
+ {filelist_remove_file_from_project}
+ "Exclude this file from list of files of this project"}
+ }
+
+ # Evaluate icon bars button states (tab "Project files")
+ FileList_project_disEna_buttons
+
+ # Pack frames of tab "Projet files"
+ pack $topFrame -fill x -side top -anchor w
+ pack $listbox_project_files -fill both -expand 1 -side right
+ pack $listbox_project_files_bm -before $listbox_project_files -fill y -side left
+ pack $search_panel -side bottom -fill x
+ pack $ls_frame -fill both -expand 1 -side top
+
+ ## Create button bar
+ set button_bar [frame $leftPanel.button_bar]
+ # Button "Show"
+ pack [ttk::button $button_bar.but_show \
+ -image ::ICONS::16::2rightarrow \
+ -command "$this filelist_show_hide" \
+ -style ToolButton.TButton \
+ ]
+ DynamicHelp::add $button_bar.but_show -text [mc "Show the panel"]
+ setStatusTip -widget $button_bar.but_show \
+ -text [mc "Show the panel"]
+ # Separator
+ pack [ttk::separator $button_bar.sep -orient horizontal] -fill x -pady 2
+
+ # Button "Instruction details"
+ pack [ttk::button $button_bar.but_opened \
+ -image ::ICONS::16::fileopen \
+ -style ToolButton.TButton \
+ -command "$this filelist_show_up opened_files" \
+ ]
+ DynamicHelp::add $button_bar.but_opened -text [mc "Currently opened files"]
+ setStatusTip -widget $button_bar.but_opened \
+ -text [mc "Currently opened files"]
+ # Button "opened files"
+ pack [ttk::button $button_bar.but_proj_open \
+ -image ::ICONS::16::project_open \
+ -style ToolButton.TButton \
+ -command "$this filelist_show_up project_files" \
+ ]
+ DynamicHelp::add $button_bar.but_proj_open -text [mc "Files in the current project"]
+ setStatusTip -widget $button_bar.but_proj_open \
+ -text [mc "Files of the current project"]
+ # Button "Filesystem browser"
+ pack [ttk::button $button_bar.but_fs_browser \
+ -image ::ICONS::16::exec \
+ -style ToolButton.TButton \
+ -command "$this filelist_show_up fs_browser" \
+ ]
+ DynamicHelp::add $button_bar.but_fs_browser -text [mc "Filesystem browser"]
+ setStatusTip -widget $button_bar.but_fs_browser \
+ -text [mc "Filesystem browser"]
+ # Button "SFR watches"
+ pack [ttk::button $button_bar.but_sfr_watches \
+ -image ::ICONS::16::kcmmemory \
+ -style ToolButton.TButton \
+ -command "$this filelist_show_up sfr_watches" \
+ ]
+ DynamicHelp::add $button_bar.but_sfr_watches -text [mc "SFR watches"]
+ setStatusTip -widget $button_bar.but_sfr_watches \
+ -text [mc "SFR watches"]
+
+ # Show the left panel
+ if {$PanelVisible != 0} {
+ pack $notebook -expand 1 -fill both
+
+ # Raise active page in the panel notebook
+ catch {
+ $notebook raise $active_page
+ }
+ } {
+ set last_sash $PanelSize
+ pack $button_bar -side top -anchor nw
+ }
+
+ # Insert left panel and editor pages manager into parent pane window
+ $parentPane add $leftPanel
+ $parentPane add $main_frame
+
+ # Set bindings for file lists
+ $listbox_opened_files bindText <ButtonRelease-3> "$this fileList_opened_filelist_item_popup %X %Y"
+ $listbox_opened_files bindText <Enter> "$this file_details_win_create O"
+ $listbox_opened_files bindText <Leave> "$this file_details_win_hide"
+ $listbox_opened_files bindText <Motion> "$this file_details_win_move"
+ bind $listbox_opened_files <<ListboxSelect>> "$this switchfile; break"
+ if {[winfo exists $listbox_opened_files.c]} {
+ bind $listbox_opened_files.c <Button-5> {%W yview scroll +5 units; break}
+ bind $listbox_opened_files.c <Button-4> {%W yview scroll -5 units; break}
+ bind $listbox_opened_files.c <ButtonRelease-3> "$this fileList_opened_filelist_popup %X %Y"
+ }
+
+ bind $listbox_opened_files_bm <<Selection>> "false_selection $listbox_opened_files_bm"
+ bind $listbox_opened_files_bm <Button-1> "$this filelist_opened_bookmark_xy %x %y"
+ bind $listbox_opened_files_bm <ButtonRelease-3> "$this filelist_opened_bm_popup_menu %X %Y %x %y"
+ bindtags $listbox_opened_files_bm $listbox_opened_files_bm
+
+ $listbox_project_files bindText <ButtonRelease-3> "$this fileList_project_filelist_item_popup %X %Y"
+ $listbox_project_files bindText <Double-Button-1> "$this filelist_project_file_open"
+ $listbox_project_files bindText <Enter> "$this file_details_win_create P"
+ $listbox_project_files bindText <Leave> "$this file_details_win_hide"
+ $listbox_project_files bindText <Motion> "$this file_details_win_move"
+ bind $listbox_project_files <<ListboxSelect>> "$this project_files_listbox_select"
+ if {[winfo exists $listbox_project_files.c]} {
+ bind $listbox_project_files.c <Button-5> {%W yview scroll +5 units; break}
+ bind $listbox_project_files.c <Button-4> {%W yview scroll -5 units; break}
+ bind $listbox_project_files.c <ButtonRelease-3> "$this fileList_project_filelist_popup %X %Y"
+ }
+
+ bind $listbox_project_files_bm <<Selection>> "false_selection $listbox_project_files_bm"
+ bind $listbox_project_files_bm <Button-1> "$this filelist_project_bookmark_xy %x %y"
+ bind $listbox_project_files_bm <ButtonRelease-3> "$this filelist_project_bm_popup_menu %X %Y %x %y"
+ bindtags $listbox_project_files_bm $listbox_project_files_bm
+
+ # Create popup menus
+ set opened_files_menu $listbox_opened_files.opened_files_menu
+ set project_files_menu $listbox_project_files.project_files_menu
+ set filetabs_pu_menu $filetabs_nb.filetabs_pu_menu
+ filelist_makePopupMenu
+
+ # Create Editor object for each file in $filelist and insert it into ListBox of opened files
+ open_files $filelist
+
+ # Initialize list of opened files
+ set actualEditor [lindex $filelist {1 0}]
+ set actualEditor2 [lindex $filelist {1 1}]
+ set multiview_sash_pos [lindex $filelist {1 2}]
+ set pwin_orient [lindex $filelist {1 3}]
+
+ ## Validate index of current editor(s)
+ if {
+ ![string is digit -strict $actualEditor]
+ ||
+ ($actualEditor >= [llength $editors])
+ ||
+ ($actualEditor < 0)
+ } then {
+ set actualEditor $actualEditor2
+ set splitted 0
+ }
+ if {
+ ![string is digit -strict $actualEditor2]
+ ||
+ ($actualEditor2 >= [llength $editors])
+ ||
+ ($actualEditor2 < 0)
+ ||
+ ($actualEditor2 == $actualEditor)
+ } then {
+ set actualEditor2 -1
+ set splitted 0
+ } else {
+ set splitted 1
+ }
+
+ ## Validate index of current editor in the first view
+ if {
+ [string is digit -strict $actualEditor]
+ &&
+ $actualEditor < [llength $editors]
+ &&
+ $actualEditor >= 0
+ } { ;# Valid value
+ $listbox_opened_files selection set [lindex [$listbox_opened_files items] $actualEditor]
+ set actualEditor -1
+ switchfile
+
+ } else { ;# Invalid value
+ set actualEditor -1
+ if {![llength $editors]} {
+ editor_new
+ } {
+ $listbox_opened_files selection set [lindex [$listbox_opened_files items] 0]
+ switchfile
+ }
+ }
+
+ # Validate selected view, sash orient and sash position
+ set selectedView [lindex $filelist {1 4}]
+ if {![string is bool -strict $selectedView]} {
+ set selectedView 0
+ }
+ if {$pwin_orient != {horizontal} && $pwin_orient != {vertical}} {
+ set pwin_orient {horizontal}
+ }
+ if {![string is digit -strict $multiview_sash_pos] || $multiview_sash_pos < 0} {
+ set multiview_sash_pos 0
+ }
+
+ # Pack editor pages manager
+ if {$splitted} {
+ pack $multiview_paned_win -fill both -expand 1
+ $multiview_paned_win configure -orient $pwin_orient
+ $multiview_paned_win add $pagesManager
+ $multiview_paned_win add $pagesManager2 -after $pagesManager
+
+ if {$pwin_orient == {vertical}} {
+ if {!$multiview_sash_pos} {
+ set multiview_sash_pos [expr {[winfo width $pagesManager] / 2}]
+ }
+ set minsize 300
+ } {
+ if {!$multiview_sash_pos} {
+ set multiview_sash_pos [expr {[winfo height $pagesManager] / 2}]
+ }
+ set minsize 80
+ }
+ $multiview_paned_win paneconfigure $pagesManager -minsize $minsize
+ $multiview_paned_win paneconfigure $pagesManager2 -minsize $minsize
+ pack [[lindex $editors $actualEditor2] cget -ed_sc_frame] \
+ -in $pagesManager2 -fill both -expand 1
+ } {
+ pack $pagesManager -fill both -expand 1
+ }
+ foreach editor $editors {
+ $editor configure_statusbar_menu !$splitted $splitted {} {}
+ }
+
+ # Set panel width
+ update idle
+ if {$PanelVisible != 0} {
+ $parent paneconfigure $leftPanel -minsize 155
+ $parent configure -sashwidth 2
+ $parent sash place 0 $PanelSize 0
+ } {
+ $parent paneconfigure $leftPanel -minsize 0
+ $parent configure -sashwidth 0
+ $parent sash place 0 25 2
+ bind $parent <Button> {break}
+ }
+ bind $parent <ButtonRelease-1> "$this left_panel_set_size"
+
+ # Update multiview sash position
+ if {$splitted} {
+ update idle
+ if {$pwin_orient == {vertical}} {
+ $multiview_paned_win sash place 0 0 $multiview_sash_pos
+ } {
+ $multiview_paned_win sash place 0 $multiview_sash_pos 0
+ }
+ }
+
+ show_hide_tab_bar
+ }
+
+ ## Prepare window file details
+ # @parm Char for - '0' == ListBox of opened files; 'P' == ListBox of project files
+ # @parm String item - Item ID
+ # @return void
+ public method file_details_win_create {for item} {
+ set filedetails_visible 0
+
+ set note {}
+
+ # Determinate full filename
+ if {$for == {O}} {
+ if {![$listbox_opened_files exists $item]} {
+ return
+ }
+ set shortname [$listbox_opened_files itemcget $item -text]
+ set filename [$listbox_opened_files itemcget $item -data]
+ set index [$listbox_opened_files index $item]
+ set encoding [lindex $file_encoding $index]
+ set eol [lindex $file_eol $index]
+ set read_only [lindex $file_ro_mode $index]
+ regexp -line -- {^.*$} [$this get_file_notes_data $index] note
+ } {
+ if {![$listbox_project_files exists $item]} {
+ return
+ }
+ set shortname [$listbox_project_files itemcget $item -text]
+ set data [$listbox_project_files itemcget $item -data]
+ if {[llength $data] < 5} {
+ set filename [lindex $data 0]
+ set eol [lindex $data 1]
+ set encoding [lindex $data 2]
+ set read_only [lindex $data 3]
+ } {
+ set filename "[lindex $data 5][lindex $data 0]"
+ set eol [lindex $data 8]
+ set encoding [lindex $data 9]
+ set read_only [lindex $data 2]
+ }
+ }
+
+ # Skip untitled files
+ if {$filename == {}} {return}
+
+ # Destroy previous window
+ catch {after cancel $filedetails_after_ID}
+ catch {destroy ${::FILEDETAILSWIN}}
+
+ # Create window
+ set ::FILEDETAILSWIN [frame .file_details_win -bg {#AADDFF}]
+ set file_details_win [frame ${::FILEDETAILSWIN}.frm -bg {#FFFFFF}]
+ bind ${::FILEDETAILSWIN} <Button-1> "catch {destroy ${::FILEDETAILSWIN}}"
+
+ # Determinate file type and set appropriate icon
+ set ext [string trimleft [file extension $filename] {.}]
+ if {$ext == {h}} {
+ set icon {source_h}
+ } elseif {$ext == {c}} {
+ set icon {source_c}
+ } elseif {$ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set icon {source_cpp}
+ } elseif {$ext == {asm}} {
+ set icon {asm}
+ } else {
+ set icon {ascii}
+ }
+
+ # Create header
+ set header [frame $file_details_win.header -bg {#AADDFF}]
+ pack [label $header.header \
+ -bg {#AADDFF} -text $shortname \
+ -justify left -pady 0 -padx 15 \
+ -compound left -anchor w \
+ -image ::ICONS::16::$icon \
+ ] -side left
+ if {$read_only == 1} {
+ pack [label $header.ro_text \
+ -bg {#AADDFF} -fg {#FF3333} \
+ -text [mc "(read only)"] \
+ -justify left -pady 0 \
+ ] -side left
+ }
+ pack $header -fill x
+
+ # Show error message if the file dosn't exist
+ if {![file exists $filename]} {
+ pack [label $file_details_win.message_label \
+ -text [mc "File does not exist"] \
+ -fg {#FF0000} \
+ ] -padx 80 -pady 40
+ catch {after cancel $filedetails_after_ID}
+ set filedetails_after_ID [after 750 "
+ set ::FileList::filedetails_visible 1
+ $this file_details_win_move"]
+ return
+ }
+
+ # Determinate informations about the file
+ set size [file size $filename] ;# Size in B
+ set mtime [file mtime $filename] ;# Modification time
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set perms [file attributes $filename] ;# Owner - Group - Permissions
+ }
+
+ # Adjust the informations aboth the file
+ set mtime [clock format $mtime -format {%D %R}]
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set owner "[lindex $perms 1] - [lindex $perms 3]"
+ set perms [lindex $perms 5]
+ set perms [string range $perms {end-3} end]
+ }
+ if {[enc2name $encoding] != {}} {
+ if {[string length $encoding] < 8} {
+ append encoding "\t"
+ }
+ append encoding "\t(" [enc2name [string trimright $encoding]] {)}
+ }
+ if {$size < 1024} {
+ append size { B}
+ } {
+ set kB [expr {$size / 1024}]
+ set B [expr {$size % 1024}]
+ set MB [expr {$kB / 1024}]
+ set kB [expr {$kB % 1024}]
+
+ set original_size $size
+ set size {}
+ if {$MB} {
+ append size $MB { MB }
+ }
+ if {$kB} {
+ append size $kB { kB }
+ }
+ if {$B} {
+ append size $B { B }
+ }
+ append size {(} $original_size { B)}
+ }
+ switch -- $eol {
+ {lf} {set eol "Unix\t\t(LF)"}
+ {crlf} {set eol "DOS\t\t(CRLF)"}
+ {cr} {set eol "Macintosh\t(CR)"}
+ }
+
+ # Create main frame (containing everything except the header)
+ set main_frame [frame $file_details_win.main_frame -bg {#FFFFFF}]
+
+ # Path
+ grid [label $main_frame.path_label \
+ -text [mc "Path:"] \
+ -fg {#0000AA} \
+ -anchor w -bg {#FFFFFF} \
+ ] -row 0 -column 0 -sticky w -pady 0
+ grid [label $main_frame.path_value \
+ -text [file dirname $filename] \
+ -anchor w -bg {#FFFFFF} \
+ ] -row 0 -column 1 -sticky w -pady 0
+
+ # Size
+ grid [label $main_frame.size_label \
+ -text [mc "Size:"] \
+ -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 1 -column 0 -sticky w -pady 0
+ grid [label $main_frame.size_value \
+ -text $size -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 1 -column 1 -sticky w -pady 0
+
+ # Modified
+ grid [label $main_frame.modified_label \
+ -text [mc "Modified:"] \
+ -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 2 -column 0 -sticky w -pady 0
+ grid [label $main_frame.modified_value \
+ -text $mtime -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 2 -column 1 -sticky w -pady 0
+
+ # Owner
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ grid [label $main_frame.owner_label \
+ -text [mc "Owner:"] \
+ -fg {#0000AA} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 3 -column 0 -sticky w -pady 0
+ grid [label $main_frame.owner_value \
+ -text $owner -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 3 -column 1 -sticky w -pady 0
+
+ # Permissions
+ grid [label $main_frame.perms_label \
+ -text [mc "Permissions:"] \
+ -fg {#0000AA} -bg {#FFFFFF} \
+ -anchor w -pady 0 \
+ ] -row 4 -column 0 -sticky w -pady 0
+ grid [label $main_frame.perms_value \
+ -text $perms -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 4 -column 1 -sticky w -pady 0
+ }
+
+ if {!${::Editor::editor_to_use}} {
+ # Separator
+ grid [ttk::separator $main_frame.sep \
+ -orient horizontal \
+ ] -row 5 -column 0 -columnspan 2 -sticky we -pady 0
+
+ # Encoding
+ grid [label $main_frame.enc_label \
+ -text [mc "Encoding:"] \
+ -fg {#880033} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 6 -column 0 -sticky w -pady 0
+ grid [label $main_frame.enc_value \
+ -text $encoding -anchor w \
+ -pady 0 -bg {#FFFFFF} \
+ ] -row 6 -column 1 -sticky w -pady 0
+
+ # EOL
+ grid [label $main_frame.eol_label \
+ -text [mc "EOL:"] -fg {#880033} \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 7 -column 0 -sticky w -pady 0
+ grid [label $main_frame.eol_value \
+ -text $eol -anchor w -pady 0 -bg {#FFFFFF} \
+ ] -row 7 -column 1 -sticky w -pady 0
+ }
+
+ # User note
+ if {$note != {} && $for == {O}} {
+ set w_max 350
+ set w [font measure ${::Todo::normal_font} $note]
+
+ if {$w > $w_max} {
+ set note [string range $note 0 [expr {int([string length $note] * $w_max/$w * 0.7)}]]
+ append note {...}
+ }
+
+ # Separator
+ grid [ttk::separator $main_frame.sep1 \
+ -orient horizontal \
+ ] -row 8 -column 0 -columnspan 2 -sticky we -pady 0
+ grid [label $main_frame.notes_value \
+ -anchor w -pady 0 -bg {#FFFFFF} \
+ -text $note -font ${::Todo::normal_font} \
+ -justify left -anchor w -wraplength $w_max \
+ ] -row 9 -column 0 -sticky w -pady 0 -columnspan 2
+ }
+
+ # Pack main frame
+ grid columnconfigure $main_frame 0 -minsize 90
+ pack $main_frame -fill both -expand 1 -padx 8 -pady 3
+ pack $file_details_win -fill both -expand 1 -padx 2 -pady 2
+
+ # After 750 ms show the window
+ catch {after cancel $filedetails_after_ID}
+ set filedetails_after_ID [after 750 "
+ set ::FileList::filedetails_visible 1
+ $this file_details_win_move"]
+ }
+
+ ## Move window "File details"
+ # @return void
+ public method file_details_win_move args {
+ # Abort if the window isn't visible
+ if {!$filedetails_visible} {return}
+
+ # Show the window
+ catch {
+ place ${::FILEDETAILSWIN} -anchor nw \
+ -x [expr {[winfo pointerx .] - [winfo rootx .] + 20}] \
+ -y [expr {[winfo pointery .] - [winfo rooty .] + 20}]
+ update
+ raise ${::FILEDETAILSWIN}
+ }
+ }
+
+ ## Hide window "File details"
+ # @return void
+ public method file_details_win_hide args {
+ set filedetails_visible 0 ;# Bool: Is file details window visible
+
+ # Hide window and cancel timeout
+ catch {after cancel $filedetails_after_ID}
+ catch {place forget ${::FILEDETAILSWIN}}
+ }
+
+ ## Define popup menus
+ # @return void
+ public method filelist_makePopupMenu {} {
+ if {[winfo exists $opened_files_menu]} {
+ destroy $opened_files_menu
+ }
+ if {[winfo exists $project_files_menu]} {
+ destroy $project_files_menu
+ }
+ if {[winfo exists $filetabs_pu_menu]} {
+ destroy $filetabs_pu_menu
+ }
+
+ menuFactory $PROJECTFILESMENU $project_files_menu 0 "$this " 0 {}
+ menuFactory $OPENEDFILESMENU $opened_files_menu 0 "$this " 0 {}
+ menuFactory $FILETABSPUMENU $filetabs_pu_menu 0 "$this " 0 {}
+
+ foreach program {gvim emacs kwrite gedit} \
+ program_name {gvim emacs kwrite gedit} \
+ {
+ if {!$::PROGRAM_AVALIABLE($program)} {
+ foreach menu [list $project_files_menu $opened_files_menu $filetabs_pu_menu] {
+ ${menu}.open_with entryconfigure [::mc $program_name] -state disabled
+ }
+ }
+ }
+ if {${::Editor::editor_to_use}} {
+ $opened_files_menu entryconfigure [::mc "Save"] -state disabled
+ $opened_files_menu entryconfigure [::mc "Save as"] -state disabled
+ $opened_files_menu entryconfigure [::mc "Save all"] -state disabled
+
+ $filetabs_pu_menu entryconfigure [::mc "Save"] -state disabled
+ $filetabs_pu_menu entryconfigure [::mc "Save as"] -state disabled
+ $filetabs_pu_menu entryconfigure [::mc "Save all"] -state disabled
+ }
+ }
+
+ ## Reload the current file
+ # @return Bool - result
+ public method filelist_reload_file {} {
+ if {$splitted && $selectedView} {
+ set editor_idx $actualEditor2
+ } {
+ set editor_idx $actualEditor
+ }
+ set editor [lindex $editors $editor_idx]
+
+ # Local variables
+ set fullFileName [$editor cget -fullFileName] ;# Full filename
+ set filename [$editor cget -filename] ;# Simple filename
+
+ if {
+ ![file exists $fullFileName] ||
+ [file isdirectory $fullFileName] ||
+ (!$::MICROSOFT_WINDOWS && ![file readable $fullFileName])
+ } {
+ tk_messageBox \
+ -title [mc "File not found"] \
+ -icon error \
+ -type ok \
+ -parent . \
+ -message [mc "The file selected for reload does not exist any more or it is not readable !"]
+ set fullFileName {}
+ }
+
+ if {$fullFileName != {}} {
+ # Prompt user is the file was modified
+ if {[$editor cget -modified] != 0} {
+ set response [tk_messageBox \
+ -title [mc "Are you sure ?"] \
+ -icon question \
+ -type yesno \
+ -parent . \
+ -message [mc "Reload of the file will change contents of the current editor. Are you sure you want that ?"] \
+ ]
+ if {$response != {yes}} {
+ Sbar [mc "Reload aborted"]
+ return 0
+ }
+ }
+
+ set enc [lindex $file_encoding $editor_idx]
+ set eol [lindex $file_eol $editor_idx]
+ set rom [lindex $file_ro_mode $editor_idx]
+ set sh [lindex $file_sh $editor_idx]
+
+ # Get number of the current line
+ set line [$editor get_current_line_number]
+ # Clear content of the current editor
+ if {[$editor cget -ro_mode]} {
+ [$editor cget -editor] configure -state normal
+ }
+ $editor clear_autocompletion_list
+ [$editor cget -editor] configure -autoseparators 0
+ [$editor cget -editor] delete 1.0 end
+ # Insert content of the file into the editor
+ set file [open $fullFileName r]
+ fconfigure $file -encoding $enc
+ set data {}
+ if {[regsub -all {[\u0000-\u0008\u000B-\u000C\u000E-\u001F\u007F-\u009F]} [read $file] {} data]} {
+ tk_messageBox -parent . \
+ -type ok -icon warning \
+ -title [mc "Binary File Opened - MCU 8015 IDE"] \
+ -message [mc "The file %s is binary, saving it will result corrupted file." $fullFileName]
+ }
+ [$editor cget -editor] insert end [regsub -all {\r\n?} $data "\n"]
+ if {[$editor cget -ro_mode]} {
+ [$editor cget -editor] configure -state disabled
+ }
+ close $file
+ $editor goto $line
+ [$editor cget -editor] edit separator
+ [$editor cget -editor] configure -autoseparators 1
+
+ # Set EOL and Encoding in ListBox of project files
+ foreach item [$listbox_project_files items] {
+ if {[$listbox_project_files itemcget $item -text] != $filename} {
+ continue
+ }
+ set data [$listbox_project_files itemcget $item -data]
+ if {[llength $data] > 5} {continue}
+ if {[lindex $data 0] != $fullFileName} {continue}
+ lset data 1 $eol
+ lset data 2 $enc
+ lset data 3 $rom
+ $listbox_project_files itemconfigure $item -data $data
+ }
+ }
+
+ # Reset status modified
+ [$editor cget -editor] edit modified 0
+ $editor recalc_status_modified 0
+ # Restore syntax highlight
+ rightPanel_clear_all_bookmarks
+ rightPanel_clear_all_breakpoints
+ rightPanel_clear_symbol_list
+ $editor parseAll
+
+ # Successful
+ return 1
+ }
+
+ ## Highlight all loaded source codes, import breakpoints and bookmarks etc.
+ # This function finalizes project initialization
+ # @return void
+ public method filelist_global_highlight {} {
+ # Class variables
+ set filelist [lreplace $filelist 0 1] ;# List of files to open (special format)
+
+ # Skip empty/invalid filelist
+ if {[lindex $filelist $actualEditor] == {}} {
+ rightPanel_enable
+ return
+ }
+
+ # Local variables
+ set ac $actualEditor ;# Number of actual editor
+ # Number of current line in the current editor
+ set ac_line [lindex $filelist [list $ac_index_in_fl 6]]
+
+ # Take care of the current editor
+ rightPanel_switch_editor_vars $ac
+ $this todo_switch_editor_vars $ac
+ [lindex $editors $ac] import_line_markers_data \
+ [lindex $filelist [list $ac_index_in_fl 9]] \
+ [lindex $filelist [list $ac_index_in_fl 10]]
+ [lindex $editors $ac] goto $ac_line
+
+ # Import bookmarks and breakpoints into all editors except the current one
+ set idx -1
+ set lines {}
+ foreach record $filelist {
+ # Skip closed files
+ if {[lindex $record 1] != {yes}} {continue}
+
+ # Detrminate file index
+ incr idx
+ set i [lindex $file_indexes $idx]
+ if {$i == {}} {
+ continue
+ }
+
+ # Skip current editor
+ if {$i == $ac} {
+ incr i
+ lappend lines $ac_line
+ continue
+ }
+ # Local variables
+ set editor [lindex $editors $i] ;# Reference to target editor object
+ set line [lindex $record 6] ;# Current line
+
+ # Adjust right panel
+ set actualEditor $i
+ rightPanel_switch_editor_vars $i
+ $this todo_switch_editor_vars $i
+ # Import bookmarks and breakpoints into editor
+ $editor import_line_markers_data \
+ [lindex $record 9] \
+ [lindex $record 10]
+ $editor goto $line
+ lappend lines $line
+ }
+
+ # Finalize
+ set filelist {}
+ set actualEditor $ac
+
+ # Adjust Right panel
+ rightPanel_enable
+ set i 0
+ foreach line $lines {
+ set editor [lindex $editors $i]
+ rightPanel_switch_editor_vars $i
+ $this todo_switch_editor_vars $i
+ $editor rightPanel_adjust $line
+ incr i
+ }
+ rightPanel_switch_editor $ac
+ $this todo_switch_editor $ac
+ if {${::ASMsyntaxHighlight::validation_L1}} {
+ [lindex $editors $actualEditor] parse_current_line
+ } {
+ [lindex $editors $actualEditor] adjust_instruction_details
+ }
+
+ set file_indexes {}
+ }
+
+ ## Switch from Normal mode to Simulator mode
+ # @return void
+ public method freeze {} {
+ # Set mode flag
+ set frozen 1
+ set simulator_editor_obj {}
+ set simulator_editor -1
+ # Freeze editor
+ if {$splitted && $selectedView} {
+ set editor_to_freeze $actualEditor2
+ } {
+ set editor_to_freeze $actualEditor
+ }
+ set idx 0
+ foreach editor $editors {
+ if {$idx == $editor_to_freeze} {
+ $editor freeze
+ set editor_to_freeze_obj $editor
+ } {
+ $editor disable
+ }
+ incr idx
+ }
+ FileList_project_disEna_buttons
+ # Disable some popupmenu items
+ foreach entry $freezable_menu_items {
+ $opened_files_menu entryconfigure [::mc $entry] -state disabled
+ }
+ $project_files_menu entryconfigure [::mc "Close file"] -state disabled
+ }
+
+ ## This method should be called immediately after simulator startup
+ #+ in order to inform editors about the change
+ # @return void
+ public method now_frozen {} {
+ $editor_to_freeze_obj now_frozen
+ }
+
+ ## Switch from Simulator mode to Normal mode
+ # @return void
+ public method thaw {} {
+ # Set mode flag
+ set frozen 0
+ # Thaw editors
+ foreach editor $editors {
+ $editor thaw
+ }
+ # Enable switching files
+ listBox_disEna_buttons \
+ [$listbox_opened_files selection get] \
+ [lindex $editors $actualEditor]
+ if {$splitted} {
+ listBox_disEna_buttons \
+ [$listbox_opened_files selection get] \
+ [lindex $editors $actualEditor]
+ }
+ # Enable some poupmenu items
+ foreach entry $freezable_menu_items {
+ $opened_files_menu entryconfigure [::mc $entry] -state normal
+ }
+ $project_files_menu entryconfigure [::mc "Close file"] -state normal
+
+ if {$simulator_editor_obj != {}} {
+ $listbox_opened_files itemconfigure [lindex \
+ $file_descriptors [lsearch -ascii -exact \
+ $editors $simulator_editor_obj \
+ ] \
+ ] -fg {#000000}
+ }
+ set simulator_editor_obj {}
+ }
+
+ ## Set variable containing ID of active page
+ # @parm String pageName - active page
+ # @return void
+ public method Left_panel_set_active_page {pageName} {
+ set active_page $pageName
+ }
+
+ ## Get mode flag
+ # @return Bool - current mode (1 == Simulation mode; 0 == Normal mode)
+ public method is_frozen {} {return $frozen}
+
+ ## Get current panel width
+ # @return Int - the width
+ public method getLeftPanelSize {} {
+ if {$PanelVisible} {
+ return $PanelSize
+ } {
+ return $last_sash
+ }
+ }
+
+ ## Set panel width acording to current sash position
+ # @return void
+ public method left_panel_set_size {} {
+ set PanelSize [lindex [$parent sash coord 0] 0]
+ }
+
+ ## Get ID of active page
+ # @return String - the active page
+ public method getLeftPanelActivePage {} {return $active_page}
+
+ ## Get value of panel visibility flag
+ # @return Bool - the flag (1 == Visible, 2 == Hidden)
+ public method isLeftPanelVisible {} {return $PanelVisible}
+
+ ## Show/Hide the left panel
+ # @return Bool - 1 == now displayed; 0 == now hidden
+ public method filelist_show_hide {} {
+ # Hide the panel
+ if {$PanelVisible} {
+ $parent paneconfigure $leftPanel -minsize 0
+
+ pack forget $notebook
+ # Show button bar
+ pack $button_bar -side top -anchor nw
+ # Move the paned window sash and remember current position
+ set last_sash [lindex [$parent sash coord 0] 0]
+ update idle
+ $parent sash place 0 25 2
+ # Hide the sash
+ bind $parent <Button> {break}
+ $parent configure -sashwidth 0
+ # done ...
+ set PanelVisible 0
+ return 0
+
+ # Show the panel
+ } {
+ $parent paneconfigure $leftPanel -minsize 155
+
+ $notebook raise $active_page
+ # Hide button bar
+ pack forget $button_bar
+ # Show the panel
+ pack $notebook -expand 1 -fill both
+ # Restore the paned window sash position to the previous state
+ update idle
+ $parent sash place 0 $last_sash 0
+ # Show the sash
+ bind $parent <Button> {}
+ $parent configure -sashwidth 2
+ # done ...
+ set PanelVisible 1
+ return 1
+ }
+ }
+
+ ## Change panel active page
+ # @parm String page - ID of the page to show
+ # @return void
+ public method filelist_show_up {page} {
+ if {!$PanelVisible} filelist_show_hide
+ $notebook raise $page
+ }
+
+ ## Move up currently selected item -- Opened files
+ # @return void
+ public method filelist_move_up {} {
+ # Local variables
+ set item [$listbox_opened_files selection get] ;# Item ID
+ set index [$listbox_opened_files index $item] ;# Item index
+ set target [expr {$index - 1}] ;# Target index
+
+ # 1st item cannot be moved up
+ if {$index == 0} {return}
+
+ # Move item in listbox
+ $listbox_opened_files move $item $target
+ # Move item in list of bookmarks and icon border
+ if {[lindex $opened_files_bookmarks $index] != [lindex $opened_files_bookmarks $target]} {
+ # Determinate bookmark flag for source and target index
+ set trg_bm [lindex $opened_files_bookmarks $target]
+ set idx_bm [lindex $opened_files_bookmarks $index]
+ # Move item in list of bookmarks
+ lset opened_files_bookmarks $target [lindex $opened_files_bookmarks $index]
+ lset opened_files_bookmarks $index $trg_bm
+ # Move item in icon border
+ incr target
+ incr index
+ $listbox_opened_files_bm delete $index.0 [list $index.0 lineend]
+ $listbox_opened_files_bm delete $target.0 [list $target.0 lineend]
+ if {$trg_bm} {
+ $listbox_opened_files_bm image create $index.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ if {$idx_bm} {
+ $listbox_opened_files_bm image create $target.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ }
+
+ # Reevaluate button states on icon bar
+ listBox_disEna_buttons $item [lindex $editors [lsearch $file_descriptors $item]]
+ }
+
+ ## Move down currently selected item -- Opened files
+ # @return void
+ public method filelist_move_down {} {
+ # Local variables
+ set item [$listbox_opened_files selection get] ;# Item ID
+ set index [$listbox_opened_files index $item] ;# Item index
+ set target [expr {$index + 1}] ;# Target index
+
+ # Last item cannot be moved up
+ if {[llength [$listbox_opened_files items]] == $index} {return}
+
+ # Move item in listbox
+ $listbox_opened_files move $item $target
+ # Move item in list of bookmarks and icon border
+ if {[lindex $opened_files_bookmarks $index] != [lindex $opened_files_bookmarks $target]} {
+ # Determinate bookmark flag for source and target index
+ set trg_bm [lindex $opened_files_bookmarks $target]
+ set idx_bm [lindex $opened_files_bookmarks $index]
+ # Move item in list of bookmarks
+ lset opened_files_bookmarks $target [lindex $opened_files_bookmarks $index]
+ lset opened_files_bookmarks $index $trg_bm
+ # Move item in icon border
+ incr target
+ incr index
+ $listbox_opened_files_bm delete $index.0 [list $index.0 lineend]
+ $listbox_opened_files_bm delete $target.0 [list $target.0 lineend]
+ if {$trg_bm} {
+ $listbox_opened_files_bm image create $index.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ if {$idx_bm} {
+ $listbox_opened_files_bm image create $target.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ }
+
+ # Reevaluate button states on icon bar
+ listBox_disEna_buttons $item [lindex $editors [lsearch $file_descriptors $item]]
+ }
+
+ ## Move to top currently selected item -- Opened files
+ # @return void
+ public method filelist_move_top {} {
+ # Local variables
+ set item [$listbox_opened_files selection get] ;# Item ID
+ set index [$listbox_opened_files index $item] ;# Item index
+
+ # Move item
+ $listbox_opened_files move $item 0
+ # Move item in list of bookmarks
+ set bm [lindex $opened_files_bookmarks $index]
+ set opened_files_bookmarks [lreplace $opened_files_bookmarks $index $index]
+ set opened_files_bookmarks [linsert $opened_files_bookmarks 0 $bm]
+ # Move item in icon border
+ incr index
+ $listbox_opened_files_bm delete $index.0 $index.0+1l
+ $listbox_opened_files_bm insert 1.0 "\n"
+ if {$bm} {
+ $listbox_opened_files_bm image create 1.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+
+ # Reevaluate button states on icon bar
+ listBox_disEna_buttons $item [lindex $editors [lsearch $file_descriptors $item]]
+ }
+
+ ## Move to bottom currently selected item -- Opened files
+ # @return void
+ public method filelist_move_bottom {} {
+ # Local variables
+ set item [$listbox_opened_files selection get] ;# Item ID
+ set index [$listbox_opened_files index $item] ;# Item index
+
+ # Move item in listbox
+ $listbox_opened_files move $item end
+ # Move item in list of bookmarks
+ set bm [lindex $opened_files_bookmarks $index]
+ set opened_files_bookmarks [lreplace $opened_files_bookmarks $index $index]
+ lappend opened_files_bookmarks $bm
+ # Move item in icon border
+ incr index
+ set end [llength $opened_files_bookmarks]
+ $listbox_opened_files_bm delete $index.0 $index.0+1l
+ $listbox_opened_files_bm insert $end.0 "\n"
+ if {$bm} {
+ $listbox_opened_files_bm image create $end.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+
+ # Reevaluate button states on icon bar
+ listBox_disEna_buttons $item [lindex $editors [lsearch $file_descriptors $item]]
+ }
+
+ ## Show up editor asociated with the currently selected item in the file list (opened files)
+ # @return void
+ public method switchfile {} {
+ # Ensure that autocompletion window is closed
+ ::Editor::close_completion_popup_window_NOW
+
+ # Determinate ID of the selected item
+ set item [$listbox_opened_files selection get]
+ set editor_idx [lsearch $file_descriptors $item]
+
+ # Adjust filetabs notebook
+ set page [lindex [$filetabs_nb pages] $editor_idx]
+ $filetabs_nb raise $page
+ $filetabs_nb see $page
+
+ # Conditionaly switch selected view
+ if {$splitted && $selectedView} {
+ if {$editor_idx == $actualEditor} {
+ set selectedView 0
+ }
+ } {
+ if {$editor_idx == $actualEditor2} {
+ set selectedView 1
+ }
+ }
+
+ # Show up the coresponding editor
+ rightPanel_switch_editor_vars $editor_idx
+ $this todo_switch_editor_vars $editor_idx
+ # Right/Bottom view selected
+ if {$splitted && $selectedView} {
+ if {$editor_idx != $actualEditor2} {
+ if {!$do_not_forget_editor && $actualEditor2 >= 0} {
+ set editor [lindex $editors $actualEditor2]
+ if {$editor != {}} {
+ pack forget [$editor cget -ed_sc_frame]
+ }
+ }
+ set actualEditor2 $editor_idx
+ pack [[lindex $editors $actualEditor2] cget -ed_sc_frame] \
+ -in $pagesManager2 -fill both -expand 1
+ }
+ set editor [lindex $editors $actualEditor2]
+
+ # Left/Top view selected
+ } {
+ if {$editor_idx != $actualEditor} {
+ if {!$do_not_forget_editor && $actualEditor >= 0} {
+ set editor [lindex $editors $actualEditor]
+ if {$editor != {}} {
+ pack forget [$editor cget -ed_sc_frame]
+ }
+ }
+ set actualEditor $editor_idx
+ pack [[lindex $editors $actualEditor] cget -ed_sc_frame] \
+ -in $pagesManager -fill both -expand 1
+ }
+ set editor [lindex $editors $actualEditor]
+ }
+
+ set do_not_forget_editor 0
+ $opened_search_entry delete 0 end
+ update idle
+ editor_procedure {} Configure {}
+ editor_procedure {} scroll {scroll +0 lines}
+ editor_procedure {} highlight_visible_area {}
+ update
+ rightPanel_switch_page $editor_idx
+ $this todo_switch_editor $editor_idx
+ # Set encoding and eol
+ set ::editor_encoding [lindex $file_encoding $editor_idx]
+ set ::editor_EOL [lindex $file_eol $editor_idx]
+ set ::editor_RO_MODE [lindex $file_ro_mode $editor_idx]
+ set ::editor_SH [lindex $file_sh $editor_idx]
+ # Adjust command line status
+ if {$editor_command_line_on} {
+ $editor cmd_line_force_on
+ } {
+ $editor cmd_line_force_off
+ }
+ # Adjust tab "Instruction details" on the right panel
+ if {${::ASMsyntaxHighlight::validation_L1}} {
+ $editor parse_current_line
+ } {
+ $editor adjust_instruction_details
+ }
+ # move arrow image
+ catch {$listbox_opened_files itemconfigure $lastItem -image {}}
+ $listbox_opened_files itemconfigure $item -image ::ICONS::16::2_rightarrow
+ set lastItem $item
+ # Reevaluate button states on left panel icon bar, program title bar and main menu and main toolbar
+ listBox_disEna_buttons $item $editor
+ ::X::adjust_title
+ ::X::adjust_mainmenu_and_toolbar_to_editor \
+ ${::editor_RO_MODE} [expr {[$editor get_language] == 1}]
+ # Focus on the editor
+ focus -force [$editor cget -editor]
+ }
+
+ ## Switch to the next editor
+ # @return void
+ public method next_editor {} {
+ if {$frozen} {return}
+ set index [$listbox_opened_files index [$listbox_opened_files selection get]]
+
+ if {$index >= ([llength $file_descriptors] - 1)} {return}
+ $listbox_opened_files selection set [$listbox_opened_files item [expr {$index + 1}]]
+ switchfile
+ }
+
+ ## Switch to the previous editor
+ # @return void
+ public method prev_editor {} {
+ if {$frozen} {return}
+ set index [$listbox_opened_files index [$listbox_opened_files selection get]]
+ if {$index} {
+ $listbox_opened_files selection set \
+ [$listbox_opened_files item [expr {$index - 1}]]
+ switchfile
+ }
+ }
+
+ ## Switch the last file in list of opened files
+ # @return void
+ public method switch_to_last {} {
+ if {$splitted} {
+ set item [expr {([llength $file_descriptors] - 1)}]
+ if {$item == $actualEditor || $item == $actualEditor2} {
+ set item {end-1}
+ }
+ } {
+ set item {end}
+ }
+ $listbox_opened_files selection set [lindex $file_descriptors $item]
+ switchfile
+ }
+
+ ## Enable/Disable buttons in opened files icon bar and popup menu
+ # @parm String item - ID of the current item
+ # @parm Object editor - reference to current editor object
+ # @return void
+ private method listBox_disEna_buttons {item editor} {
+
+ # Is the file part of the project ?
+ if {[getItemNameFromProjectList [$editor cget -fullFileName]] != {}} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $opened_files_menu entryconfigure [::mc "Append to project"] -state $state
+ $filetabs_pu_menu entryconfigure [::mc "Append to project"] -state $state
+
+ # Items: "Move up" and "Move to top"
+ set item_idx [$listbox_opened_files index $item]
+ if {$item_idx == 0} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $opened_files_menu entryconfigure [::mc "Move up"] -state $state
+ $opened_files_menu entryconfigure [::mc "Move to top"] -state $state
+ $prev_editor_button configure -state $state
+ ${opened_files_buttonBox}up configure -state $state
+ ${opened_files_buttonBox}top configure -state $state
+
+ # Items: "Move down" and "Move to bottom"
+ if {($item_idx + 1) >= [llength [$listbox_opened_files items]]} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $opened_files_menu entryconfigure [::mc "Move down"] -state $state
+ $opened_files_menu entryconfigure [::mc "Move to bottom"] -state $state
+ $next_editor_button configure -state $state
+ ${opened_files_buttonBox}down configure -state $state
+ ${opened_files_buttonBox}bottom configure -state $state
+ }
+
+ ## Invoke popup menu for "Opened files"
+ # @parm Int x - absolute X coordinate
+ # @parm Int y - absolute Y coordinate
+ # @return void
+ public method fileList_opened_filelist_popup {x y} {
+ if {$item_menu_invoked} {
+ set item_menu_invoked 0
+ return
+ }
+
+ if {!${::Editor::editor_to_use}} {
+ $opened_files_menu entryconfigure [::mc "Save as"] -state disabled
+ $opened_files_menu entryconfigure [::mc "Save"] -state disabled
+
+ $filetabs_pu_menu entryconfigure [::mc "Save"] -state disabled
+ $filetabs_pu_menu entryconfigure [::mc "Save as"] -state disabled
+ }
+ foreach entry {
+ {Close} {Bookmark} {Move up}
+ {Move down} {Move to top} {Move to bottom}
+ {Open with} {Append to project}
+ } {
+ $opened_files_menu entryconfigure [::mc $entry] -state disabled
+ }
+
+ tk_popup $opened_files_menu $x $y
+ }
+
+ ## Invoke popup menu for "Opened files" -- for particular item
+ # note: This method should be associated with the 'bindtext' command
+ # @parm Int x - absolute X coordinate
+ # @parm Int y - absolute Y coordinate
+ # @parm String item - ID of selected item
+ # @return void
+ public method fileList_opened_filelist_item_popup {x y item} {
+ set item_menu_invoked 1
+
+ if {!${::Editor::editor_to_use}} {
+ $opened_files_menu entryconfigure [::mc "Save as"] -state normal
+ $opened_files_menu entryconfigure [::mc "Save"] -state normal
+
+ $filetabs_pu_menu entryconfigure [::mc "Save"] -state normal
+ $filetabs_pu_menu entryconfigure [::mc "Save as"] -state normal
+ }
+ foreach entry {
+ {Close} {Bookmark} {Move up}
+ {Move down} {Move to top} {Move to bottom}
+ {Open with}
+ } {
+ $opened_files_menu entryconfigure [::mc $entry] -state normal
+ }
+ # It is not so easy to open the file with an external editor on Microsoft Windows as
+ # it is on a POSIX system, that's why this feature is disabled here
+ if {$::MICROSOFT_WINDOWS} {
+ $opened_files_menu entryconfigure [::mc {Open with}] -state disabled
+ $filetabs_pu_menu entryconfigure [::mc {Open with}] -state disabled
+ }
+
+ $listbox_opened_files selection set $item
+ switchfile
+
+ # Enable/Disable item "Append to project"
+ set fullFileName [[lindex $editors [lsearch $file_descriptors $item]] cget -fullFileName]
+ if {$fullFileName == {} || [getItemNameFromProjectList $fullFileName] != {}} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $opened_files_menu entryconfigure [::mc "Append to project"] -state $state
+
+ tk_popup $opened_files_menu $x $y
+ }
+
+ # ---------------------------------------------------------------------
+ # AUXILIARY DATA MANAGEMENT PROCEDURES
+ # ---------------------------------------------------------------------
+
+ ## Open all files in the given list
+ # @parm List filelist - files to open (spec. format)
+ # @return void
+ public method open_files {filelist} {
+ # NS variables
+ set file_indexes {} ;# List of line indexes (auxiliary variable for opening multiple files)
+ set ac_index_in_fl -1 ;# Index of actual editor filelist
+
+ # Local variables
+ set num_of_opened_files 0 ;# Number of opened files
+ set rfi 0 ;# Record field index
+ set open_files_progress 0 ;# Value for progress dialog (progress)
+ set open_files_abort 0 ;# Abort variable
+ set keep_order 1 ;# Bool: Keep order of files
+ set rec_i -1 ;# Record index (in $filelist)
+ set file_indexes_fb {} ;# Fallback file indexes
+ set unopened_files {} ;# List of files which were unable to open
+ set changed_files {} ;# List of files changed since last project save
+ set project_path [$this cget -projectPath] ;# Path to the project directory
+ set filelist_length [llength $filelist] ;# Length of the given filelist
+ set ac [lindex $filelist {1 0}] ;# Index of actual editor
+
+ ## Lists of files to open
+ # Ordered
+ set files_to_open__path [string repeat {{} } $filelist_length] ;# Path
+ set files_to_open__enc [string repeat {{} } $filelist_length] ;# Encoding
+ set files_to_open__eol [string repeat {{} } $filelist_length] ;# EOL
+ set files_to_open__bm [string repeat {{} } $filelist_length] ;# Bookmark flag
+ set files_to_open__ro [string repeat {{} } $filelist_length] ;# Read only flag
+ set files_to_open__sh [string repeat {{} } $filelist_length] ;# Syntax highlight
+ set files_to_open__nt [string repeat {{} } $filelist_length] ;# Notes for file
+ # Unordered
+ set files_to_open_path {} ;# Path
+ set files_to_open_enc {} ;# Encoding
+ set files_to_open_eol {} ;# EOL
+ set files_to_open_bm {} ;# Bookmark flag
+ set files_to_open_ro {} ;# Read only flag
+ set files_to_open_sh {} ;# Syntax highlight
+ set files_to_open_nt {} ;# Notes for file
+
+ # Abort if the given filelist is empty
+ if {!$filelist_length} {return}
+
+ # Iterate over records in $filelist
+ foreach record $filelist {
+ incr rec_i ;# Record index
+
+ # First 2 records have no meaning here
+ if {$rec_i < 2 || $record == {}} {continue}
+
+ # Parse record
+ set rfi 0
+ foreach var {
+ file_name active o_bookmark p_bookmark
+ file_index read_only file_line file_md5
+ file_path file_BMs file_BPs eol
+ enc sh notes
+ } {
+ set $var [lindex $record $rfi]
+ incr rfi
+ }
+
+ # Adjust file path
+ if {[string index $file_path 0] != {/}} {
+ set file_path "$project_path/$file_path"
+ }
+ # Determinate full file name
+ set full_file_name "$file_path$file_name"
+
+ # Check for file usebility
+ if {
+ ![file exists $full_file_name] ||
+ [file isdirectory $full_file_name] ||
+ (!$::MICROSOFT_WINDOWS && ![file readable $full_file_name])
+ } then {
+ lappend file_indexes_fb {}
+ lappend unopened_files $full_file_name
+ continue
+ }
+
+ # Compare file MD5
+ if {[catch {
+ if {[md5::md5 -hex -file $file_path$file_name] != $file_md5} {
+ lappend changed_files $file_path$file_name
+ }
+ }]} then {
+ tk_messageBox \
+ -icon warning \
+ -type ok \
+ -title [mc "Unknown error"] \
+ -message [mc "Raised error during md5 checking file %s. Maybe md5 extension is not correctly loaded." $file_name]
+ }
+
+ # Chech for valid EOL and Encoding
+ if {$eol != {lf} && $eol != {cr} && $eol != {crlf}} {
+ set eol $default_eol
+ puts stderr "Invalid EOL -- using default ($eol)"
+ }
+ if {$enc != {def} && [lsearch [encoding names] $enc] == -1} {
+ set enc $default_encoding
+ puts stderr "Invalid encoding -- using default ($default_encoding)"
+ }
+ if {![string is boolean -strict $read_only]} {
+ set read_only 0
+ puts stderr "Read only flag -- using default (0)"
+ }
+
+ # Insert bookmark to icon border for project files
+ if {[llength $project_files_bookmarks]} {
+ $listbox_project_files_bm insert end "\n"
+ }
+ if {$p_bookmark == 1} {
+ lappend project_files_bookmarks 1
+ $listbox_project_files_bm image create [list {end-1l} linestart] \
+ -image ::ICONS::16::bookmark -align center
+ } {
+ lappend project_files_bookmarks 0
+ }
+ $listbox_project_files_bm tag add center 0.0 end
+
+ # Register the file in the project
+ if {$active == {no}} {
+ if {[llength $record] < 5} {continue}
+ $listbox_project_files insert end #auto \
+ -font $closed_file_font -fill {#888888} \
+ -text $file_name \
+ -data [list $file_name $active \
+ $read_only $file_line \
+ $file_md5 $file_path \
+ $file_BMs $file_BPs \
+ $eol $enc \
+ $sh $notes \
+ ]
+ continue
+ } {
+ $listbox_project_files insert end #auto \
+ -font $opened_file_font -fill {#000000} \
+ -text $file_name -data [list $file_path$file_name $eol $enc $read_only]
+ if {![string is digit -strict $file_index]} {
+ set keep_order 0
+ }
+ }
+
+ # Adjust lists of file indexes
+ lappend file_indexes $file_index
+ lappend file_indexes_fb $num_of_opened_files
+
+ # Adjust list of files to open
+ lset files_to_open__path $file_index $file_path$file_name
+ lset files_to_open__enc $file_index $enc
+ lset files_to_open__eol $file_index $eol
+ lset files_to_open__bm $file_index $o_bookmark
+ lset files_to_open__ro $file_index $read_only
+ lset files_to_open__sh $file_index $sh
+ lset files_to_open__nt $file_index $notes
+ lappend files_to_open_path $file_path$file_name
+ lappend files_to_open_enc $enc
+ lappend files_to_open_eol $eol
+ lappend files_to_open_bm $o_bookmark
+ lappend files_to_open_ro $read_only
+ lappend files_to_open_sh $sh
+ lappend files_to_open_nt $notes
+
+ # Determinate index in file list for actual editor
+ if {$file_index == $ac} {
+ set ac_index_in_fl $rec_i
+ incr ac_index_in_fl -2
+ }
+
+ # Increment number of opened files
+ incr num_of_opened_files
+ }
+
+ # Invoke progress dialog
+ set max [llength $file_indexes_fb]
+ if {!$max} {set max 1}
+ create_progress_bar .prgDl \
+ . \
+ ::FileList::open_files_cur_file \
+ {} \
+ ::FileList::open_files_progress \
+ $max \
+ [mc "Opening project files"] \
+ ::ICONS::16::fileopen \
+ [mc "Abort"] \
+ {set ::FileList::open_files_abort 1}
+
+ # Adjust lists of files to open
+ if {!$keep_order} {
+ set files_to_open__path $files_to_open_path
+ set files_to_open__enc $files_to_open_enc
+ set files_to_open__eol $files_to_open_eol
+ set files_to_open__bm $files_to_open_bm
+ set files_to_open__ro $files_to_open_ro
+ set files_to_open__sh $files_to_open_sh
+ set files_to_open__nt $files_to_open_nt
+ set file_indexes $file_indexes_fb
+ }
+
+ # Check for validity of list of file indexes
+ if {$unopened_files != {}} {
+ set file_indexes $file_indexes_fb
+ } {
+ for {set i 0} {$i < $num_of_opened_files} {incr i} {
+ if {[lsearch -ascii -exact $file_indexes $i] == -1} {
+ set file_indexes $file_indexes_fb
+ break
+ }
+ }
+ }
+
+ # Open files
+ set i 0
+ set pos 0
+ foreach path $files_to_open__path \
+ enc $files_to_open__enc \
+ eol $files_to_open__eol \
+ bm $files_to_open__bm \
+ ro $files_to_open__ro \
+ sh $files_to_open__sh \
+ notes $files_to_open__nt \
+ {
+ incr pos
+ if {$path == {}} {
+ continue
+ }
+
+ # Abort process on user request
+ if {$open_files_abort} {
+ $listbox_project_files delete [$listbox_project_files items $i end]
+ if {$i} {
+ incr i -1
+ set file_indexes [lrange $file_indexes 0 $i]
+ set file_indexes_fb [lrange $file_indexes_fb 0 $i]
+ } {
+ set file_indexes {}
+ set file_indexes_fb {}
+ }
+
+ set filelist [lrange $filelist 0 $pos]
+ break
+ }
+
+ # Adjust progress dialog
+ incr open_files_progress
+ set open_files_cur_file [file tail $path]
+ update
+
+ # Open file
+ if {[openfile $path 0 . $enc $eol $ro 0 $sh] != {}} {
+ if {$bm == 1} {
+ opened_files_bookmark $i
+ }
+ $this set_file_notes_data $notes
+ }
+ incr i
+ }
+
+ # Invoke dialog "File(s) not found"
+ if {$unopened_files != {}} {
+ # Create toplevel window
+ set win [toplevel .file_not_found$obj_idx -class {Error dialog} -bg {#EEEEEE}]
+
+ # Create window header
+ pack [frame $win.frame1] -side top -fill x -anchor nw
+ pack [label $win.frame1.image \
+ -image ::ICONS::32::messagebox_critical \
+ ] -anchor nw -expand 0 -side left -padx 10 -pady 5
+ pack [label $win.frame1.header \
+ -text [mc "The following files could not be located:"] \
+ ] -side left -fill x
+
+ # Create text widget with scrollbar
+ pack [frame $win.frame2] -side top -expand 1 -fill both -pady 10 -padx 5
+ pack [text $win.frame2.text -height 5 -width 40 \
+ -yscrollcommand "$win.frame2.scrollbar set"] -side left -fill both -expand 1
+ pack [ttk::scrollbar $win.frame2.scrollbar \
+ -orient vertical \
+ -command "$win.frame2.text yview" \
+ ] -side right -fill y
+
+ # Insert list of unopened files into the text widgets
+ $win.frame2.text insert end [join $unopened_files "\n"]
+ $win.frame2.text configure -state disabled
+
+ bind $win.frame2.text <1> "focus $win.frame2.text"
+
+ # Create button "Ok"
+ pack [ttk::button $win.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "
+ grab release $win
+ destroy $win
+ " \
+ ] -side bottom
+
+ # Dialog event bindings
+ bind $win <Return> "
+ grab release $win
+ destroy $win
+ "
+ bind $win <KP_Enter> "
+ grab release $win
+ destroy $win
+ "
+ bind $win <Escape> "
+ grab release $win
+ destroy $win
+ "
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::status_unknown
+ wm title $win [mc "File(s) not found"]
+ wm geometry $win 500x200
+ wm protocol $win WM_DELETE_WINDOW "
+ grab release $win
+ destroy $win
+ "
+ update
+ catch {grab $win}
+ raise $win
+ }
+
+ # Invoke dialog "File(s) changed"
+ if {$changed_files != {}} {
+ # Create dialog toplevel window
+ set win [toplevel .changed_files$obj_idx -class {File changed} -bg {#EEEEEE}]
+
+ # Create dialog header
+ pack [frame $win.frame1] -side top -fill x -anchor nw
+ pack [label $win.frame1.image -image ::ICONS::32::messagebox_info] \
+ -anchor nw -expand 0 -side left -padx 10 -pady 5
+ pack [label $win.frame1.header \
+ -text [mc "The following files were modified since last save:"] \
+ ] -side left -fill x
+
+ # Create text widget and scrollbar
+ pack [frame $win.frame2] -side top -expand 1 -fill both -pady 10 -padx 5
+ pack [text $win.frame2.text -height 5 -width 50 \
+ -yscrollcommand "$win.frame2.scrollbar set"] -side left -fill both -expand 1
+ pack [ttk::scrollbar $win.frame2.scrollbar \
+ -orient vertical \
+ -command "$win.frame2.text yview" \
+ ] -side right -fill y
+
+ # Insert info about changed files
+ foreach file $changed_files {
+ if {[file exists $file_path$file_name]} {
+ set time [clock format [file mtime $file_path$file_name] -format {%T %D}]
+ } {
+ set time " -----\t"
+ }
+ $win.frame2.text insert end "$time\t$file\n"
+ }
+ $win.frame2.text configure -state disabled
+
+ bind $win.frame2.text <1> "focus $win.frame2.text"
+
+ # Create button "Ok"
+ pack [ttk::button $win.but_ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "
+ grab release $win
+ destroy $win
+ " \
+ ] -side bottom -pady 5
+
+ # Set dialog event bindings
+ bind $win <Return> "
+ grab release $win
+ destroy $win
+ "
+ bind $win <KP_Enter> "
+ grab release $win
+ destroy $win
+ "
+ bind $win <Escape> "
+ grab release $win
+ destroy $win
+ "
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::info
+ wm title $win [mc "File(s) changed"]
+ wm geometry $win 500x200
+ wm protocol $win WM_DELETE_WINDOW "
+ grab release $win
+ destroy $win
+ "
+ update
+ catch {grab $win}
+ raise $win
+ }
+ }
+
+ ## Open file at the given location and with some additional options
+ # Alogorithm:
+ # * check if the file exists, if it doesn't then invoke an error message
+ # * if the file exists then open it and read its content
+ # * if the specified file path is an empty string then consider that file as a new one
+ # * check if that file in not already opened and if it is then focus on it and return
+ # * register that file in the class's internal variables
+ # * create a new editor for that file and eventualy display content of the file
+ # * focus on that newly created editor
+ #
+ # @parm String file_path - full file name including path, {} means create a new one
+ # @parm Bool ask - ask user about adding the file to the project
+ # @parm String parent - path to the parent widget (eg. dialog which invoked this procedure)
+ # @parm String enc - Character encoding
+ # @parm String eol - End of Line character identifier (one of {lf crlf cr})
+ # @parm Bool read_only - Read only flag
+ # @parm Bool fast - Open the file as fast as possible (only for creating new files)
+ # sh
+ # @return String - descriptor of the opened file
+ public method openfile {file_path ask parent enc eol read_only fast sh} {
+ set newfile 0 ;# Bool: created new virtual file
+
+ # Open an existing file
+ if {$file_path != {}} {
+ # Report error if the file does not exist
+ if {
+ !${::Editor::editor_to_use} && (
+ ![file exists $file_path] ||
+ ![file isfile $file_path] ||
+ (!$::MICROSOFT_WINDOWS && ![file readable $file_path])
+ )
+ } {
+ tk_messageBox \
+ -type ok \
+ -title [mc "File not found - MCU 8051 IDE"] \
+ -message [mc "File %s not found !" $file_path] \
+ -icon error
+ set newfile 1
+ }
+
+ # determine the filename
+ regexp {[^\\\/]+$} $file_path file_name
+
+ # Create a new file (untitled)
+ } else {
+ if {![regexp {untitled\d*} $file_descriptors]} {
+ set untitled_num -1
+ }
+ if {$untitled_num == -1} {
+ set file_name "untitled"
+ } {
+ set file_name "untitled$untitled_num"
+ }
+ incr untitled_num
+ set newfile 1
+ }
+ if {$file_name == {.#special:tmp}} {
+ if {![regexp {untitled\d*} $file_descriptors]} {
+ set untitled_num -1
+ }
+ if {$untitled_num == -1} {
+ set file_name "untitled"
+ } {
+ set file_name "untitled$untitled_num"
+ }
+ incr untitled_num
+ set newfile 1
+ }
+
+ # Check if the file isn't already opened
+ if {!$newfile} {
+ set idx 0
+ foreach editor $editors {
+ if {[$editor cget -fullFileName] == $file_path} {
+ set item [lindex $file_descriptors $idx]
+ $listbox_opened_files selection set $item
+ switchfile
+ set lastItem $item
+ Sbar [mc "File: %s is alredy opened." $file_path]
+ return {}
+ }
+ incr idx
+ }
+ }
+
+ # Adjust arguments 'eol' and 'enc'
+ if {$eol == {def}} {
+ set eol $default_eol
+ }
+ if {$enc == {def}} {
+ set enc $default_encoding
+ }
+
+ # Determinate unique file descriptor
+ set file_descriptor [regsub -all {_} $file_name {__}]
+ set file_descriptor [regsub -all {\.} $file_descriptor {_}]
+ set file_descriptor [regsub -all -- {-} $file_descriptor {--}]
+ set file_descriptor [regsub -all -- {\s} $file_descriptor {-}]
+ # Handle similar file descriptors of different files
+ while 1 {
+ if {[lsearch $file_descriptors $file_descriptor] != -1} {
+ append file_descriptor {_}
+ } {
+ break
+ }
+ }
+
+ # Register the file descriptor
+ lappend file_descriptors $file_descriptor
+ # Insert filename into ListBox of opened files
+ $listbox_opened_files insert end $file_descriptor \
+ -text $file_name -data $file_path -font $icon_border_font
+ if {[llength $opened_files_bookmarks]} {
+ $listbox_opened_files_bm insert end "\n"
+ }
+ lappend opened_files_bookmarks 0
+
+ if {$ask} {
+ # test if the file isn't already included in the project
+ set item [getItemNameFromProjectList $file_path]
+ if {$item != {}} {
+ set ask 0
+ }
+
+ if {!$ask} {
+ $listbox_project_files itemconfigure $item \
+ -font $opened_file_font \
+ -fg {#000000} \
+ -data [list $file_path $eol $enc $read_only]
+ }
+ }
+
+ if {$ask && $::FileList::ask__append_file_to_project} {
+ # Ask for append the file to the project
+ set ::FileList::dialog_response 0
+ set win [toplevel .append_to_the_project_dialog]
+
+ pack [label $win.label -text [mc "Do you want to append this file to the project ?\n%s" $file_name]] -fill x -pady 5 -padx 5
+
+ pack [frame $win.frm] -pady 5
+ pack [ttk::button $win.frm.yes_button -text [mc "Yes"] -command "
+ set ::FileList::dialog_response 1
+ grab release $win
+ destroy $win" \
+ ] -side left
+ bind $win.frm.yes_button <Return> "
+ set ::FileList::dialog_response 1
+ grab release $win
+ destroy $win"
+ bind $win.frm.yes_button <KP_Enter> "
+ set ::FileList::dialog_response 1
+ grab release $win
+ destroy $win"
+ pack [ttk::button $win.frm.no_button -text [mc "No"] -command "
+ grab release $win
+ destroy $win" \
+ ] -side left
+ bind $win.frm.no_button <Return> "
+ grab release $win
+ destroy $win"
+ bind $win.frm.no_button <KP_Enter> "
+ grab release $win
+ destroy $win"
+
+ pack [ttk::separator $win.sep -orient horizontal] -fill x -pady 10
+ pack [checkbutton $win.chb -text [mc "Do not ask again"] -onvalue 0 -offvalue 1 -variable ::FileList::ask__append_file_to_project] -anchor w
+ pack [text $win.tip -fg {#888888} -bg {#EEEEEE} -height 2 -width 0 -bd 0] -fill x
+ $win.tip insert end [mc "Tip: You can enable/disable this dialog in MCU 8051 IDE configuration dialog."]
+ $win.tip configure -state disabled
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::help
+ wm title $win [mc "Add file ?"]
+ wm resizable $win 0 0
+ wm transient $win .
+ catch {grab $win}
+ focus -force $win.frm.yes_button
+ wm protocol $win WM_DELETE_WINDOW "
+ grab release $win
+ destroy $win
+ "
+ raise $win
+ update
+ tkwait window $win
+
+ if {$::FileList::dialog_response } {
+ if {[llength $project_files_bookmarks]} {
+ $listbox_project_files_bm insert end "\n"
+ }
+ lappend project_files_bookmarks 0
+ $listbox_project_files insert end #auto \
+ -font $opened_file_font -fill {#000000} \
+ -text $file_name -data [list $file_path $eol $enc $read_only]
+ }
+ }
+
+ # Create editor object for the file
+ if {$file_path != {}} {
+ set data {}
+ if {!${::Editor::editor_to_use}} {
+ set file [open $file_path]
+ fconfigure $file -encoding $enc
+ if {[regsub -all {[\u0000-\u0008\u000B-\u000C\u000E-\u001F\u007F-\u009F]} [read $file] {} data]} {
+ tk_messageBox -parent . \
+ -type ok -icon warning \
+ -title [mc "Binary File Opened - MCU 8015 IDE"] \
+ -message [mc "The file %s is binary, saving it will result corrupted file." $file_path]
+ }
+ close $file
+ }
+
+ set editor [Editor "::editor${file_count}_$obj_idx" \
+ [expr {!$fast}] $eol $enc $read_only $file_switching_enabled $this \
+ $file_name $file_path "$this editor_procedure {} " \
+ [regsub -all {\r\n?} $data "\n"] $sh \
+ ]
+ } {
+ set editor [Editor "::editor${file_count}_$obj_idx" \
+ [expr {!$fast}] $eol $enc $read_only $file_switching_enabled $this \
+ $file_name $file_path "$this editor_procedure {} " {} $sh \
+ ]
+ }
+
+ # Determinate file type and set appropriate icon
+ set ext [string trimleft [file extension $file_name] {.}]
+ if {$ext == {h}} {
+ set icon {source_h}
+ } elseif {$ext == {c}} {
+ set icon {source_c}
+ } elseif {$ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set icon {source_cpp}
+ } elseif {$ext == {asm}} {
+ set icon {asm}
+ } else {
+ set icon {ascii}
+ }
+ $filetabs_nb insert end $file_descriptor \
+ -text $file_name -image ::ICONS::16::$icon \
+ -raisecmd "$this switch_file_from_filetabs $file_descriptor"
+ $filetabs_nb see $file_descriptor
+
+ # Conditionaly show Line Numbers and Icon Border
+ if {$iconBorder == 0} {
+ $editor hideLineNumbers
+ }
+ if {$lineNumbers == 0} {
+ $editor hideIconBorder
+ }
+
+ if {$sh == {}} {
+ set sh [$editor get_language]
+ }
+
+ # Editor text widget
+ lappend editor_wdgs [$editor cget -editor]
+ # Register Editor's object and widget and its frame
+ lappend editors $editor
+ lappend file_eol $eol
+ lappend file_encoding $enc
+ lappend file_ro_mode $read_only
+ lappend file_sh $sh
+
+ # Add editor to right panel
+ rightPanel_add_Editor [expr {!$fast}]
+ $this todo_add_Editor {}
+ $this todo_change_filename end $file_name
+ $editor goto 1
+
+ # Increment counter of opened files
+ incr file_count
+ # Return descriptor of the file
+ return $file_descriptor
+ }
+
+ ## Switch file from filetabs notebook
+ # @parm String page - Page ID
+ # @return void
+ public method switch_file_from_filetabs {page} {
+ $listbox_opened_files selection set $page
+ switchfile
+ }
+
+ ## Show file details windows from files tab (or something ...)
+ # $filetabs_nb bindtabs <Enter> "$this file_details_win_create_from_ftnb"
+ # @parm String page - Page ID
+ # @return void
+ public method file_details_win_create_from_ftnb {page} {
+ $this file_details_win_create O $page
+ }
+
+ ## Invoke popup menu for specific file from files tab (or something ...)
+ # $filetabs_nb bindtabs <ButtonRelease-3> "$this filetabs_nb_popup_menu %X %Y"
+ # @parm Int X - X coordinate
+ # @parm Int Y - Y coordinate
+ # @parm String page - Page ID
+ # @return void
+ public method filetabs_nb_popup_menu {X Y page} {
+ switch_file_from_filetabs $page
+
+ tk_popup $filetabs_pu_menu $X $Y
+ }
+
+ ## Save currently opened file under a given filename
+ # note: should be used only for saving untitled files !
+ # @parm String filename - Full file name including path
+ # @return bool - 1: (maybe) successful; 0: argument is empty
+ public method save_as {filename} {
+
+ # Handle empty argument
+ if {$filename == {}} {return 0}
+
+ # Adjust filename
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[$this cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [$this cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+ if {[file extension $filename] == {}} {
+ append filename {.asm}
+ }
+ # Determinate file rootname
+ set rootname [file tail $filename]
+
+ # Ask user for overwrite existing file
+ if {[file exists $filename] && [file isfile $filename]} {
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent . \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" $rootname]
+ ] != {yes}
+ } {
+ return 1
+ }
+ }
+
+ # Change filename in the listbox of opened files
+ set item [$listbox_opened_files selection get]
+ $listbox_opened_files itemconfigure $item -text $rootname -data $filename
+ $filetabs_nb itemconfigure $item -text $rootname
+
+ # Determinate some additional informations
+ if {$splitted && $selectedView} {
+ set idx $actualEditor2
+ } {
+ set idx $actualEditor
+ }
+ set editor [lindex $editors $idx]
+ set fullFileName [$editor cget -fullFileName] ;# Original full filename
+ set original_rootname [$editor cget -filename] ;# Original file rootname
+
+ # Mark the file as opened (in listbox of project files)
+ foreach item [$listbox_project_files items] {
+ if {[$listbox_project_files itemcget $item -text] != $original_rootname} {
+ continue
+ }
+ set data [$listbox_project_files itemcget $item -data]
+ if {[llength $data] > 4} {continue}
+ if {[lindex $data 0] != $fullFileName} {continue}
+ lset data 0 $filename
+ $listbox_project_files itemconfigure $item -data $data -text $rootname
+ }
+
+ # Set new file name
+ $editor set_FileName $filename $rootname
+ $editor save
+ $this todo_change_filename $idx $rootname
+
+ # Ask for appending the file to the project
+ set response [tk_messageBox \
+ -title [mc "Add file ?"] \
+ -icon question -type yesno \
+ -parent $parent \
+ -message [mc "Do you want to append this file to the project ?\n%s" $rootname]
+ ]
+ if {$response == {yes}} {
+ filelist_append_to_prj
+ }
+
+ ::X::recent_files_add 1 $filename
+
+ # Done ...
+ return 1
+ }
+
+
+ # ---------------------------------------------------------------------
+ # EDITOR PROCEDURES
+ # ---------------------------------------------------------------------
+
+ ## Show/Hide line numbers
+ # @return void
+ public method show_hide_lineNumbers {} {
+ if {$lineNumbers} {
+ set lineNumbers 0
+ foreach editor $editors {$editor hideLineNumbers}
+ } {
+ set lineNumbers 1
+ foreach editor $editors {$editor showLineNumbers}
+ }
+ }
+
+ ## Show/Hide icon border
+ # @return void
+ public method show_hide_IconBorder {} {
+ if {$iconBorder} {
+ set iconBorder 0
+ foreach editor $editors {$editor hideIconBorder}
+ } {
+ set iconBorder 1
+ foreach editor $editors {$editor showIconBorder}
+ }
+ }
+
+ ## Get number of lines in the current editor
+ # @return Int - result
+ public method editor_linescount {} {
+ if {$splitted && $selectedView} {
+ set tmp $actualEditor2
+ } {
+ set tmp $actualEditor
+ }
+ set tmp [[lindex $editors $tmp] cget -lastEnd]
+ return [expr {$tmp-1}]
+ }
+
+ ## Get number of line with the insertion cursor
+ # @return Int - result
+ public method editor_actLineNumber {} {
+ if {$splitted && $selectedView} {
+ set idx $actualEditor2
+ } {
+ set idx $actualEditor
+ }
+ return [expr {int([[lindex $editor_wdgs $idx] index insert])}]
+ }
+
+ ## Call any editor procedure
+ # @parm Int objectNumber - Number of editor object to use, {} mean current editor
+ # @parm String procedure - name of the procedure
+ # @parm String arguments - list of arguments to pass that procedure
+ # @retrurn mixed - result of invoked procedure
+ public method editor_procedure {objectNumber procedure arguments} {
+ # Determinate editor number
+ if {$objectNumber == {}} {
+ if {$splitted && $selectedView} {
+ set objectNumber $actualEditor2
+ } {
+ set objectNumber $actualEditor
+ }
+ }
+ # Call editor procedure
+ set editor [lindex $editors $objectNumber]
+ if {$editor == {}} {
+ switch_to_last
+ update
+ }
+ return [eval "$editor $procedure $arguments"]
+ }
+
+ ## Compare two tag ranges (text widget tags)
+ # @parm TextIndex first - 1st text tag range to compare {TextIndex Bool__Start_or_End}
+ # @parm TextIndex second - 2nd text tag range to compare {TextIndex Bool__Start_or_End}
+ # @return Int - result (on of {-1 0 1})
+ proc editor__sort_tag_ranges {first second} {
+
+ # Local variables
+ set idx0 [split [lindex $first 0] {.}] ;# Adjusted 1st text index -- list: {Row Column}
+ set row0 [lindex $idx0 0] ;# Row (1st index)
+ set col0 [lindex $idx0 1] ;# Column (1st index)
+ set idx1 [split [lindex $second 0] {.}] ;# Adjusted 2nd text index -- list: {Row Column}
+ set row1 [lindex $idx1 0] ;# Row (2nd index)
+ set col1 [lindex $idx1 1] ;# Column (2nd index)
+ set StartEnd0 [lindex $first 2] ;# Bool: Start_or_End (1st index)
+ set StartEnd1 [lindex $second 2] ;# Bool: Start_or_End (2nd index)
+
+ # Compare rows
+ if {$row0 > $row1} {
+ return -1
+ } elseif {$row0 < $row1} {
+ return 1
+ }
+
+ # Compare columns
+ if {$col0 > $col1} {
+ return -1
+ } elseif {$col0 < $col1} {
+ return 1
+ }
+
+ # Compare "Start_or_End" flags
+ if {!$StartEnd0 && $StartEnd1} {
+ return 1
+ } elseif {$StartEnd0 && !$StartEnd1} {
+ return -1
+ } else {
+ return 0
+ }
+ }
+
+ ## Get list of project files
+ # @return List - result
+ public method get_project_files_list {} {
+ ## Local variables
+ # List header
+ if {$splitted} {
+ set _actualEditor2 $actualEditor2
+ } {
+ set _actualEditor2 -1
+ }
+ if {$splitted} {
+ if {$pwin_orient == {vertical}} {
+ set idx 1
+ } {
+ set idx 0
+ }
+ set multiview_sash_pos [lindex [$multiview_paned_win sash coord 0] $idx]
+ }
+ set file_list [list \
+ [llength $editors] \
+ [list \
+ $actualEditor \
+ $_actualEditor2 \
+ $multiview_sash_pos \
+ $pwin_orient \
+ $selectedView \
+ ] \
+ ]
+ # Project directory
+ set project_path [$this cget -projectPath]
+ append project_path {/}
+ # Lenght of the project directory path string
+ set project_path_length [string length $project_path]
+ # Opened files index
+ set opened_i 0
+
+ ## Create list of full paths of opened files (in order of listbox of opened files)
+ set opened_files {}
+ foreach item [$listbox_opened_files items] {
+ set file_path [$listbox_opened_files itemcget $item -data]
+ if {$file_path == {}} {continue}
+ lappend opened_files $file_path
+ }
+
+ # Iterate over items of ListBox of project files
+ set i -1
+ foreach item [$listbox_project_files items] {
+ incr i
+
+ # Determinate item data
+ set data [$listbox_project_files itemcget $item -data]
+
+ # Unopened file
+ if {[llength $data] > 4} {
+ # Set opened flag
+ lset data 1 {no}
+ # Set file path
+ set path [lindex $data 5]
+ if {[string first $project_path $path] == 0} {
+ lset data 5 [string range $path $project_path_length end]
+ }
+
+ # Append o-bookmark=0, p-bookmark=$bm and file index=0
+ set data [linsert $data 2 0 [lindex $project_files_bookmarks $i] 0]
+
+ # Append file record to the resulting list
+ lappend file_list $data
+
+ # Opened file
+ } {
+ # Find the file in list of opened files
+ foreach editor $editors {
+ # Local variables
+ set file_name [$editor cget -fullFileName] ;# Full file name
+
+ if {$file_name != [lindex $data 0]} {continue}
+
+ # Determinate true item data
+ set data [getFileInfo $editor {yes}]
+
+ # Set file path
+ set path [lindex $data 5]
+ if {[string first $project_path $path] == 0} {
+ lset data 5 [string range $path $project_path_length end]
+ }
+
+ # Determinate index in Listbox of opened files
+ set index [lsearch $opened_files $file_name]
+
+ # Append o-bookmark, p-bookmark and file index
+ set data [linsert $data 2 \
+ [lindex $opened_files_bookmarks $index] \
+ [lindex $project_files_bookmarks $i] \
+ $index]
+
+ # Append encoding and EOL info
+ lappend data \
+ [lindex $file_eol $opened_i] \
+ [lindex $file_encoding $opened_i] \
+ [lindex $file_sh $opened_i] \
+ [$this get_file_notes_data $i]
+
+ incr opened_i
+
+ # Append file record to the resulting list
+ lappend file_list $data
+ }
+ }
+ }
+
+ # Return the file list
+ return $file_list
+ }
+
+ ## Get opened file item data to use in filelists
+ # @see get_project_files_list
+ # @see editor_close
+ # @parm Object editor - Reference to editor object
+ # @parm String active - Active flag
+ # @return List - resulting data or '{}'
+ private method getFileInfo {editor active} {
+ # Determinate full file name
+ set file_name [$editor cget -fullFileName]
+ if {$file_name == {}} {return {}}
+
+ # Determinate file rootname, path and MD5 hex hash
+ regexp {[^\\\/]*$} $file_name name
+ regexp {^.*[\\\/]} $file_name path
+ if {[catch {
+ set md5_hash [md5::md5 -hex -hex -file $file_name]
+ }]} {
+ set md5_hash {}
+ }
+
+ set actual_line [$editor get_current_line_number] ;# Current line
+ set line_markers [$editor export_line_markers_data] ;# bookmarks and breakpoints
+ set bookmarks [lindex $line_markers 0] ;# Bookmarks
+ set breakpoints [lindex $line_markers 1] ;# Breakpoints
+
+ # Return result
+ return [list \
+ $name $active [$editor cget -ro_mode] \
+ $actual_line $md5_hash $path \
+ $bookmarks $breakpoints \
+ ]
+ }
+
+ ## Invoke dialog "Open file" (require NS 'X')
+ # @return void
+ public method editor_open {} {
+ X::__open
+ }
+
+ ## Save the current file
+ # @return void
+ public method editor_save {} {
+ if {$splitted && $selectedView} {
+ [lindex $editors $actualEditor2] save
+ } {
+ [lindex $editors $actualEditor] save
+ }
+ }
+
+ ## Save current file under a different name (reires NS 'X')
+ # @return void
+ public method editor_save_as {} {
+ X::__save_as
+ }
+
+ ## Call procedure save for each editor object in the current project
+ # note: in other words save all opened files
+ # @return void
+ public method editor_save_all {} {
+ foreach editor $editors {
+ $editor save
+ }
+ }
+
+ ## Create a new empty editor object inside the project and focus on it
+ # @return void
+ public method editor_new {} {
+ openfile {} 0 . def def 0 1 {}
+ switch_to_last
+ set editor [lindex $editors end]
+ update
+ $editor create_highlighting_tags
+ update
+ rightPanel_add_Editor__create_menu_and_tags
+ $editor parseAll
+ focus [$editor cget -editor]
+ }
+
+ ## Open a new editor containing the given data
+ # @parm String data - Data to insert into the editor
+ # @return void
+ public method background_open {data} {
+ if {!${::Editor::editor_to_use}} {
+ openfile {} 0 . def def 0 0 {}
+ set editor [lindex $editors end]
+ $editor insertData $data {}
+ [$editor cget -editor] edit modified 0
+ [$editor cget -editor] edit reset
+ } {
+ set dir [${::X::actualProject} cget -ProjectDir]
+ catch {
+ file delete -force -- [file join $dir .#special:tmp]
+ }
+
+ set file [open [file join $dir .#special:tmp] w 420]
+ puts -nonewline $file $data
+ close $file
+
+ openfile [file join $dir .#special:tmp] 0 . def def 0 0 {}
+ }
+ }
+
+ ## Close the current editor and optionaly save its data to some file
+ # note: if this procedure was executed to destroy the last
+ # remainig editor then a new one would be created !!!
+ # @parm Bool ask - Ask user for saving the file (if was modified)
+ # @parm Int editorIdx - number of editor to close, {} mean currently active editor
+ # @return Bool - Created a new editor ?
+ public method editor_close {ask editorIdx} {
+ if {$editor_close_in_progress} {return}
+ set editor_close_in_progress 1
+
+ # Determinate editor object reference
+ if {$editorIdx == {}} {
+ if {$splitted && $selectedView} {
+ set editorIdx $actualEditor2
+ } {
+ set editorIdx $actualEditor
+ }
+ } {
+ if {$editorIdx == $actualEditor} {
+ set selectedView 0
+ } elseif {$editorIdx == $actualEditor2} {
+ set selectedView 1
+ }
+ }
+ set editor [lindex $editors $editorIdx]
+
+ # Ask user for saving the file (if was modified)
+ if {$ask && [$editor cget -modified]} {
+ set response [tk_messageBox \
+ -type yesnocancel \
+ -title [mc "Close document - MCU 8051 IDE"] \
+ -icon question \
+ -default yes \
+ -message [mc "The document %s have been modified.\nDo you want to save it ?" [[lindex $editors $editorIdx] cget -fullFileName]]]
+
+ if {$response == {yes}} {
+ $editor save
+ } elseif {$response == {cancel}} {
+ set editor_close_in_progress 0
+ return {}
+ }
+ }
+
+ # Mark the file as unopened (in ListBox of project fies)
+ set items [$listbox_project_files items] ;# List of project files
+ set fullFileName [$editor cget -fullFileName] ;# Full filename of the current file
+ set rootname [$editor cget -filename] ;# Rootname of the current file
+ foreach item $items {
+ if {[$listbox_project_files itemcget $item -text] != $rootname} {
+ continue
+ }
+ set data [$listbox_project_files itemcget $item -data]
+ if {[llength $data] > 4} {continue}
+
+ if {[lindex $data 0] == $fullFileName} {
+ $listbox_project_files itemconfigure $item \
+ -fg {#888888} \
+ -font $closed_file_font \
+ -data [concat \
+ [getFileInfo $editor {no}] \
+ [lindex $file_eol $editorIdx] \
+ [lindex $file_encoding $editorIdx] \
+ [lindex $file_sh $editorIdx] \
+ [$this get_file_notes_data $editorIdx] \
+ ]
+ }
+ }
+
+ # Delete editor object and all its widgets
+ set file_descriptor [lindex $file_descriptors $editorIdx]
+ set item_index [$listbox_opened_files index $file_descriptor]
+ $listbox_opened_files delete $file_descriptor
+ $listbox_opened_files_bm delete [expr {$item_index + 1}].0 [expr {$item_index + 2}].0
+ set opened_files_bookmarks [lreplace $opened_files_bookmarks $item_index $item_index]
+ delete object $editor
+ rightPanel_remove_Editor $editorIdx
+ $this todo_remove_editor $editorIdx
+
+ $filetabs_nb delete $file_descriptor
+
+ # Adjust object variables
+ foreach var {editors file_descriptors editor_wdgs file_eol file_encoding file_ro_mode file_sh} {
+ set $var [lreplace [subst "\$$var"] $editorIdx $editorIdx]
+ }
+ if {$actualEditor > $editorIdx} {
+ incr actualEditor -1
+ }
+ if {$actualEditor2 > $editorIdx} {
+ incr actualEditor2 -1
+ }
+ if {$actualEditor == $editorIdx || $actualEditor2 == $editorIdx} {
+ set do_not_forget_editor 1
+ if {$actualEditor == $editorIdx} {
+ set actualEditor -1
+ }
+ if {$actualEditor2 == $editorIdx} {
+ set actualEditor2 -1
+ }
+
+ # Conditionaly open a new editor
+ if {$splitted} {
+ set min 2
+ } {
+ set min 1
+ }
+ if {[llength $file_descriptors] < $min} {
+ if {$min == 1} {
+ set file_count 0
+ }
+ Sbar [mc "Last editor window closed -> opening a new one ..."]
+ editor_new
+ set editor_close_in_progress 0
+ return 1
+ }
+ # Switch to last editor in the list
+ switch_to_last
+ }
+
+ set editor_close_in_progress 0
+ return 1
+ }
+
+ ## Close all editors in the list of opened files
+ # @parm Bool allowCancelButton - Display button "Cancel" in dialog "Save multiple files"
+ # @parm Bool projectClose - Should be 1 if closing project
+ # @return Bool - 1: all have been done smoothly; 0: user has been asked about modified files
+ public method editor_close_all {allowCancelButton projectClose} {
+ # Determinate number of editors to close
+ set editorCount [llength $file_descriptors]
+
+ # Create list of the modified ones
+ set unsaved {}
+ foreach editor $editors {
+ if {[$editor cget -modified]} {
+ lappend unsaved $editor
+ }
+ }
+
+ # Ask user for file save
+ if {$unsaved != {}} {
+ save_multiple_files $allowCancelButton
+ return 0
+ } {
+ if {!$projectClose} {
+ editor_force_close_all
+ }
+ return 1
+ }
+ }
+
+ ## Close all opened files without any warning
+ # @return void
+ public method editor_force_close_all {} {
+ # Determinate number of editors
+ set editorMaxIdx [llength $file_descriptors]
+ set editorMaxIdx [expr {$editorMaxIdx - 1}]
+
+ # Close editors
+ for {set i $editorMaxIdx} {$i >= 0} {incr i -1} {
+ editor_close 0 $i
+ }
+ }
+
+ ## Create special dialog to ask user which files should be saved
+ # Intended for closing multiple files
+ # note: * Using class variable 'unsaved' instead of any argument !!!
+ # * Depend on methods: save_multiple_files_DESTROY, save_multiple_files_CANCEL,
+ # save_multiple_files_SAVEALL, save_multiple_files_SAVESELECTED
+ # @parm allowCancelButton bool - 1: show 'Cancel' button; 0: nothing
+ # @return void
+ public method save_multiple_files {allowCancelButton} {
+
+ # Create a new toplevel window for the dialog
+ set dialog .save_multiple_files
+ toplevel $dialog
+
+ # Create the top part of dialog (Header and some icon)
+ pack [frame $dialog.topframe] -fill x -expand 1
+ pack [label $dialog.topframe.image -image ::ICONS::32::fileclose] -side left -padx 10
+ pack [label $dialog.topframe.message \
+ -text [mc "The following documents have been modified,\ndo you want to save them before closing ?"] \
+ ] -side right -fill x -expand 1
+
+ # Create the middle part of the dialog (list of unsaved files)
+ pack [tkk::labelframe $dialog.lf \
+ -text [mc "Unsaved files"] \
+ ] -fill both -expand 1 -pady 10 -padx 10
+ set i 0
+ foreach editorObj $unsaved {
+ pack [checkbutton $dialog.lf.chb$i \
+ -text [$editorObj cget -filename] \
+ -variable unsavedfile$i \
+ -image ::ICONS::16::kcmdf \
+ -compound left \
+ ] -anchor w -padx 10
+ incr i
+ }
+
+ # Create the bottom part of the dialog (buttons "Save selected", "Save all" etc.)
+ pack [ttk::separator $dialog.separator -orient horizontal] -fill x -expand 1
+ pack [frame $dialog.f]
+ # SAVESELECTED
+ pack [ttk::button $dialog.f.b_save_selected \
+ -text [mc "Save selected"] \
+ -compound left \
+ -image ::ICONS::16::filesave \
+ -command {${X::actualProject} save_multiple_files_SAVESELECTED} \
+ ] -side left
+ # SAVEALL
+ pack [ttk::button $dialog.f.b_save_all \
+ -text [mc "Save all"] \
+ -compound left \
+ -image ::ICONS::16::save_all \
+ -command {${X::actualProject} save_multiple_files_SAVEALL} \
+ ] -side left
+ # DESTROY
+ pack [ttk::button $dialog.f.b_discard \
+ -text [mc "Discard"] \
+ -compound left \
+ -image ::ICONS::16::editdelete \
+ -command {${X::actualProject} save_multiple_files_DESTROY} \
+ ] -side left
+ # CANCEL
+ if {$allowCancelButton} {
+ pack [ttk::button $dialog.f.b_cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {${X::actualProject} save_multiple_files_CANCEL} \
+ ] -side left
+ }
+
+ # Set dialog attributes (modal window)
+ wm iconphoto $dialog ::ICONS::16::exit
+ wm title $dialog [mc "Close files - MCU 8051 IDE"]
+ wm state $dialog normal
+ wm minsize $dialog 350 200
+ wm transient $dialog .
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ "
+ update
+ catch {
+ grab $dialog
+ }
+ raise $dialog
+ focus $dialog
+ tkwait window $dialog
+ }
+
+ ## Auxiliary procedure for method 'save_multiple_files'
+ # It should be executed on pressing button 'Save selected' dialog 'Save multiple files'
+ # This function saves all files selected in dialog 'Save multiple files'
+ # @return void
+ public method save_multiple_files_SAVESELECTED {} {
+ set i 0
+ foreach editor $unsaved {
+ set cnd [subst "\${::unsavedfile$i}"]
+ if {$cnd} {$editor save}
+ incr i
+ }
+ save_multiple_files_DESTROY
+ }
+
+ ## Auxiliary procedure for method 'save_multiple_files'
+ # It should be executed on pressing button 'Save all' dialog 'Save multiple files'
+ # @return void
+ public method save_multiple_files_SAVEALL {} {
+ foreach editor $unsaved {
+ $editor save
+ }
+ save_multiple_files_DESTROY
+ }
+
+ ## Auxiliary procedure for method 'save_multiple_files'
+ # It should be executed on pressing button 'Discard' in 'Save multiple files' dialog
+ # @return void
+ public method save_multiple_files_DESTROY {} {
+ set editorMaxIdx [llength $file_descriptors]
+ set editorMaxIdx [expr {$editorMaxIdx - 1}]
+ editor_force_close_all
+ save_multiple_files_CANCEL
+ }
+
+ ## Auxiliary procedure for method 'save_multiple_files'
+ # It should be executed on pressing button 'Cancel' in 'Save multiple files' dialog
+ # @return void
+ public method save_multiple_files_CANCEL {} {
+ destroy .save_multiple_files
+ }
+
+ ## Reevaluate state of buttons on icon bar in tab LProject files
+ # @return void
+ public method FileList_project_disEna_buttons {} {
+
+ # Determinate selected item
+ set item [$listbox_project_files selection get]
+
+ # Non empty selection
+ if {$item != {}} {
+ ${project_files_buttonBox}remove configure -state normal
+ ${project_files_buttonBox}bookmark configure -state normal
+
+ # Simulator engaged
+ if {$frozen} {
+ ${project_files_buttonBox}close configure -state disabled
+ ${project_files_buttonBox}open configure -state disabled
+
+ # Simulator disengaged
+ } {
+ # Opened file
+ if {[llength [$listbox_project_files itemcget $item -data]] < 5} {
+ ${project_files_buttonBox}close configure -state normal
+ ${project_files_buttonBox}open configure -state disabled
+
+ # Unopened file
+ } {
+ ${project_files_buttonBox}close configure -state disabled
+ ${project_files_buttonBox}open configure -state normal
+ }
+ }
+
+ # Nothing selected
+ } {
+ ${project_files_buttonBox}remove configure -state disabled
+ ${project_files_buttonBox}open configure -state disabled
+ ${project_files_buttonBox}close configure -state disabled
+ ${project_files_buttonBox}bookmark configure -state disabled
+ }
+ }
+
+ ## Invoke project files popup menu
+ # @parm Int X - relative X coordinate
+ # @parm Int Y - relative Y coordinate
+ # @return void
+ public method fileList_project_filelist_popup {X Y} {
+ if {$item_menu_invoked} {
+ set item_menu_invoked 0
+ return
+ }
+
+ foreach entry {
+ {Remove file from the project} {Close file} {Open file}
+ {Bookmark} {Move up} {Move down}
+ {Move to top} {Move to bottom} {Open with}
+ } {
+ $project_files_menu entryconfigure [::mc $entry] -state disabled
+ }
+
+ tk_popup $project_files_menu $X $Y
+ }
+
+ ## Invoke project files popup menu -- for particular item
+ # @parm Int X - relative X coordinate
+ # @parm Int Y - relative Y coordinate
+ # @parm String item - ID of the current item
+ # @return void
+ public method fileList_project_filelist_item_popup {X Y item} {
+ set item_menu_invoked 1
+
+ foreach entry {
+ {Remove file from the project} {Bookmark} {Open with}
+ } {
+ $project_files_menu entryconfigure [::mc $entry] -state normal
+ }
+
+ # It is not so easy to open the file with an external editor on Microsoft Windows as
+ # it is on a POSIX system, that's why this feature is disabled here
+ if {$::MICROSOFT_WINDOWS} {
+ $project_files_menu entryconfigure [::mc {Open with}] -state disabled
+ }
+
+ # Adjust ListBox selection
+ $listbox_project_files selection set $item
+
+ # Opened file
+ if {[llength [$listbox_project_files itemcget $item -data]] < 5} {
+ if {!$frozen} {
+ $project_files_menu entryconfigure [::mc "Close file"] -state normal
+ }
+ $project_files_menu entryconfigure [::mc "Open file"] -state disabled
+ # Unopened file
+ } {
+ if {!$frozen} {
+ $project_files_menu entryconfigure [::mc "Close file"] -state disabled
+ }
+ $project_files_menu entryconfigure [::mc "Open file"] -state normal
+ }
+
+ # Movement commands
+ if {[$listbox_project_files index $item] == 0} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $project_files_menu entryconfigure [::mc "Move up"] -state $state
+ $project_files_menu entryconfigure [::mc "Move to top"] -state $state
+
+ if {[$listbox_project_files index $item] == ([llength [$listbox_project_files items]] - 1)} {
+ set state disabled
+ } {
+ set state normal
+ }
+ $project_files_menu entryconfigure [::mc "Move down"] -state $state
+ $project_files_menu entryconfigure [::mc "Move to bottom"] -state $state
+
+ # Invoke the menu
+ tk_popup $project_files_menu $X $Y
+ }
+
+ ## Move up current item in project filelist
+ # @return void
+ public method filelist_prj_move_up {} {
+ # Local variables
+ set item [$listbox_project_files selection get] ;# Item ID
+ set index [$listbox_project_files index $item] ;# Item index
+ set target [expr {$index - 1}] ;# Target index
+
+ # Check if the item can be moved
+ if {$index == 0} {return}
+
+ # Move item in listbox
+ $listbox_project_files move $item $target
+ # Move item in list of bookmarks and icon border
+ if {[lindex $project_files_bookmarks $index] != [lindex $project_files_bookmarks $target]} {
+ # Determinate bookmark flag for source and target index
+ set trg_bm [lindex $project_files_bookmarks $target]
+ set idx_bm [lindex $project_files_bookmarks $index]
+ # Move item in list of bookmarks
+ lset project_files_bookmarks $target [lindex $project_files_bookmarks $index]
+ lset project_files_bookmarks $index $trg_bm
+ # Move item in icon border
+ incr target
+ incr index
+ $listbox_project_files_bm delete $index.0 [list $index.0 lineend]
+ $listbox_project_files_bm delete $target.0 [list $target.0 lineend]
+ if {$trg_bm} {
+ $listbox_project_files_bm image create $index.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ if {$idx_bm} {
+ $listbox_project_files_bm image create $target.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ }
+ }
+
+ ## Move down current item in project filelist
+ # @return void
+ public method filelist_prj_move_down {} {
+ # Local variables
+ set item [$listbox_project_files selection get] ;# Item ID
+ set index [$listbox_project_files index $item] ;# Item index
+ set items [llength [$listbox_project_files items]] ;# Number of items in listbox
+ set target [expr {$index + 1}] ;# Target index
+
+ # Check if the item can be moved
+ if {$index == $items} {return}
+
+ # Move item in listbox
+ $listbox_project_files move $item $target
+ # Move item in list of bookmarks and icon border
+ if {[lindex $project_files_bookmarks $index] != [lindex $project_files_bookmarks $target]} {
+ # Determinate bookmark flag for source and target index
+ set trg_bm [lindex $project_files_bookmarks $target]
+ set idx_bm [lindex $project_files_bookmarks $index]
+ # Move item in list of bookmarks
+ lset project_files_bookmarks $target [lindex $project_files_bookmarks $index]
+ lset project_files_bookmarks $index $trg_bm
+ # Move item in icon border
+ incr target
+ incr index
+ $listbox_project_files_bm delete $index.0 [list $index.0 lineend]
+ $listbox_project_files_bm delete $target.0 [list $target.0 lineend]
+ if {$trg_bm} {
+ $listbox_project_files_bm image create $index.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ if {$idx_bm} {
+ $listbox_project_files_bm image create $target.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ }
+ }
+
+ ## Move to top current item in project filelist
+ # @return void
+ public method filelist_prj_move_top {} {
+ # Determinate index of the current item
+ set item [$listbox_project_files selection get]
+ set index [$listbox_project_files index $item]
+
+ # Check if the item can be moved
+ if {$index == 0} {return}
+
+ # Move item in listbox
+ $listbox_project_files move $item 0
+ # Move item in list of bookmarks
+ set bm [lindex $project_files_bookmarks $index]
+ set project_files_bookmarks [lreplace $project_files_bookmarks $index $index]
+ set project_files_bookmarks [linsert $project_files_bookmarks 0 $bm]
+ # Move item in icon border
+ incr index
+ $listbox_project_files_bm delete $index.0 $index.0+1l
+ $listbox_project_files_bm insert 1.0 "\n"
+ if {$bm} {
+ $listbox_project_files_bm image create 1.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ }
+
+ ## Move to bottom current item in project filelist
+ # @return void
+ public method filelist_prj_move_bottom {} {
+ # Determinate index of the current item and end index
+ set item [$listbox_project_files selection get]
+ set index [$listbox_project_files index $item]
+ set items [llength [$listbox_project_files items]]
+
+ # Check if the item can be moved
+ if {$index == $items} {return}
+
+ # Move item in listbox
+ $listbox_project_files move $item [expr {$items - 1}]
+ # Move item in list of bookmarks
+ set bm [lindex $project_files_bookmarks $index]
+ set project_files_bookmarks [lreplace $project_files_bookmarks $index $index]
+ lappend project_files_bookmarks $bm
+ # Move item in icon border
+ incr index
+ set end [llength $project_files_bookmarks]
+ $listbox_project_files_bm delete $index.0 $index.0+1l
+ $listbox_project_files_bm insert $end.0 "\n"
+ if {$bm} {
+ $listbox_project_files_bm image create $end.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ }
+
+ ## Open file from ListBox of project files
+ # Takes any set of arguments and discards them
+ # @return void
+ public method filelist_project_file_open args {
+ if {$frozen} {return}
+
+ # Local varibales
+ set item [$listbox_project_files selection get] ;# Item ID
+ set record [$listbox_project_files itemcget $item -data] ;# Item data
+
+ # If the file is already opended -- abort
+ if {[llength $record] == 4} {return}
+
+ # Parse item data
+ set ri 0
+ foreach var {file_name active ro file_line file_md5 file_path file_BMs file_BPs eol enc sh notes} {
+ set $var [lindex $record $ri]
+ incr ri
+ }
+
+ # Check for file existence
+ if {![file exists $file_path$file_name]} {
+ tk_messageBox \
+ -title [mc "File not found"] \
+ -icon error \
+ -type ok \
+ -message [mc "File %s could not be located at the specified location." $file_name]
+ return
+ }
+
+ # Verify file MD5 hash
+ if {[catch {
+ if {[md5::md5 -hex -file $file_path$file_name] != $file_md5} {
+ tk_messageBox \
+ -icon warning \
+ -type ok \
+ -title [mc "File changed"] \
+ -message [mc "File \"%s\" was modified since last project save\nTime: %s" $file_name [clock format [file mtime $file_path$file_name] -format {%T %D}]]
+ }
+ }]} then {
+ tk_messageBox \
+ -icon warning \
+ -type ok \
+ -title [mc "Unknown error"] \
+ -message [mc "Raised error during md5 checking file %s. Maybe md5 extension is not correctly loaded." $file_name]
+ }
+
+ # Open the file
+ if {[openfile $file_path$file_name 0 . $enc $eol $ro 0 $sh] != {}} {
+ set i [llength $editors]
+ incr i -1
+ set editor [lindex $editors $i]
+ rightPanel_switch_editor $i
+ $this todo_switch_editor $i
+ $editor import_line_markers_data $file_BMs $file_BPs
+ $editor goto $file_line
+ switch_to_last
+ incr i
+
+ $this set_file_notes_data $notes
+ }
+
+ # Adjust listbox of opened files
+ $listbox_project_files itemconfigure $item \
+ -font $opened_file_font -fg {#000000} -data [list $file_path$file_name $eol $enc $ro]
+
+ # Reevaluate iconbar
+ FileList_project_disEna_buttons
+ }
+
+ ## Close file in ListBox of project files
+ # @return void
+ public method filelist_project_file_close {} {
+ # Determinate filename
+ set item [$listbox_project_files selection get]
+ set filename [$listbox_project_files itemcget $item -data]
+ if {[llength $filename] > 4} {return}
+
+ # Determinate editor index
+ set filename [lindex $filename 0]
+ set idx 0
+ foreach editor $editors {
+ if {[$editor cget -fullFileName] == $filename} {break}
+ incr idx
+ }
+
+ # Close the editor
+ editor_close 1 $idx
+ FileList_project_disEna_buttons
+ }
+
+ ## Remove file from the project ListBox
+ # @return void
+ public method filelist_remove_file_from_project {} {
+ # Determinate item ID
+ set item [$listbox_project_files selection get]
+ set index [$listbox_project_files index $item]
+ # Remove item from the ListBox
+ $listbox_project_files delete $item
+ # Remove item from icon border and list of bookmarks
+ $listbox_project_files_bm delete [expr {$index + 1}].0 [expr {$index + 2}].0
+ set project_files_bookmarks [lreplace $project_files_bookmarks $index $index]
+ # Select the next item
+ set end [llength [$listbox_project_files items]]
+ incr end -1
+ if {$index > $end} {
+ set index $end
+ }
+ if {$index != -1} {
+ $listbox_project_files selection set \
+ [$listbox_project_files items $index]
+ }
+ # Reevaluate icon bar
+ FileList_project_disEna_buttons
+ }
+
+ ## Append the current file to the project
+ # @return void
+ public method filelist_append_to_prj {} {
+ # Index of the current file
+ set idx [lsearch $file_descriptors [$listbox_opened_files selection get]]
+ # Reference to editor object
+ set editor [lindex $editors $idx]
+
+ # Check if the file isn't already part of the project
+ set fullFileName [$editor cget -fullFileName]
+ if {$fullFileName == {} || [getItemNameFromProjectList $fullFileName] != {}} {
+ return
+ }
+
+ # Adjust ListBox of project files
+ $listbox_project_files insert end #auto \
+ -font $opened_file_font \
+ -fg {#000000} \
+ -text [$editor cget -filename] \
+ -data [list $fullFileName \
+ [lindex $file_eol $idx] \
+ [lindex $file_encoding $idx] \
+ [lindex $file_ro_mode $idx] \
+ ]
+
+ # Adjust icon border
+ if {[llength $project_files_bookmarks]} {
+ $listbox_project_files_bm insert end "\n"
+ }
+ lappend project_files_bookmarks 0
+
+ }
+
+ ## Translate full filename to item ID (in project files ListBox)
+ # @parm String fullFileName - full file name
+ # @return String - item ID or '{}'
+ private method getItemNameFromProjectList {fullFileName} {
+ # Get list of project file items
+ set items [$listbox_project_files items]
+
+ # Search for the given filename
+ foreach item $items {
+ # Determinate item data
+ set data [$listbox_project_files itemcget $item -data]
+
+ # Opened file
+ if {[llength $data] < 5} {
+ if {[lindex $data 0] == $fullFileName} {
+ return $item
+ }
+
+ # Unopened file
+ } {
+ if { "[lindex $data 5][lindex $data 0]" == $fullFileName} {
+ return $item
+ }
+ }
+ }
+
+ # Failed
+ return {}
+ }
+
+ ## Change encoding in the current editor
+ # @return void
+ public method change_encoding {} {
+ if {$splitted && $selectedView} {
+ set idx $actualEditor2
+ } {
+ set idx $actualEditor
+ }
+ if {[lindex $file_encoding $idx] == ${::editor_encoding}} {
+ return
+ }
+
+ # Configure editor
+ set original_encoding [lindex $file_encoding $idx]
+ lset file_encoding $idx ${::editor_encoding}
+ [lindex $editors $idx] configure -encoding ${::editor_encoding}
+ if {![filelist_reload_file]} {
+ set ::editor_encoding $original_encoding
+ lset file_encoding $idx $original_encoding
+ [lindex $editors $idx] configure -encoding $original_encoding
+ } {
+ # Configure list of project files
+ set filename [[lindex $editors $idx] cget -fullFileName]
+ foreach item [$listbox_project_files items] {
+ set data [$listbox_project_files itemcget $item -data]
+ if {[lindex $data 0] == $filename} {
+ lset data 2 ${::editor_encoding}
+ $listbox_project_files itemconfigure $item -data $data
+ break
+ }
+ }
+ }
+ }
+
+ ## Change EOL in the current editor
+ # @return void
+ public method change_EOL {} {
+ if {$splitted && $selectedView} {
+ set idx $actualEditor2
+ } {
+ set idx $actualEditor
+ }
+ if {[lindex $file_eol $idx] == ${::editor_EOL}} {
+ return
+ }
+
+ # Configure editor
+ lset file_eol $idx ${::editor_EOL}
+ [lindex $editors $idx] configure -eol ${::editor_EOL}
+
+ # Configure list of project files
+ set filename [[lindex $editors $idx] cget -fullFileName]
+ foreach item [$listbox_project_files items] {
+ set data [$listbox_project_files itemcget $item -data]
+ if {[lindex $data 0] == $filename} {
+ lset data 1 ${::editor_EOL}
+ $listbox_project_files itemconfigure $item -data $data
+ break
+ }
+ }
+ }
+
+ ## Change RO mode in the current editor
+ # @return void
+ public method switch_editor_RO_MODE {} {
+ if {$splitted && $selectedView} {
+ set idx $actualEditor2
+ } {
+ set idx $actualEditor
+ }
+ if {[lindex $file_ro_mode $idx] == ${::editor_RO_MODE}} {
+ return
+ }
+
+ # Configure editor
+ lset file_ro_mode $idx ${::editor_RO_MODE}
+ [lindex $editors $idx] change_RO_MODE ${::editor_RO_MODE}
+
+ # Configure list of project files
+ set filename [[lindex $editors $idx] cget -fullFileName]
+ foreach item [$listbox_project_files items] {
+ set data [$listbox_project_files itemcget $item -data]
+
+ # Unknown bug workaround :-(
+ if {[llength $data] < 4} {
+ puts "data == {$data}" ;# Dump
+ lappend data {}
+ }
+
+ if {[lindex $data 0] == $filename} {
+ lset data 3 ${::editor_RO_MODE}
+ $listbox_project_files itemconfigure $item -data $data
+ break
+ }
+ }
+ }
+
+ ## Adjust scrollbar for listbox of opened files
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method filelist_o_scrollbar_set {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {$o_scrollbar_visible} {
+ pack forget $opened_files_scrollbar
+ set o_scrollbar_visible 0
+ }
+ # Show scrollbar
+ } {
+ if {!$o_scrollbar_visible} {
+ pack $opened_files_scrollbar \
+ -side left \
+ -fill y \
+ -before $listbox_opened_files_bm
+ set o_scrollbar_visible 1
+ }
+ # Adjust icon border
+ $listbox_opened_files_bm yview moveto $frac0
+ # Adjust scrollbar
+ $opened_files_scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Scroll synchronously listbox of opened files and its icon border
+ # @parm List - arguments for subcommand yview
+ # @return void
+ public method filelist_o_scroll args {
+ eval "$listbox_opened_files yview $args"
+ eval "$listbox_opened_files_bm yview $args"
+ }
+
+ ## Adjust scrollbar for listbox of opened files
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method filelist_p_scrollbar_set {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {$p_scrollbar_visible} {
+ pack forget $project_files_scrollbar
+ set p_scrollbar_visible 0
+ }
+ # Show scrollbar
+ } {
+ if {!$p_scrollbar_visible} {
+ pack $project_files_scrollbar \
+ -side left \
+ -fill y \
+ -before $listbox_project_files_bm
+ set p_scrollbar_visible 1
+ }
+ # Adjust icon border
+ $listbox_project_files_bm yview moveto $frac0
+ # Adjust scrollbar
+ $project_files_scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Scroll synchronously listbox of project files and its icon border
+ # @parm List - arguments for subcommand yview
+ # @return void
+ public method filelist_p_scroll args {
+ eval "$listbox_project_files yview $args"
+ eval "$listbox_project_files_bm yview $args"
+ }
+
+ ## Validator function for search entry in tab of opened files
+ # @parm String content - String which to search for (in listbox of opened files)
+ # @return Bool - always 1
+ public method filelist_opened_search {content} {
+ # Empty input string
+ if {$content == {}} {
+ $opened_search_clear_button configure -state disabled
+ $opened_search_entry configure -style TEntry
+ opened_files_unhighlight_item
+ return 1
+ }
+
+ # Enable clear button
+ $opened_search_clear_button configure -state normal
+
+ # Search the listbox
+ foreach item [$listbox_opened_files items] {
+ if {![string first $content [$listbox_opened_files itemcget $item -text]]} {
+ $opened_search_entry configure -style StringFound.TEntry
+ opened_files_highlight_item $item
+ return 1
+ }
+ }
+
+ # Search failed
+ $opened_search_entry configure -style StringNotFound.TEntry
+ return 1
+ }
+
+
+ ## Highlight item in listbox of opened files
+ # @parm String item - item ID
+ # @return void
+ private method opened_files_highlight_item {item} {
+ opened_files_unhighlight_item
+ set opened_files_highlighted_item $item
+ set opened_files_hg_item_fg_clr [$listbox_opened_files itemcget $item -fg]
+ $listbox_opened_files itemconfigure $item -indent 10 -fg {#00DD00}
+ $listbox_opened_files see $item
+ }
+
+ ## Clear highlightion for currently highlighted item in listbox of opened files
+ # @return void
+ private method opened_files_unhighlight_item {} {
+ # If no item highlighted -> abort
+ if {$opened_files_highlighted_item == {}} {
+ return
+ }
+
+ # Unhighlight item
+ $listbox_opened_files itemconfigure \
+ $opened_files_highlighted_item \
+ -indent 0 -fg $opened_files_hg_item_fg_clr
+ set opened_files_hg_item_fg_clr {}
+ set opened_files_highlighted_item {}
+ }
+
+ ## Validator function for search entry in tab of project files
+ # @parm String content - String which to search for (in listbox of project files)
+ # @return Bool - always 1
+ public method filelist_project_search {content} {
+ # Empty input string
+ if {$content == {}} {
+ $project_search_clear_button configure -state disabled
+ $project_search_entry configure -style TEntry
+ project_files_unhighlight_item
+ return 1
+ }
+
+ # Enable clear button
+ $project_search_clear_button configure -state normal
+
+ # Search the listbox
+ foreach item [$listbox_project_files items] {
+ if {![string first $content [$listbox_project_files itemcget $item -text]]} {
+ $project_search_entry configure -style StringFound.TEntry
+ project_files_highlight_item $item
+ return 1
+ }
+ }
+
+ # Search failed
+ $project_search_entry configure -style StringNotFound.TEntry
+ return 1
+ }
+
+ ## Highlight item in listbox of project files
+ # @parm String item - item ID
+ # @return void
+ private method project_files_highlight_item {item} {
+ project_files_unhighlight_item
+ set project_files_highlighted_item $item
+ set project_files_hg_item_fg_clr [$listbox_project_files itemcget $item -fg]
+ $listbox_project_files itemconfigure $item -indent 10 -fg {#00DD00}
+ $listbox_project_files see $item
+ }
+
+ ## Clear highlightion for currently highlighted item in listbox of project files
+ # @return void
+ private method project_files_unhighlight_item {} {
+ # If no item highlighted -> abort
+ if {$project_files_highlighted_item == {}} {
+ return
+ }
+
+ # Unhighlight item
+ $listbox_project_files itemconfigure \
+ $project_files_highlighted_item \
+ -indent 0 -fg $project_files_hg_item_fg_clr
+ set project_files_hg_item_fg_clr {}
+ set project_files_highlighted_item {}
+ }
+
+ ## Binding for virtual event '<<ListboxSelect>>' for listbox of project files
+ # Clear search entry and unhighlight currently highlighted item (if any)
+ # @return void
+ public method project_files_listbox_select {} {
+ $project_search_entry delete 0 end
+ $this FileList_project_disEna_buttons
+ }
+
+ ## Add/Remove bookmark to/from item in listbox of opened files
+ # @parm Int x - Relative position in icon border (X axis)
+ # @parm Int y - Relative position in icon border (Y axis)
+ # @return void
+ public method filelist_opened_bookmark_xy {x y} {
+ opened_files_bookmark [expr {int([$listbox_opened_files_bm index @$x,$y]) - 1}]
+ }
+
+ ## Add/Remove bookmark to/from item in listbox of opened files
+ # Affects currently selected item
+ # @return void
+ public method filelist_o_bookmark {} {
+ opened_files_bookmark [$listbox_opened_files index \
+ [$listbox_opened_files selection get]]
+ }
+
+ ## Add/Remove bookmark to/from item in listbox of opened files
+ # @parm Int line - Target line (begins from zero)
+ # @return void
+ public method opened_files_bookmark {line} {
+ # Check for allowed range
+ if {$line >= [llength $opened_files_bookmarks]} {
+ return
+ }
+
+ set page [lindex [$listbox_opened_files items] $line]
+
+ # Remove bookmark
+ if {[lindex $opened_files_bookmarks $line]} {
+ lset opened_files_bookmarks $line 0
+ incr line
+ $listbox_opened_files_bm delete $line.0 [list $line.0 lineend]
+
+ set ext [string trimleft [file extension [$listbox_opened_files itemcget $page -text]] {.}]
+ if {$ext == {h}} {
+ set icon {source_h}
+ } elseif {$ext == {c}} {
+ set icon {source_c}
+ } elseif {$ext == {cxx} || $ext == {cpp} || $ext == {cc}} {
+ set icon {source_cpp}
+ } elseif {$ext == {asm}} {
+ set icon {asm}
+ } else {
+ set icon {ascii}
+ }
+ $filetabs_nb itemconfigure $page -image ::ICONS::16::$icon
+
+ # Add bookmark
+ } {
+ lset opened_files_bookmarks $line 1
+ incr line
+ $listbox_opened_files_bm image create $line.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+
+ $filetabs_nb itemconfigure $page -image ::ICONS::16::bookmark
+ }
+
+ $listbox_opened_files_bm tag add center 0.0 end
+ }
+
+ ## Invoke icon border popup menu -- list of opened files
+ # @parm Int x - Abolute position in icon border (X axis)
+ # @parm Int y - Abolute position in icon border (Y axis)
+ # @parm Int x - Relative position in icon border (X axis)
+ # @parm Int y - Relative position in icon border (Y axis)
+ # @return void
+ public method filelist_opened_bm_popup_menu {X Y x y} {
+ set pmenu_cline [expr {int([$listbox_opened_files_bm index @$x,$y]) - 1}]
+ set bookmark [lindex $opened_files_bookmarks $pmenu_cline]
+ tk_popup $IB_o_menu $X $Y
+ }
+
+ ## Add/Remove bookmark to/from item in listbox of project files
+ # @parm Int x - Relative position in icon border (X axis)
+ # @parm Int y - Relative position in icon border (Y axis)
+ # @return void
+ public method filelist_project_bookmark_xy {x y} {
+ project_files_bookmark [expr {int([$listbox_project_files_bm index @$x,$y]) - 1}]
+ }
+
+ ## Add/Remove bookmark to/from item in listbox of project files
+ # Affects currently selected item
+ # @return void
+ public method filelist_p_bookmark {} {
+ project_files_bookmark [$listbox_project_files index \
+ [$listbox_project_files selection get]]
+ }
+
+ ## Add/Remove bookmark to/from item in listbox of project files
+ # @parm Int line - Target line (begins from zero)
+ # @return void
+ public method project_files_bookmark {line} {
+ # Check for allowed range
+ if {($line < 0) || ($line >= [llength $project_files_bookmarks])} {
+ return
+ }
+
+ # Remove bookmark
+ if {[lindex $project_files_bookmarks $line]} {
+ lset project_files_bookmarks $line 0
+ incr line
+ $listbox_project_files_bm delete $line.0 [list $line.0 lineend]
+ # Add bookmark
+ } {
+ lset project_files_bookmarks $line 1
+ incr line
+ $listbox_project_files_bm image create $line.0 \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+
+ $listbox_project_files_bm tag add center 0.0 end
+ }
+
+ ## Invoke icon border popup menu -- list of project files
+ # @parm Int x - Abolute position in icon border (X axis)
+ # @parm Int y - Abolute position in icon border (Y axis)
+ # @parm Int x - Relative position in icon border (X axis)
+ # @parm Int y - Relative position in icon border (Y axis)
+ # @return void
+ public method filelist_project_bm_popup_menu {X Y x y} {
+ set pmenu_cline [expr {int([$listbox_project_files_bm index @$x,$y]) - 1}]
+ set bookmark [lindex $project_files_bookmarks $pmenu_cline]
+ tk_popup $IB_p_menu $X $Y
+ }
+
+ ## Clear flag "command line on"
+ # @return void
+ public method cmd_line_off {} {
+ set editor_command_line_on 0
+ if {$splitted} {
+ [lindex $editors $actualEditor2] cmd_line_force_off
+ }
+ [lindex $editors $actualEditor] cmd_line_force_off
+ }
+
+ ## Set flag "command line on"
+ # All editors in current project will focus on command line
+ # @return void
+ public method cmd_line_on {} {
+ set editor_command_line_on 1
+ if {$splitted} {
+ [lindex $editors $actualEditor2] cmd_line_force_on
+ }
+ [lindex $editors $actualEditor] cmd_line_force_on
+
+ if {$splitted && $selectedView} {
+ [lindex $editors $actualEditor2] cmd_line_focus 1
+ } {
+ [lindex $editors $actualEditor] cmd_line_focus 1
+ }
+ }
+
+ ## Split editor vertical
+ # @return void
+ public method split_vertical {} {
+ split_editor 1
+ }
+
+ ## Split editor horizontal
+ # @return void
+ public method split_horizontal {} {
+ split_editor 0
+ }
+
+ ## Close current view (if editor is splitted)
+ # If editor is already splitted this procedure will do nothing
+ # @return void
+ public method close_current_view {editor_object} {
+ if {!$splitted} {return}
+
+ # Save current sash position
+ if {$pwin_orient == {vertical}} {
+ set idx 1
+ } {
+ set idx 0
+ }
+ set multiview_sash_pos [lindex [$multiview_paned_win sash coord 0] $idx]
+
+ # Unmap paned window and the second pages manager and remap the first pages manager
+ $multiview_paned_win forget $pagesManager2
+ $multiview_paned_win forget $pagesManager
+ pack forget $multiview_paned_win
+ pack $pagesManager -fill both -expand 1
+
+ # Configure all editor status bar popup menus
+ foreach editor $editors {
+ $editor configure_statusbar_menu 1 0 {} {}
+ }
+
+ # Determinate which editor will be visible now
+ if {$editor_object != {}} {
+ set editor_object [lsearch $editors $editor_object]
+ if {$editor_object == $actualEditor2} {
+ set selectedView 1
+ } {
+ set selectedView 0
+ }
+ }
+
+ # Insure than the choosen editor (see above) is (in)visible
+ if {!$selectedView} {
+ $listbox_opened_files selection set [lindex $file_descriptors $actualEditor2]
+ }
+ set selectedView 0
+ set splitted 0
+ set actualEditor2 -1
+ switchfile
+ }
+
+ ## Syntax highlight changed from editor
+ # @parm Object editor_object - New active editor object reference
+ # @parm Int lang - -1 == unknown; 0 == Assembly language; 1 == C language
+ # @return void
+ public method filelist_editor_sh_changed {editor_object lang} {
+ lset file_sh [lsearch $editors $editor_object] $lang
+ }
+
+ ## Change active view if editor is splitted
+ # If editor is already splitted this procedure will do nothing
+ # @parm Object editor_object - New active editor object reference
+ # @return void
+ public method filelist_editor_selected {editor_object} {
+ if {!$splitted} {return}
+
+ # Search for the given object
+ set idx [lsearch $editors $editor_object]
+ if {$idx == $actualEditor} {
+ set selectedView 0
+ } elseif {$idx == $actualEditor2} {
+ set selectedView 1
+ }
+ rightPanel_switch_editor_vars $idx
+ $this todo_switch_editor_vars $idx
+
+ # Adjust selection in list of opened files
+ set item [lindex $file_descriptors $idx]
+ $listbox_opened_files selection set $item
+ catch {$listbox_opened_files itemconfigure $lastItem -image {}}
+ $listbox_opened_files itemconfigure $item -image ::ICONS::16::2_rightarrow
+ set lastItem $item
+
+ update
+ $filetabs_nb raise [lindex $file_descriptors $idx]
+ $filetabs_nb see [lindex $file_descriptors $idx]
+ rightPanel_switch_page $idx
+ $this todo_switch_editor $idx
+ listBox_disEna_buttons $item $editor_object
+ ::X::adjust_title
+ ::X::adjust_mainmenu_and_toolbar_to_editor \
+ ${::editor_RO_MODE} [expr {[$editor_object get_language] == 1}]
+ }
+
+ ## Split editor vertical or horizontal
+ # If editor is already splitted this procedure will do nothing
+ # @parm Bool vert_or_horz - 1 == Vertical; 0 == Horizontal
+ # @return void
+ private method split_editor {vert_or_horz} {
+ if {$splitted} {return}
+
+ # Determinate orientation
+ if {$vert_or_horz} {
+ set pwin_orient {horizontal}
+ } {
+ set pwin_orient {vertical}
+ }
+ $multiview_paned_win configure -orient $pwin_orient
+
+ # Validate sash position
+ if {!$multiview_sash_pos} {
+ set multiview_sash_pos [expr {[winfo width $pagesManager] / 2}]
+ }
+
+ # Unmap current pages manager and remap it with the second one into paned window
+ pack forget $pagesManager
+ pack $multiview_paned_win -fill both -expand 1
+ $multiview_paned_win add $pagesManager
+ $multiview_paned_win add $pagesManager2 -after $pagesManager
+
+ # Configure minimum size for panes
+ if {$vert_or_horz} {
+ set minsize 300
+ } {
+ set minsize 80
+ }
+ $multiview_paned_win paneconfigure $pagesManager -minsize $minsize
+ $multiview_paned_win paneconfigure $pagesManager2 -minsize $minsize
+
+ # Move paned window sash
+ update idle
+ if {$pwin_orient == {vertical}} {
+ $multiview_paned_win sash place 0 0 $multiview_sash_pos
+ } {
+ $multiview_paned_win sash place 0 $multiview_sash_pos 0
+ }
+
+ # Configure status bar popup menu for all opened editors
+ foreach editor $editors {
+ $editor configure_statusbar_menu 0 1 {} {}
+ }
+
+ # Show up some editor in the second view
+ set splitted 1
+ set selectedView 0
+ set len [llength $file_descriptors]
+ if {$len > 1} {
+ if {$actualEditor < ($len - 1)} {
+ set actualEditor2 [expr {$actualEditor + 1}]
+ } {
+ set actualEditor2 0
+ }
+ } {
+ set selectedView 1
+ editor_new
+ set selectedView 0
+ }
+ pack [[lindex $editors $actualEditor2] cget -ed_sc_frame] \
+ -in $pagesManager2 -fill both -expand 1
+ }
+
+ ## Sort items in list of opened files or project files
+ # @parm Char by - {S} == Size; {U} == URL; {N} == Name
+ # @parm Bool opened_project - 1 == List of opened files; 0 == List of project files
+ # @return void
+ public method sort_file_list {by opened_project} {
+ if {$opened_project} {
+ set listbox $listbox_opened_files
+ set bookmarks_text $listbox_opened_files_bm
+ set bookmarks_var {opened_files_bookmarks}
+ } {
+ set listbox $listbox_project_files
+ set bookmarks_text $listbox_project_files_bm
+ set bookmarks_var {project_files_bookmarks}
+ }
+
+ # Determinate list of values (strings or integers) to sort
+ set items {} ;# List of values to sort
+ set num_of_items 0 ;# Length of items
+ foreach item [$listbox items] {
+ switch -- $by {
+ {N} { ;# For sorting by name
+ lappend items [$listbox itemcget $item -text]
+ }
+ {U} { ;# For sorting by URL
+ set data [$listbox itemcget $item -data]
+ if {!$opened_project} {
+ # Unopened file
+ if {[llength $data] > 4} {
+ set data [lindex $data 5]
+
+ # Opened file
+ } {
+ set data [lindex $data 0]
+ }
+ }
+ lappend items $data
+ }
+ {S} { ;# For sorting by size
+ set path [$listbox itemcget $item -data]
+ if {!$opened_project} {
+ # Unopened file
+ if {[llength $path] > 4} {
+ set path [lindex $path 5]
+
+ # Opened file
+ } {
+ set path [lindex $path 0]
+ }
+ }
+ set size 0
+ catch {
+ set size [file size $path]
+ }
+ lappend items $size
+ }
+ }
+ incr num_of_items
+ }
+
+ # List of item indexes in new order (e.g. {0 2 1 3 4 5 7 6})
+ set new_order {}
+ for {set i 0} {$i < $num_of_items} {incr i} {
+ lappend new_order $i
+ }
+
+ ## Sort lists items and new_order using Bouble Sort
+ # By name of URL (string comparison)
+ if {$by == {N} || $by == {U}} {
+ for {set i 1} {$i < $num_of_items} {incr i} {
+ for {set j 1; set k 0} {$j < $num_of_items} {incr j; incr k} {
+ if {[string compare [lindex $items $k] [lindex $items $j]] < 0} {
+ set tmp [lindex $items $k]
+ lset items $k [lindex $items $j]
+ lset items $j $tmp
+
+ set tmp [lindex $new_order $k]
+ lset new_order $k [lindex $new_order $j]
+ lset new_order $j $tmp
+ }
+ }
+ }
+ # By size (integer comparison)
+ } {
+ for {set i 1} {$i < $num_of_items} {incr i} {
+ for {set j 1; set k 0} {$j < $num_of_items} {incr j; incr k} {
+ if {[lindex $items $k] > [lindex $items $j]} {
+ set tmp [lindex $items $k]
+ lset items $k [lindex $items $j]
+ lset items $j $tmp
+
+ set tmp [lindex $new_order $k]
+ lset new_order $k [lindex $new_order $j]
+ lset new_order $j $tmp
+ }
+ }
+ }
+ }
+
+ # Reorder list of bookmarks and
+ #+ determinate list of item descriptors in the new order.
+ #+ No GUI will be affected
+ set new_items_order {}
+ set bookmarks_new {}
+ set bookmarks_org [subst "\$$bookmarks_var"]
+ for {set i 0} {$i < $num_of_items} {incr i} {
+ set idx [lindex $new_order $i]
+ lappend new_items_order [$listbox items $idx]
+ lappend bookmarks_new [lindex $bookmarks_org $idx]
+ }
+ set $bookmarks_var $bookmarks_new
+
+ # Adjust GUI to the new order
+ $listbox reorder $new_items_order
+ $bookmarks_text delete 1.0 end
+ foreach bm $bookmarks_new {
+ if {$bm} {
+ $bookmarks_text image create insert \
+ -image ::ICONS::16::bookmark \
+ -align center
+ }
+ $bookmarks_text insert end "\n"
+ }
+ }
+
+ ## Open selected file with an external editor
+ # @parm Bool o_p - 1 == opened file; 0 == project file
+ # @parm String command - Command to execute the editor
+ # @return void
+ public method filelist_open_with {o_p command} {
+ # Determinate filename
+ if {$o_p} {
+ set item [$listbox_opened_files selection get]
+ if {![$listbox_opened_files exists $item]} {
+ return
+ }
+ set filename [$listbox_opened_files itemcget $item -data]
+ } {
+ set item [$listbox_project_files selection get]
+ if {![$listbox_project_files exists $item]} {
+ return
+ }
+ set data [$listbox_project_files itemcget $item -data]
+ if {[llength $data] < 5} {
+ set filename [lindex $data 0]
+ } {
+ set filename "[lindex $data 5][lindex $data 0]"
+ }
+ }
+
+ # Adjust editor command
+ if {$command == {other}} {
+ set command [open_with_other]
+ }
+ if {$command == {}} {
+ return
+ }
+
+ # Start external editor
+ if {[catch {
+ exec $command "$filename" &
+ }]} {
+ tk_messageBox \
+ -parent . \
+ -icon error \
+ -type ok \
+ -title [mc "Program not found"] \
+ -message [mc "Unable to execute \"%s\"" $command]
+ }
+ }
+
+ ## Open dialog "Open with other editor" and return text entered by user
+ # @return String - Command which executes exernal editor
+ private method open_with_other {} {
+ set ::FileList::open_with_cnfr 0
+
+ # Create toplevel window
+ set win [toplevel .open_with_other_dlg -class {Open with ...} -bg {#EEEEEE}]
+
+ # Create label, entryBox and horizontal separator
+ pack [label $win.lbl -text [mc "Enter command to execute:"]] -fill x -anchor w -padx 5
+ pack [ttk::entry $win.ent \
+ -textvariable ::FileList::open_with \
+ -width 0 \
+ ] -fill x -padx 10 -anchor w
+# pack [ttk::separator $win.sep -orient horizontal] -fill x -padx 5 -pady 10
+
+ bind $win.ent <Return> "grab release $win; destroy $win"
+ bind $win.ent <KP_Enter> "grab release $win; destroy $win"
+
+ # Create button frame
+ set buttonFrame [frame $win.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "
+ set ::FileList::open_with_cnfr 1
+ grab release $win
+ destroy $win
+ " \
+ ] -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ grab release $win
+ destroy $win
+ " \
+ ] -side left
+ pack $buttonFrame -side bottom -padx 5 -pady 5 -anchor e
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::terminal
+ wm title $win [mc "Open with other ..."]
+ wm minsize $win 320 80
+ wm transient $win .
+ catch {grab $win}
+ wm protocol $win WM_DELETE_WINDOW "
+ grab release $win
+ destroy $win
+ "
+ raise $win
+ update
+ $win.ent selection range 0 end
+ focus $win.ent
+ tkwait window $win
+
+ # Return result
+ if {${::FileList::open_with_cnfr}} {
+ return ${::FileList::open_with}
+ } {
+ return {}
+ }
+ }
+
+ ## Kill childern
+ # @return void
+ public method filelist_kill_childern {} {
+ foreach editor $editors {
+ $editor kill_childern
+ }
+ }
+
+ ## Focus and conditionaly open editor with the specified filename
+ # @parm String filename - Name of file
+ # @parm Bool suppress_error - Suppress error messages
+ # @return Bool - 1 == Success; 0 == Fail
+ public method fucus_specific_editor {filename suppress_error} {
+
+ # Search list of opened files
+ foreach item [$listbox_opened_files items] {
+ if {$filename == [$listbox_opened_files itemcget $item -text]} {
+ $listbox_opened_files selection set $item
+ switchfile
+ return 1
+ }
+ }
+ # Search list of project files
+ foreach item [$listbox_project_files items] {
+ if {$filename == [$listbox_project_files itemcget $item -text]} {
+ $listbox_project_files selection set $item
+ filelist_project_file_open
+ return 1
+ }
+ }
+
+ # Display error message
+ if {!$suppress_error} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "File not found"] \
+ -message [mc "Unable to find \"%s\" in list of opened files or project files" $filename]
+ }
+ return 0
+ }
+
+ ## Move simulator pointer in editor
+ # - Switch to specified editor and go to specified line
+ # @parm List line_info - Line information number {Line_number File_number}
+ # @retun void
+ public method move_simulator_line {line_info} {
+ set line_number [lindex $line_info 0]
+ set file_number [lindex $line_info 1]
+
+ if {$line_number == {}} {
+ return
+ }
+
+ if {[$this cget -programming_language]} {
+ $this cvarsview_load_local_variables [lindex $line_info 2] [lindex $line_info 3]
+ }
+
+ # Switch file
+ if {$file_number != {} && $simulator_editor != $file_number} {
+ # Gain target file name
+ set file_name [$this simulator_get_filename $file_number]
+
+ # Search for the given file and try to switch to it
+ if {$file_switching_enabled || $simulator_editor == -1} {
+ foreach item [$listbox_opened_files items] {
+ if {$file_name != [$listbox_opened_files itemcget $item -data]} {
+ continue
+ }
+
+ $listbox_opened_files selection set $item
+ if {$simulator_editor_obj != {}} {
+ $simulator_editor_obj disable
+ $listbox_opened_files itemconfigure [lindex \
+ $file_descriptors [lsearch -ascii -exact \
+ $editors $simulator_editor_obj \
+ ] \
+ ] -fg {#000000}
+ }
+ $listbox_opened_files itemconfigure $item -fg {#FF0000}
+ set simulator_editor_obj [lindex $editors \
+ [lsearch -ascii -exact $file_descriptors $item] \
+ ]
+ $simulator_editor_obj freeze
+ $simulator_editor_obj move_simulator_line $line_number
+ switchfile
+ set simulator_editor $file_number
+ return
+ }
+ }
+ Sbar [mc "Simulator: unable to switch to file: '%s'" $file_name]
+
+ # Move simulator pointer directly
+ } elseif {$simulator_editor_obj != {}} {
+ $simulator_editor_obj move_simulator_line $line_number
+ }
+ }
+
+ ## Get editor object used by simulator
+ # @return Object - Editor object
+ public method filelist_get_simulator_editor_obj {} {
+ return $simulator_editor_obj
+ }
+
+ ## Set "auto file switch" lock
+ # @parm Object from_obj - Editor object from which this procedure is called
+ # @parm Bool new_state - New state of the lock
+ # @return void
+ public method set_editor_lock {from_obj new_state} {
+ foreach editor $editors {
+ if {$editor == $from_obj} {
+ continue
+ }
+ $editor set_lock $new_state
+ }
+ set file_switching_enabled [expr {!$new_state}]
+ }
+
+ ## Get value of "auto file switch lock"
+ # This lock disables automatic file switching during sumulation
+ # @return Bool - 1 == unlocked; 0 == locked
+ public method get_file_switching_enabled {} {
+ return $file_switching_enabled
+ }
+
+ ## Redraw panel pane
+ # @return void
+ public method leftpanel_redraw_pane {} {
+ update idle
+ if {$PanelVisible != 0} {
+ $parent sash place 0 $PanelSize 0
+ }
+ }
+
+ ## Get object reference for the current editor
+ # @return Object - Active editor
+ public method get_current_editor_object {} {
+ if {$splitted && $selectedView} {
+ set editor_num $actualEditor2
+ } {
+ set editor_num $actualEditor
+ }
+ return [lindex $editors $editor_num]
+ }
+
+ ## Show or hide the tab bar
+ # @return void
+ public method show_hide_tab_bar {} {
+ # Show
+ if {${::CONFIG(SHOW_EDITOR_TAB_BAR)}} {
+ if {![winfo ismapped $filetabs_frm]} {
+ if {$splitted} {
+ set before $multiview_paned_win
+ } {
+ set before $pagesManager
+ }
+ pack $filetabs_frm -fill x -before $before
+
+ filelist_adjust_size_of_tabbar
+ }
+ # Hide
+ } {
+ if {[winfo ismapped $filetabs_frm]} {
+ pack forget $filetabs_frm
+ }
+ }
+ }
+
+ ## Special purpose method (see the usage in the code)
+ # It should be used to ensure that the height of the tab bat is not too big
+ # @return void
+ public method filelist_adjust_size_of_tabbar {} {
+ $filetabs_nb see [lindex [$filetabs_nb pages] 0]
+ update
+ catch {
+ $filetabs_nb.c configure -height 20
+ }
+ $filetabs_nb see [$filetabs_nb raise]
+
+ # Keep editor nice after adjustment of filestab height
+ if {!${::Editor::editor_to_use}} {
+ [get_current_editor_object] scroll scroll +0 lines
+ }
+ }
+
+ ## Call method Configure in both editors
+ # @return void
+ public method ensure_that_both_editors_are_properly_initialized {} {
+ if {$splitted} {
+ update
+ [lindex $editors $actualEditor] Configure
+ [lindex $editors $actualEditor2] Configure
+ }
+ }
+}
+set ::FileList::ask__append_file_to_project ${::CONFIG(ASK_ON_FILE_OPEN)}
diff --git a/lib/leftpanel/fsbrowser.tcl b/lib/leftpanel/fsbrowser.tcl
new file mode 100755
index 0000000..0a28d82
--- /dev/null
+++ b/lib/leftpanel/fsbrowser.tcl
@@ -0,0 +1,1164 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements file system browser for the left panel
+# --------------------------------------------------------------------------
+
+class FSBrowser {
+
+ # Definition of popup menu for filesystem browser, part: configure
+ common FSMENU_CONFIGURE {
+ {cascade "Sorting" 0 "" .sorting false 1 {
+ {radiobutton "By Name" "" {::KIFSD::FSD::config(sorting)}
+ {name} {filelist_fsb_reload} 3
+ "Sort files by name"}
+ {radiobutton "By Date" "" {::KIFSD::FSD::config(sorting)}
+ {date} {filelist_fsb_reload} 3
+ "Sort files by date"}
+ {radiobutton "By Size" "" {::KIFSD::FSD::config(sorting)}
+ {size} {filelist_fsb_reload} 3
+ "Sort files by size"}
+ {separator}
+ {checkbutton "Reverse" ""
+ {::KIFSD::FSD::config(reverse_sorting)} 1 0 0
+ {filelist_fsb_reload} "Decremental sorting"}
+ {checkbutton "Case insensitive" ""
+ {::KIFSD::FSD::config(case_insensitive)} 1 0 0
+ {filelist_fsb_reload} "Sorting mode ASCII / Dictionary"}
+ }}
+ {checkbutton "Show hidden files" ""
+ {::KIFSD::FSD::config(show_hidden_files)} 1 0 5
+ {filelist_fsb_reload} "Show / Ignore files starting with dot"}
+ }
+
+ # Definition of popup menu for filesystem browser, part: listbox
+ common FSMENU_LISTBOX {
+ {command {Up} {} 0 "filelist_fsb_up" {up}
+ "Go to parent folder"}
+ {command {Back} {} 0 "filelist_fsb_back" {left}
+ "Go back in history"}
+ {command {Forward} {} 0 "filelist_fsb_forward" {right}
+ "Go forward in history"}
+ {separator}
+ {command {Home} {} 0 "filelist_fsb_gohome" {gohome}
+ "Go to your home folder"}
+ {command {Reload} {} 1 "filelist_fsb_reload" {reload}
+ "Reload filelist"}
+ {separator}
+ {command {Rename} {} 0 "filelist_fsb_rename" {edit}
+ "Rename file"}
+ {command {Delete} {} 0 "filelist_fsb_delete" {editdelete}
+ "Delete file"}
+ {command {New folder} {} 0 "filelist_fsb_new_folder" {folder_new}
+ "Create new directory"}
+ {command {Bookmark folder} {} 0 "filelist_fsb_bookmark_this" {bookmark_add}
+ "Bookmark the current directory"}
+ {separator}
+ {command {Properties} {} 0 "filelist_fsb_properties" {}
+ "Show file properties"}
+ }
+
+ # Definition of popup menu for filesystem browser, part: bookmarks
+ common FSMENU_BOOKMARKS {
+ {command {Add bookmark} {} 0 "filelist_fsb_add_bookmark"
+ {bookmark_add} "Bookmark the current folder"}
+ {command {Edit bookmarks} {} 0 "filelist_fsb_edit_bookmarks"
+ {bookmark} "Invoke bookmark editor"}
+ {separator}
+ }
+
+ ## PRIVATE
+ private variable fs_browser_selected_item {} ;# Item selected by popup menu for filesystem browser
+ private variable fs_browser_selection_in_P 0 ;# Procedure "filelist_fsb_select" in progress
+ private variable fs_browser_listbox_top_frame ;# Top frame of filesystem browser
+ private variable forward_history {} ;# List of forward history (filesystem browser)
+ private variable back_history {} ;# List of backward history (filesystem browser)
+ private variable fs_browser_current_dir ;# Current directory (filesystem browser)
+ private variable fs_browser_conf_menu ;# ID of filesystem browser configuration menu
+ private variable fs_browser_dir_ok ;# Button: Confirm location
+ private variable fs_browser_listbox_menu ;# ID of popup menu for filesystem browser
+ private variable fs_browser_bm_menu ;# ID of bookmarks popup menu (filesystem browser)
+ private variable fs_browser_toolbar ;# ID of filesystem browser toolbar
+ private variable fs_browser_dir ;# ComboBox: Current directory
+ private variable fs_browser_listbox ;# ListBox: Files & Directories
+ private variable fs_browser_listbox_v_scrollbar ;# Vertical scrollbar for filesystem browser
+ private variable fs_browser_listbox_h_scrollbar ;# Horizontal scrollbar for filesystem browser
+ private variable fs_browser_filter ;# ComboBox: Filter
+ private variable item_menu_invoked 0 ;# Bool: Item menu request
+ # Current GLOB filter for filesystem browser
+ private variable fs_browser_current_mask ${::CONFIG(FS_BROWSER_MASK)}
+
+ # Variables related to object initialization
+ private variable parent
+ private variable gui_initialized 0
+
+ constructor {} {
+ # Configure local ttk styles
+ ttk::style configure FSBrowser_RedBg.TCombobox \
+ -fieldbackground {#FFDDDD}
+ ttk::style map FSBrowser_RedBg.TCombobox \
+ -fieldbackground [list {readonly !readonly} {#FFDDDD}]
+ }
+
+ destructor {
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - GUI parent widget
+ # @return void
+ public method PrepareFSBrowser {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Create GUI of tab "File system browser"
+ # @return void
+ public method CreateFSBrowserGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ set fs_browser_current_dir [$this cget -projectPath]
+
+ # Toolbar
+ set fs_browser_toolbar [frame $parent.toolbar]
+ iconBarFactory $fs_browser_toolbar "$this " \
+ [string range $fs_browser_toolbar 1 end] ::ICONS::16:: {
+ {up "Up" {up} {filelist_fsb_up}
+ "Go to parent folder"}
+ {back "Back" {left} {filelist_fsb_back}
+ "Back in history"}
+ {forward "Forward" {right} {filelist_fsb_forward}
+ "Forward in history"}
+ {separator}
+ {bookmark "Bookmark" {bookmark_toolbar} {filelist_fsb_popup_bm_menu}
+ "Bookmark menu"}
+ {current "Current document folder" {next} {filelist_fsb_current_doc_folder}
+ "Go to directory containing the current document"}
+ {configure "Configure" {configure} {filelist_fsb_popup_config_menu}
+ "Filesystem browser configuration menu"}
+ }
+ ${fs_browser_toolbar}forward configure -state disabled
+ ${fs_browser_toolbar}back configure -state disabled
+
+ # Directory location bar
+ set fs_browser_dir_frame [frame $parent.dir_frame]
+ set fs_browser_dir [ttk::combobox $fs_browser_dir_frame.dir \
+ -validatecommand [list $this filelist_fsb_validate_dir %P] \
+ -width 1 \
+ -values {} \
+ -validate all \
+ ]
+ bind $fs_browser_dir <Return> [list $this filelist_fsb_dir_ok]
+ bind $fs_browser_dir <KP_Enter> [list $this filelist_fsb_dir_ok]
+ bind $fs_browser_dir <<ComboboxSelected>> "$this filelist_fsb_dir_ok"
+ DynamicHelp::add $fs_browser_dir -text [mc "Current directory"]
+ setStatusTip -widget $fs_browser_dir \
+ -text [mc "Directory location bar"]
+ set fs_browser_dir_ok [ttk::button $fs_browser_dir_frame.ok \
+ -style Flat.TButton \
+ -image ::ICONS::16::key_enter \
+ -command [list $this filelist_fsb_dir_ok] \
+ ]
+ DynamicHelp::add $fs_browser_dir_frame.ok -text [mc "Confirm directory location"]
+ setStatusTip -widget $fs_browser_dir_ok \
+ -text [mc "Confirm directory location"]
+ pack $fs_browser_dir -fill x -expand 1 -side left
+ pack $fs_browser_dir_ok -side right -after $fs_browser_dir
+
+ # ListBox of files and directories
+ set fs_browser_listbox_frame [frame $parent.lsbox_frame]
+ set fs_browser_listbox_top_frame [frame $fs_browser_listbox_frame.tp_frame]
+ set fs_browser_listbox [ListBox $fs_browser_listbox_top_frame.listbox \
+ -bg white -highlightthickness 0 -selectmode single -bd 1 \
+ -selectfill 1 -width 0 -height 10 -highlightcolor {#BBBBFF} \
+ -selectbackground {#8888FF} -selectforeground black \
+ -yscrollcommand "$this filelist_fsb_vscroll" \
+ -xscrollcommand "$this filelist_fsb_hscroll" \
+ ]
+ if {[winfo exists $fs_browser_listbox.c]} {
+ bind $fs_browser_listbox.c <Button-5> {%W yview scroll +5 units; break}
+ bind $fs_browser_listbox.c <Button-4> {%W yview scroll -5 units; break}
+ bind $fs_browser_listbox.c <ButtonRelease-3> \
+ [list $this filelist_fsb_popup_listbox_menu %X %Y]
+ }
+ bind $fs_browser_listbox <<ListboxSelect>> "catch {$this filelist_fsb_select}"
+ $fs_browser_listbox bindText <ButtonRelease-3> \
+ [list $this filelist_fsb_popup_listbox_item_menu %X %Y]
+ $fs_browser_listbox bindImage <ButtonRelease-3> \
+ [list $this filelist_fsb_popup_listbox_item_menu %X %Y]
+
+ # Scrollbars
+ set fs_browser_listbox_v_scrollbar [ttk::scrollbar \
+ $fs_browser_listbox_top_frame.scrollbar \
+ -orient vertical -command "$fs_browser_listbox yview" \
+ ]
+ set fs_browser_listbox_h_scrollbar [ttk::scrollbar \
+ $fs_browser_listbox_frame.scrollbar \
+ -orient horizontal -command "$fs_browser_listbox xview" \
+ ]
+
+ pack $fs_browser_listbox -fill both -expand 1 -side left
+ pack $fs_browser_listbox_top_frame -fill both -expand 1
+
+ # GLOB Filter
+ set fs_browser_bottom_frame [frame $parent.bottom_frame]
+ set fs_browser_filter [ttk::combobox $fs_browser_bottom_frame.filter \
+ -state readonly \
+ -width 0 \
+ -font ${::FileList::opened_file_font} \
+ -values {
+ {*.asm - Assembler}
+ {*.inc - INC files}
+ {*.c - C source}
+ {*.h - C header}
+ {*.lst - Code listing}
+ {* - All files}
+ } \
+ ]
+ bind $fs_browser_filter <Return> [list $this filelist_fsb_filter_ok]
+ bind $fs_browser_filter <KP_Enter> [list $this filelist_fsb_filter_ok]
+ bind $fs_browser_filter <<ComboboxSelected>> [list $this filelist_fsb_filter_ok]
+ DynamicHelp::add $fs_browser_filter -text [mc "Filter"]
+ setStatusTip -widget $fs_browser_filter \
+ -text [mc "File filter"]
+ set val [lsearch -exact -ascii {{*.asm} {*.inc} {*.c} {*.h} {*}} $fs_browser_current_mask]
+ if {$val == -1} {
+ set val 0
+ }
+ $fs_browser_filter current $val
+ pack $fs_browser_filter -fill x -expand 1 -side left
+
+ # Pack componets of filesystem browser
+ pack $fs_browser_toolbar -anchor w
+ pack $fs_browser_dir_frame -fill x -pady 3
+ pack $fs_browser_listbox_frame -fill both -expand 1
+ pack $fs_browser_bottom_frame -fill x -pady 3
+
+ # Create popup menus
+ set fs_browser_conf_menu $parent.conf_menu
+ set fs_browser_listbox_menu $parent.listbox_menu
+ set fs_browser_bm_menu $parent.bm_menu
+ filelist_fsb_makePopupMenu
+
+ # Initialize filesystem browser
+ filelist_fsb_change_dir $fs_browser_current_dir
+ filelist_fsb_refresh_bookmarks
+ }
+
+ ## Popup bookmarks menu for filesystem browser
+ # @return void
+ public method filelist_fsb_popup_bm_menu {} {
+ set x [winfo rootx ${fs_browser_toolbar}bookmark]
+ set y [winfo rooty ${fs_browser_toolbar}bookmark]
+ incr y [winfo height ${fs_browser_toolbar}bookmark]
+
+ tk_popup $fs_browser_bm_menu $x $y
+ }
+
+ ## Popup configuration menu for filesystem browser
+ # @return void
+ public method filelist_fsb_popup_config_menu {} {
+ set x [winfo rootx ${fs_browser_toolbar}configure]
+ set y [winfo rooty ${fs_browser_toolbar}configure]
+ incr y [winfo height ${fs_browser_toolbar}configure]
+
+ tk_popup $fs_browser_conf_menu $x $y
+ }
+
+ ## Popup filesystem browser listbox menu
+ # @parm Int x - Relative horizontal position of mouse pointer
+ # @parm Int y - Relative vertical position of mouse pointer
+ # @return void
+ public method filelist_fsb_popup_listbox_menu {x y} {
+ # If item menu was invoked then abort
+ if {$item_menu_invoked} {
+ set item_menu_invoked 0
+ return
+ }
+
+ # Configure and popup the menu
+ set fs_browser_selected_item {}
+ foreach entry {Rename Delete Properties} {
+ $fs_browser_listbox_menu entryconfigure [::mc $entry] -state disabled
+ }
+ tk_popup $fs_browser_listbox_menu $x $y
+ }
+
+ ## Popup filesystem browser listbox menu
+ # @parm Int x - Relative horizontal position of mouse pointer
+ # @parm Int y - Relative vertical position of mouse pointer
+ # @parm String item - Selected item (file of directory)
+ # @return void
+ public method filelist_fsb_popup_listbox_item_menu {x y item} {
+ if {[$fs_browser_listbox itemcget $item -text] == {..}} {
+ return
+ }
+
+ # Configure and popup the menu
+ set item_menu_invoked 1
+ foreach entry {Rename Delete Properties} {
+ $fs_browser_listbox_menu entryconfigure [::mc $entry] -state normal
+ }
+ set fs_browser_selected_item $item
+ tk_popup $fs_browser_listbox_menu $x $y
+ }
+
+ ## Change current directory in filesystem browser
+ # @parm String dir - New directory location
+ # @return void
+ public method filelist_fsb_change_dir {dir} {
+ if {!$gui_initialized} {CreateFSBrowserGUI}
+
+ if {$::MICROSOFT_WINDOWS} {
+ # Transform for instance "C:" to "C:/"
+ if {[regexp {^\w+:$} $dir]} {
+ append dir {/}
+ }
+ }
+
+ # Check if the given directory is valid
+ if {![file exists $dir] || ![file isdirectory $dir]} {
+ tk_messageBox -parent . \
+ -title [mc "Invalid directory"] \
+ -type ok -icon warning \
+ -message [mc "The specified directory does not exist:\n%s" $dir]
+ return
+ }
+
+ # Normalize path and configure toolbar (history control)
+ set dir [file normalize $dir]
+ if {$dir != $fs_browser_current_dir} {
+ lappend back_history $fs_browser_current_dir
+ set forward_history {}
+ $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state disabled
+ $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state normal
+ ${fs_browser_toolbar}forward configure -state disabled
+ ${fs_browser_toolbar}back configure -state normal
+ }
+ set fs_browser_current_dir $dir
+
+ # Reload contents of browser ListBox
+ set tmp ${::KIFSD::FSD::config(detailed_view)}
+ set ::KIFSD::FSD::config(detailed_view) 0
+ $fs_browser_listbox delete [$fs_browser_listbox items]
+ foreach file [::KIFSD::FSD::dir_file_cmd $dir $fs_browser_current_mask] {
+
+ # Local variables
+ set filename {} ;# File name (if $file file)
+ set folder {} ;# Directory name (if $file is directory)
+ set fullname [lindex $file 0] ;# Full path
+ set text $fullname ;# Text to display
+
+ # Determinate icon
+ switch -- [lindex $file 1] {
+ u { ;# Parent directory
+ set image {up}
+ set folder {..}
+ }
+ d { ;# Directory
+ set image {fileopen}
+ set folder $fullname
+ }
+ f { ;# File
+ set image {ascii}
+ set filename $fullname
+ }
+ }
+
+ # Insert item into the listbox
+ $fs_browser_listbox insert end #auto \
+ -text $text \
+ -image ::ICONS::16::$image \
+ -data [list $filename $folder]
+ }
+ set ::KIFSD::FSD::config(detailed_view) $tmp
+
+ # Configure button "Up"
+ if {$dir == [file separator]} {
+ $fs_browser_listbox_menu entryconfigure [::mc "Up"] -state disabled
+ ${fs_browser_toolbar}up configure -state disabled
+ } {
+ $fs_browser_listbox_menu entryconfigure [::mc "Up"] -state normal
+ ${fs_browser_toolbar}up configure -state normal
+ }
+
+ # Fill directory location combobox
+ set values {}
+ set folder $dir
+ while 1 {
+ lappend values $folder
+ if {$folder == [file separator]} {break}
+ if {$::MICROSOFT_WINDOWS} {
+ if {[regexp {^\w+:[\\\/]?$} $folder]} {break}
+ }
+ set folder [file normalize [file join $folder {..}]]
+ }
+ foreach folder [::KIFSD::FSD::dir_cmd $dir 1] {
+ if {$folder == {..}} {continue}
+ lappend values [file join $dir $folder]
+ }
+ if {$::MICROSOFT_WINDOWS} { ;# Include drive letters on Microsoft Windows
+ foreach drive_letter {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
+ if {[file exists "${drive_letter}:/"]} {
+ lappend values "${drive_letter}:/"
+ }
+ }
+ }
+
+ $fs_browser_dir configure -values $values
+ $fs_browser_dir current 0
+ $fs_browser_dir icursor end
+ catch {
+ $fs_browser_dir.e xview end
+ }
+ }
+
+ ## Select file/directory to open
+ # This method should be connected to <<Selection>> event on FS browser ListBox
+ # @return void
+ public method filelist_fsb_select {} {
+ if {[$this is_frozen]} {
+ tk_messageBox \
+ -parent . \
+ -icon info \
+ -type ok \
+ -title [mc "Unable to compile"] \
+ -message [mc "Unable to open source file while simulator is engaged."]
+ return
+ }
+
+ if {$fs_browser_selection_in_P} {return}
+ set fs_browser_selection_in_P 1
+
+ # Determinate name of file/directory to open
+ set file [$fs_browser_listbox itemcget \
+ [$fs_browser_listbox selection get] -data]
+
+ # Open file
+ if {[lindex $file 0] != {}} {
+ set simplename $file
+ set file [file join $fs_browser_current_dir [lindex $file 0]]
+
+ # Check if the file seems to be valid source code
+ if {![regexp {\.(asm|inc|c|h|cpp|cc|cxx|lst)$} $file] || ([file size $file] > 1048576)} {
+ set response [tk_messageBox \
+ -parent . -type yesno \
+ -icon warning \
+ -title [mc "Open file %s" $simplename] \
+ -message [mc "This file does not look like a source code.\nDo you really want to open it ?"] \
+ ]
+ if {$response != {yes}} {
+ set fs_browser_selection_in_P 0
+ return
+ }
+ }
+
+ # Perform opening procedure
+ if {[$this openfile $file 1 . def def 0 0 {}] != {}} {
+ $this switch_to_last
+ update
+ $this editor_procedure {} parseAll {}
+
+ # Make LST read only
+ if {[file extension $file] == {.lst}} {
+ set ::editor_RO_MODE 1
+ $this switch_editor_RO_MODE
+ }
+
+ ::X::recent_files_add 1 $file
+ }
+
+ # Open directory
+ } {
+ filelist_fsb_change_dir \
+ [file join $fs_browser_current_dir [lindex $file 1]]
+ }
+ set fs_browser_selection_in_P 0
+ update
+ }
+
+ ## Invoke dialog to edit FS browser bookmarks
+ # @return void
+ public method filelist_fsb_edit_bookmarks {} {
+ catch {delete object fsd}
+ KIFSD::FSD fsd
+ fsd edit_bookmarks
+ delete object fsd
+ }
+
+ ## Synchronize bookmarks in FS browser with KIFSD (KI File selection dialog)
+ # This method shoul be called after FSD close
+ # @return void
+ public method filelist_fsb_refresh_bookmarks {} {
+ if {!$gui_initialized} {CreateFSBrowserGUI}
+
+ # Clear current bookmarks entries
+ if {[$fs_browser_bm_menu index end] > 2} {
+ $fs_browser_bm_menu delete 3 end
+ }
+ # Create new bookmark entries
+ foreach dir ${::KIFSD::FSD::config(bookmarks)} {
+ $fs_browser_bm_menu add command \
+ -label $dir -compound left \
+ -image ::ICONS::16::fileopen \
+ -command "$this filelist_fsb_change_dir {$dir}"
+ }
+ }
+
+ ## Bookmark current directory
+ # @return void
+ public method filelist_fsb_add_bookmark {} {
+ lappend ::KIFSD::FSD::config(bookmarks) $fs_browser_current_dir
+ $fs_browser_bm_menu add command \
+ -label $fs_browser_current_dir -compound left \
+ -image ::ICONS::16::fileopen \
+ -command "$this filelist_fsb_change_dir {$fs_browser_current_dir}"
+ }
+
+ ## Bookmark directory selected by popup menu
+ # @return void
+ public method filelist_fsb_bookmark_this {} {
+ # No item selected -> bookmark current directory
+ if {$fs_browser_selected_item == {}} {
+ filelist_fsb_add_bookmark
+ return
+ }
+
+ # Directory selected -> bookmark it
+ if {[lindex [$fs_browser_listbox itemcget $fs_browser_selected_item -data] 1] != {}} {
+ set tmp $fs_browser_current_dir
+ set fs_browser_current_dir [file join $fs_browser_current_dir \
+ [$fs_browser_listbox itemcget $fs_browser_selected_item -text]]
+ filelist_fsb_add_bookmark
+ set fs_browser_current_dir $tmp
+
+ # File selected -> bookmark current directory
+ } {
+ filelist_fsb_add_bookmark
+ }
+ }
+
+ ## Reload filesystem browser contents
+ # @return void
+ public method filelist_fsb_reload {} {
+ if {!$gui_initialized} {CreateFSBrowserGUI}
+ filelist_fsb_change_dir $fs_browser_current_dir
+ }
+
+ ## Go to parent directory (in FS browser)
+ # @return void
+ public method filelist_fsb_up {} {
+ filelist_fsb_change_dir [file join $fs_browser_current_dir {..}]
+ }
+
+ ## Go back in history (in FS browser)
+ # @return void
+ public method filelist_fsb_back {} {
+ # Gain new directory location
+ set folder [lindex $back_history end]
+ if {$folder == {}} {return}
+
+ # Adjust back and forward history
+ set back_history [lreplace $back_history end end]
+ lappend forward_history $fs_browser_current_dir
+
+ # Make backup for history lists
+ set tmp_forw_hist $forward_history
+ set tmp_back_hist $back_history
+
+ # Change current directory (go back in history)
+ filelist_fsb_change_dir $folder
+
+ # Restore history lists
+ set forward_history $tmp_forw_hist
+ set back_history $tmp_back_hist
+
+ # Configure toolbar and popup menu
+ if {![llength $back_history]} {
+ ${fs_browser_toolbar}back configure -state disabled
+ $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state disabled
+ } {
+ ${fs_browser_toolbar}back configure -state normal
+ $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state normal
+ }
+ $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state normal
+ ${fs_browser_toolbar}forward configure -state normal
+ }
+
+ ## Go forward in history (in FS browser)
+ # @return void
+ public method filelist_fsb_forward {} {
+ # Gain new directory location
+ set folder [lindex $forward_history end]
+ if {$folder == {}} {return}
+
+ # Adjust forward and back history
+ set forward_history [lreplace $forward_history end end]
+ lappend back_history $fs_browser_current_dir
+
+ # Make backup for history lists
+ set tmp_forw_hist $forward_history
+ set tmp_back_hist $back_history
+
+ # Change current directory (go forward in history)
+ filelist_fsb_change_dir $folder
+
+ # Restore history lists
+ set forward_history $tmp_forw_hist
+ set back_history $tmp_back_hist
+
+ # Configure toolbar and popup menu
+ if {![llength $forward_history]} {
+ ${fs_browser_toolbar}forward configure -state disabled
+ $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state disabled
+ } {
+ ${fs_browser_toolbar}forward configure -state normal
+ $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state normal
+ }
+ ${fs_browser_toolbar}back configure -state normal
+ $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state normal
+ }
+
+ ## Change current directory to the current document folder
+ # @return void
+ public method filelist_fsb_current_doc_folder {} {
+ # Determinate path to current document
+ set file [$this editor_procedure {} getFileName {}]
+ if {[lindex $file 0] != {}} {
+ set dir [lindex $file 0]
+ } {
+ set dir $projectPath
+ }
+ # Change current directory
+ filelist_fsb_change_dir $dir
+ }
+
+ ## Rename selected file
+ # @return void
+ public method filelist_fsb_rename {} {
+ # Determina original and new name
+ set original [$fs_browser_listbox itemcget $fs_browser_selected_item -text]
+ set newname [$fs_browser_listbox edit $fs_browser_selected_item \
+ [$fs_browser_listbox itemcget $fs_browser_selected_item -text]]
+ if {$newname == {}} {
+ return
+ }
+
+ # Normalize file names (original and new)
+ set original [file join $fs_browser_current_dir $original]
+ set newname [file join $fs_browser_current_dir $newname]
+
+ # Rename file/directory
+ if {[catch {file rename -force $original $newname}]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to rename file:\n%s" $original]
+ }
+
+ # Refresh browser
+ filelist_fsb_reload
+ }
+
+ ## Delete selected file/directory
+ # @return void
+ public method filelist_fsb_delete {} {
+ set filename [$fs_browser_listbox itemcget $fs_browser_selected_item -text]
+
+ if {[tk_messageBox \
+ -parent . \
+ -type yesno \
+ -icon question \
+ -title [mc "Delete file"] \
+ -message [mc "Do you really want to delete file:\n%s" $filename]]
+ ==
+ {yes}
+ } {
+ if {[catch {file delete -force -- [file join $fs_browser_current_dir $filename]}]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to remove file:\n%s" $filename]
+ }
+ }
+ filelist_fsb_reload
+ }
+
+ ## Invoke dialog: "Create new directory" (FS browser)
+ # @return void
+ public method filelist_fsb_new_folder {} {
+ # Create dialog window
+ set dialog [toplevel .new_dir_dialog -class {New folder} -bg {#EEEEEE}]
+
+ # Create header
+ pack [label $dialog.header \
+ -justify left \
+ -text [mc "Create new folder in:\n%s" $fs_browser_current_dir] \
+ ] -side top -anchor w -padx 15 -pady 5
+ # Create EntryBox for name of new folder
+ pack [ttk::entry $dialog.entry -bg white \
+ ] -side top -fill x -expand 1 -padx 5 -pady 5
+
+ # Create bottom button bar
+ set button_frame [frame $dialog.bottom]
+ # - Button: Clear
+ pack [ttk::button $button_frame.clear \
+ -text [mc "Clear"] \
+ -compound left \
+ -image ::ICONS::16::clear_left \
+ -command "$dialog.entry delete 0 end"
+ ] -side left -expand 0
+ # - Button: OK
+ pack [ttk::button $button_frame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command [list $this create_new_folder] \
+ ] -side left -expand 0
+ # - Button: Cancel
+ pack [ttk::button $button_frame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "grab release $dialog; destroy $dialog" \
+ ] -side left -expand 0
+ # Pack button frame
+ pack $button_frame -side bottom -anchor e -expand 0 -padx 5 -pady 5
+
+ # Configure dialog window
+ wm iconphoto $dialog ::ICONS::16::folder_new
+ wm title $dialog [mc "New folder"]
+ wm resizable $dialog 1 0
+ wm minsize $dialog 340 120
+ wm geometry $dialog 340x120
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ "
+ wm transient $dialog .
+ grab $dialog
+ raise $dialog
+ focus -force $dialog.entry
+ tkwait window $dialog
+ }
+
+ ## Create new directory (in FS browser)
+ # @return void
+ public method create_new_folder {} {
+ # Local variables
+ set dialog .new_dir_dialog ;# ID of dialog window
+ set folder [$dialog.entry get] ;# Name of folder to create
+ set error 0 ;# Bool: error occured
+
+ # Check for folder name validity
+ if {$folder == {}} {
+ set error 1
+ }
+
+ # Create new folder
+ if {$error || [catch {file mkdir [file join $fs_browser_current_dir $folder]}]} {
+ tk_messageBox -parent $dialog -icon warning -type ok \
+ -title [mc "Unable to create folder"] \
+ -message [mc "Unable to create the specified folder"]
+ } {
+ # Remove dialog and reload browser
+ grab release $dialog
+ destroy $dialog
+ filelist_fsb_reload
+ }
+ }
+
+ ## Invoke dialog: "File/Directory properties" (in FS browser)
+ # @return void
+ public method filelist_fsb_properties {} {
+ ## Determinate item properties
+ # - filename
+ # - full path
+ # - size
+ # - permissions
+ # - owner + group
+ # - modification time
+ # - access time
+ set name [$fs_browser_listbox itemcget $fs_browser_selected_item -data]
+ if {[lindex $name 0] == {}} {
+ set name [lindex $name 1]
+ set type [mc "Directory"]
+ } {
+ set name [lindex $name 0]
+ set type [mc "File"]
+ }
+ set fullname [file join $fs_browser_current_dir $name]
+ if {![file exists $fullname]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unknown Error"] \
+ -message [mc "This file apparently does not exist"]
+ return
+ }
+ set size [file size $fullname]
+ append size { B}
+ set modified [clock format [file mtime $fullname] -format {%D %R}]
+ set accessed [clock format [file atime $fullname] -format {%D %R}]
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set perms [file attributes $fullname]
+ set group [lindex $perms 1]
+ set owner [lindex $perms 3]
+ set perms [lindex $perms 5]
+ set perms [string range $perms {end-3} end]
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ mask {0400 0200 0100 040 020 010 04 02 01} \
+ {
+ set ::KIFSD::FSD::item_properties($var) [expr {($perms & $mask) > 0}]
+ }
+ }
+
+
+ # Create dialog window componets
+ set dialog [toplevel .properties_dialog -class {File properties} -bg {#EEEEEE}] ;# Toplevel window itself
+ set nb [NoteBook $dialog.nb -bg {#EEEEEE}] ;# NoteBook
+ set bottom_frame [frame $dialog.bottom_frame] ;# Button frame
+
+ # Create tabs in NoteBook
+ $nb insert end general -text [mc "General"]
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ $nb insert end permission -text [mc "Permissions"]
+ }
+ $nb raise general
+
+ #
+ ## Create componets of tab "GENERAL"
+ #
+ set frame [frame [$nb getframe general].frame]
+ pack $frame -side top -anchor n -fill x -expand 1
+ set row 0
+ grid [label $frame.lbl_$row \
+ -text [mc "Name:"] -anchor w \
+ ] -column 0 -row $row -sticky w -pady 3
+ set ::KIFSD::FSD::item_properties(name) $name
+ grid [ttk::entry $frame.val_lbl_$row \
+ -validate all \
+ -textvariable ::KIFSD::FSD::item_properties(name) \
+ -validatecommand "::KIFSD::FSD::not_empty_entry_validator %W %P" \
+ ] -column 1 -row $row -sticky w -pady 3
+ incr row
+ foreach lbl {Type Location Size Modified Accessed} \
+ value [list $type $fs_browser_current_dir $size $modified $accessed] \
+ {
+ grid [label $frame.lbl_$row \
+ -text "$lbl:" -anchor w \
+ ] -column 0 -row $row -sticky w -pady 3
+ grid [label $frame.val_lbl_$row \
+ -text $value -anchor w \
+ ] -column 1 -row $row -sticky w -pady 3
+ incr row
+ }
+ grid columnconfigure $frame 0 -minsize 100
+
+ #
+ ## Create componets of tab "PERMISSIONS"
+ #
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set frame [$nb getframe permission]
+ set ap_frame [ttk::labelframe $frame.ap_frame \
+ -text [mc "Access permissions"] \
+ ]
+ set i 0
+ foreach text {Class Read Write Exec Owner Group Others} \
+ row {0 0 0 0 1 2 3} \
+ col {0 1 2 3 0 0 0} \
+ {
+ grid [label $ap_frame.lbl_$i \
+ -text $text -justify center \
+ ] -row $row -column $col -sticky w -padx 4 -pady 4
+ incr i
+ }
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ row {1 1 1 2 2 2 3 3 3} \
+ col {1 2 3 1 2 3 1 2 3} \
+ {
+ grid [checkbutton $ap_frame.check_$i \
+ -variable ::KIFSD::FSD::item_properties($var)
+ ] -row $row -column $col
+ incr i
+ }
+
+ grid columnconfigure $ap_frame 0 -minsize 70
+ grid columnconfigure $ap_frame 0 -weight 1
+ pack $ap_frame -side top -fill x -expand 1 -padx 5 -pady 5 -anchor nw
+
+ set own_frame [ttk::labelframe $frame.own_frame \
+ -text [mc "Ownership"] \
+ ]
+ grid [label $own_frame.owner_lbl \
+ -text [mc "Owner"] \
+ ] -row 0 -column 0 -padx 10 -pady 3 -sticky w
+ grid [label $own_frame.owner_val_lbl \
+ -text $owner -anchor w \
+ ] -row 0 -column 1 -padx 10 -pady 3 -sticky we
+ grid [label $own_frame.group_lbl \
+ -text [mc "Group"] \
+ ] -row 1 -column 0 -padx 10 -pady 3 -sticky w
+ grid [label $own_frame.group_val_lbl \
+ -text $group -anchor w \
+ ] -row 1 -column 1 -padx 10 -pady 3 -sticky we
+ grid columnconfigure $own_frame 0 -minsize 70
+ grid columnconfigure $own_frame 1 -weight 1
+ pack $own_frame -side top -fill x -expand 1 -padx 5 -pady 5
+ }
+
+ #
+ ## Create componets of bottom frame
+ #
+ pack [ttk::button $bottom_frame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "$this properties_ok $dialog $fullname" \
+ ] -side left
+ pack [ttk::button $bottom_frame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ grab release $dialog
+ destroy $dialog" \
+ ]
+
+ # Pack NoteBook and bottom frame
+ pack $nb -fill both -expand 1 -padx 10 -pady 5
+ pack $bottom_frame -anchor e -after $nb -padx 10 -pady 5
+
+ # Configure dialog window
+ wm title $dialog [mc "Item properties"]
+ wm minsize $dialog 280 320
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog"
+ wm transient $dialog .
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+
+ ## Binding to OK button in item properties dialog
+ # @parm String dialog - ID of dialog toplevel window
+ # @parm String file - Name of file related to the dialog
+ # @return void
+ public method properties_ok {dialog file} {
+ set error 0
+
+ # Determinate permissions (in decimal)
+ if {!$::MICROSOFT_WINDOWS} { ;# Microsoft Windows has no file rights (compatible with posix rights)
+ set perm 0
+ foreach var {ur uw ux gr gw gx or ow ox} \
+ val {256 128 64 32 16 8 4 2 1} {
+ if {$::KIFSD::FSD::item_properties($var)} {
+ incr perm $val
+ }
+ }
+ # Change permissions
+ if {[catch {file attributes $file -permissions "0[format {%o} $perm]"}]} {
+ set error 1
+ tk_messageBox -type ok -icon warning -parent $dialog \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to change permissions for file:\n%s" [file tail $file]]
+ }
+ }
+ set dir [file dirname $file]
+
+ # Set new file name
+ if {${::KIFSD::FSD::item_properties(name)} != [file tail $file]} {
+ if {[catch {
+ file rename -force -- \
+ $file [file join $dir \
+ ${::KIFSD::FSD::item_properties(name)}]}]
+ } {
+ set error 1
+ tk_messageBox -type ok -icon warning -parent $dialog \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to rename file:\n%s\n\t=>\n%s" [file tail $file] ${::KIFSD::FSD::item_properties(name)}]
+ }
+ filelist_fsb_reload
+ }
+
+ # If no error occured, close dialog
+ if {!$error} {
+ grab release $dialog
+ destroy $dialog
+ }
+ }
+
+ ## Go to home directory
+ # @return void
+ public method filelist_fsb_gohome {} {
+ filelist_fsb_change_dir {~}
+ }
+
+ ## Confirm new filter settings
+ # @return void
+ public method filelist_fsb_filter_ok {} {
+ set fs_browser_current_mask [$fs_browser_filter current]
+ switch -- $fs_browser_current_mask {
+ 0 {set fs_browser_current_mask {*.asm}}
+ 1 {set fs_browser_current_mask {*.inc}}
+ 2 {set fs_browser_current_mask {*.c}}
+ 3 {set fs_browser_current_mask {*.h}}
+ 4 {set fs_browser_current_mask {*.lst}}
+ 5 {set fs_browser_current_mask {*}}
+ }
+ filelist_fsb_reload
+ }
+
+ ## Validate content of directory location ComboBox
+ # @parm String content - Directory to validate
+ # @return Bool - always true
+ public method filelist_fsb_validate_dir {content} {
+ if {[file exists $content] && [file isdirectory $content]} {
+ $fs_browser_dir_ok configure -state normal
+ $fs_browser_dir configure -style TCombobox
+
+ # Fill directory location combobox
+ set folder $content
+ set values {}
+ while 1 {
+ lappend values $folder
+ if {$folder == [file separator]} {break}
+ if {$::MICROSOFT_WINDOWS} {
+ if {[regexp {^\w+:[\\\/]?$} $folder]} {break}
+ }
+ set folder [file normalize [file join $folder {..}]]
+ }
+ foreach folder [::KIFSD::FSD::dir_cmd $content 1] {
+ if {$folder == {..}} {continue}
+ lappend values [file join $content $folder]
+ }
+ if {$::MICROSOFT_WINDOWS} { ;# Include drive letters on Microsoft Windows
+ foreach drive_letter {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
+ if {[file exists "${drive_letter}:/"]} {
+ lappend values "${drive_letter}:/"
+ }
+ }
+ }
+ $fs_browser_dir configure -values $values
+ } {
+ $fs_browser_dir_ok configure -state disabled
+ $fs_browser_dir configure -style FSBrowser_RedBg.TCombobox
+ }
+
+ return 1
+ }
+
+ ## Confirm directory location in ComboBox
+ # @return void
+ public method filelist_fsb_dir_ok {} {
+ filelist_fsb_change_dir [$fs_browser_dir get]
+ }
+
+ ## Verticaly scroll FileSystem browser ListBox
+ # @parm Float frac0 - Fraction of top visible area
+ # @parm Float frac1 - Fraction of bottom visible area
+ # @return void
+ public method filelist_fsb_vscroll {frac0 frac1} {
+ # All content is in visible area -> unmap scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $fs_browser_listbox_v_scrollbar]} {
+ pack forget $fs_browser_listbox_v_scrollbar
+ update
+ }
+
+ # Otherwise -> create scrollbar
+ } {
+ if {![winfo ismapped $fs_browser_listbox_v_scrollbar]} {
+ pack $fs_browser_listbox_v_scrollbar \
+ -after $fs_browser_listbox \
+ -fill y -expand 1
+ update
+ }
+ $fs_browser_listbox_v_scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Horizontaly scroll FileSystem browser ListBox
+ # @parm Float frac0 - Fraction of top visible area
+ # @parm Float frac1 - Fraction of bottom visible area
+ # @return void
+ public method filelist_fsb_hscroll {frac0 frac1} {
+ # All content is in visible area -> unmap scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $fs_browser_listbox_h_scrollbar]} {
+ pack forget $fs_browser_listbox_h_scrollbar
+ update
+ }
+
+ # Otherwise -> create scrollbar
+ } {
+ if {![winfo ismapped $fs_browser_listbox_h_scrollbar]} {
+ pack $fs_browser_listbox_h_scrollbar \
+ -after $fs_browser_listbox_top_frame \
+ -side bottom -fill x -expand 0
+ update
+ }
+ $fs_browser_listbox_h_scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Recreate popup menus
+ # @return void
+ public method filelist_fsb_makePopupMenu {} {
+ if {!$gui_initialized} {return}
+ if {[winfo exists $fs_browser_conf_menu]} {
+ destroy $fs_browser_conf_menu
+ }
+ if {[winfo exists $fs_browser_listbox_menu]} {
+ destroy $fs_browser_listbox_menu
+ }
+ if {[winfo exists $fs_browser_bm_menu]} {
+ destroy $fs_browser_bm_menu
+ }
+
+ menuFactory $FSMENU_CONFIGURE $fs_browser_conf_menu 0 "$this " 0 {}
+ menuFactory $FSMENU_LISTBOX $fs_browser_listbox_menu 0 "$this " 0 {}
+ menuFactory $FSMENU_BOOKMARKS $fs_browser_bm_menu 0 "$this " 0 {}
+
+ if {![llength $back_history]} {
+ $fs_browser_listbox_menu entryconfigure [::mc "Back"] -state disabled
+ }
+ if {![llength $forward_history]} {
+ $fs_browser_listbox_menu entryconfigure [::mc "Forward"] -state disabled
+ }
+ }
+
+ ## Get current file mask
+ # @return String - Current mask
+ public method fs_browser_get_current_mask {} {
+ return $fs_browser_current_mask
+ }
+}
diff --git a/lib/leftpanel/sfrwatches.tcl b/lib/leftpanel/sfrwatches.tcl
new file mode 100755
index 0000000..ba47dc5
--- /dev/null
+++ b/lib/leftpanel/sfrwatches.tcl
@@ -0,0 +1,620 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides SFR watches for left panel
+# --------------------------------------------------------------------------
+
+class SFRWatches {
+
+ ## COMMON
+ # Font for addresses and register names
+ common main_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ -weight bold \
+ ]
+ # Just another font but not bold
+ common roman_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ ]
+ # Fonr for register entry boxes
+ common entry_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ ]
+
+ ## PRIVATE
+ private variable text_widget ;# Widget: Text widget containing SFR watches
+ private variable scrollbar ;# Widget: Scrollbar for $text_widget
+ private variable search_entry ;# Widget: Search entry box at the bottom of the panel
+ private variable search_clear_but ;# Widget: Button "Clear" at the bottom of the panel
+ private variable main_left_frame ;# Widget: Frame containing $text_widget and its header label
+ private variable entry_count 0 ;# Int: Number of SFRs
+ private variable validation_ena 1 ;# Bool: SFR entry box validation enabled
+ private variable haddr2idx ;# Array: $haddr2idx($hex_addr) --> row_in_text_widget - 1
+ private variable addr2idx ;# Array: $addr2idx($dec_addr) --> row_in_text_widget - 1
+ private variable reg2idx ;# Array: $addr2idx($register_name_upppercase) --> row_in_text_widget - 1
+ private variable last_selected_line 0 ;# Int: Selected row in the text widget
+ private variable search_ena 1 ;# Bool: Search enabled
+ private variable menu ;# Widget: Popup menu for the text widget
+
+ # Variables related to object initialization
+ private variable parent ;# Parent GUI object (tempotary variable)
+ private variable gui_initialized 0 ;# GUI ready
+
+ constructor {} {
+ }
+
+ destructor {
+ if {$gui_initialized} {
+ menu_Sbar_remove $menu
+ }
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - parent container (some frame)
+ # @return void
+ public method PrepareSFRWatches {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Initialize SFR watches GUI
+ # @return void
+ public method CreateSFRWatchesGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ set validation_ena 0
+ create_GUI
+ fill_gui
+ set validation_ena 1
+
+ if {![$this is_frozen]} {
+ sfr_watches_disable
+ }
+ }
+
+ ## Create entry box to embedd in the text widget
+ # @parm Int i - Entry index (row - 1)
+ # @parm String type - Entry type (hex or dec)
+ # @parm Int addr - SFR address (128..255)
+ # @parm String reg - SFR name (e.g. PSW)
+ # @return Widget - Created entry box
+ private method create_entry {i type addr reg} {
+ # Determinate entry box width
+ if {$type == {hex}} {
+ set width 2
+ } {
+ set width 3
+ }
+
+ # Create entry widget
+ set entry [entry $text_widget.${type}_entry_${i} \
+ -width $width -font $entry_font \
+ -bg {#FFFFFF} -validate all \
+ -takefocus 0 -highlightthickness 0 \
+ -disabledbackground {#FFFFFF} \
+ -vcmd "$this sfr_watches_validate ${type} $addr %P" \
+ -bd 0 -justify right \
+ ]
+
+ # Perform name correction for accumulators
+ if {$reg == {A} || $reg == {B}} {
+ append reg {_hex}
+ }
+
+ # Set event bindins
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg"
+ bind $entry <Button-1> "$this sfr_watches_select_line 0 [expr {$i + 1}] $type"
+ bind $entry <Key-Up> "$this sfr_watches_up $type 1"
+ bind $entry <Key-Down> "$this sfr_watches_down $type 1"
+ bind $entry <Key-Next> "$this sfr_watches_down $type 4"
+ bind $entry <Key-Prior> "$this sfr_watches_up $type 4"
+ bind $entry <Button-4> "$text_widget yview scroll -5 units"
+ bind $entry <Button-5> "$text_widget yview scroll +5 units"
+ if {$type == {hex}} {
+ bind $entry <Key-Right> "
+ focus $text_widget.dec_entry_${i}
+ $text_widget.dec_entry_${i} selection clear
+ update
+ $text_widget.dec_entry_${i} icursor 0"
+ } {
+ bind $entry <Key-Left> "
+ focus $text_widget.hex_entry_${i}
+ $text_widget.hex_entry_${i} selection clear
+ update
+ $text_widget.dec_entry_${i} icursor end"
+ }
+
+ return $entry
+ }
+
+ ## Complite GUI initialization (load all SFRs into the text widget)
+ # @return void
+ private method fill_gui {} {
+ set entry_count 0
+ set validation_ena 0
+
+ # Iterate over defined SFRs ({{addr name} ... })
+ foreach reg [$this simulator_get_sfrs] {
+ # Determinate hexadecimal address
+ set addr [lindex $reg 0]
+ set hex_addr [format %X $addr]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ } elseif {[string length $hex_addr] == 3} {
+ set hex_addr [string replace $hex_addr 0 0]
+ }
+ # Determinate register name and make it 8 characters long
+ set reg [lindex $reg 1]
+ set reg_org $reg
+ switch -- $reg {
+ SBUFR {
+ set reg {SBUF R}
+ }
+ SBUFT {
+ set reg {SBUF T}
+ }
+ default {
+ set reg $reg
+ }
+ }
+ append reg [string repeat { } [expr {8 - [string length $reg]}]]
+
+ # Register this SFR
+ set haddr2idx($hex_addr) $entry_count
+ set addr2idx($addr) $entry_count
+ set reg2idx($reg_org) $entry_count
+
+ # Insert address and name into the text widget
+ $text_widget insert end $hex_addr
+ $text_widget insert end { }
+ $text_widget insert end $reg
+
+ # Set highlighting tags
+ set line [expr {int([$text_widget index insert])}]
+ $text_widget tag add tag_addr $line.0 $line.2
+ $text_widget tag add tag_name $line.3 $line.11
+
+ # Create and insert embedded entry boxes
+ set entry [create_entry $entry_count hex $addr $reg_org]
+ $entry insert 0 [$this getSfr $addr]
+ $text_widget window create end -window $entry -pady 0
+ $text_widget insert end { }
+ set entry [create_entry $entry_count dec $addr $reg_org]
+ $entry insert 0 [$this getSfrDEC $addr]
+ $text_widget window create end -window $entry -pady 0
+
+ # Finalize this row
+ $text_widget insert end "\n"
+ incr entry_count
+ }
+
+ # Remove the last line (empty line) and disable the text widget
+ $text_widget delete end-1l end
+ set validation_ena 1
+ }
+
+ ## Set value of SFR at current line to the specified value
+ # @parm String value - Hexadecimal value
+ # @return void
+ public method sfr_watches_set_current_to {value} {
+ set idx [expr {$last_selected_line - 1}]
+ set addr [lindex [$this simulator_get_sfrs] [list $idx 0]]
+
+ $this setSfr $addr $value
+ $this Simulator_GUI_sync S $addr
+ }
+
+ ## Create GUI elements of this panel
+ # @return void
+ private method create_GUI {} {
+ # Create and pack panel frames
+ set main_frame [frame $parent.main_frame]
+ set main_left_frame [frame $main_frame.left]
+ pack $main_left_frame -side left -fill both -expand 1
+ pack $main_frame -fill both -expand 1
+
+ # Create text widget and its header
+ pack [label $main_left_frame.header_label \
+ -anchor w -justify left -pady 0 -padx 2 \
+ -fg ${::Simulator_GUI::small_color} \
+ -font ${::Simulator_GUI::smallfont} \
+ -text "[mc {Register}] [mc {HEX}] [mc {DEC}]" -width 1 \
+ ] -fill x -pady 0 -anchor nw
+ set text_widget [text $main_left_frame.text \
+ -bg {#FFFFFF} -font $roman_font -bd 2 \
+ -width 0 -height 0 -wrap none \
+ -yscrollcommand "$this sfr_watches_scroll_set" \
+ -cursor left_ptr \
+ ]
+
+ # Create popup menu for the text widget
+ set menu $text_widget.menu
+ menuFactory {
+ {command {Set to 0x00} {} 9 "sfr_watches_set_current_to 00"
+ {} "Set this register to 0"}
+ {command {Set to 0xFF} {} 9 "sfr_watches_set_current_to FF"
+ {} "Set this register to 255"}
+ } $menu 0 "$this " 0 {}
+
+ # Set event bindings for the text widget
+ bindtags $text_widget $text_widget
+ foreach event {
+ <ButtonRelease-1> <B1-Enter> <B1-Leave>
+ <B2-Motion> <Button-5> <Button-4>
+ <MouseWheel>
+ } {
+ bind $text_widget $event [bind Text $event]
+ }
+ bind $text_widget <Button-1> \
+ "$this sfr_watches_select_line 0 \[expr {int(\[%W index @%x,%y\])}\] hex"
+ bind $text_widget <ButtonRelease-3> \
+ "$this sfr_watches_select_line 0 \[expr {int(\[%W index @%x,%y\])}\] hex
+ tk_popup $menu %X %Y"
+
+ # Pack the text widget and create its scrollbar
+ pack $text_widget -fill both -expand 1
+ set scrollbar [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical -command "$text_widget yview" \
+ ]
+
+ # Create bottom frame (search bar)
+ set search_frame [frame $parent.top]
+ pack [label $search_frame.lbl \
+ -text [mc "Search:"] \
+ ] -side left
+ set search_entry [ttk::entry $search_frame.entry \
+ -width 0 \
+ -validate all \
+ -validatecommand "$this sfr_watches_search_validate %P" \
+ ]
+ pack $search_entry -side left -fill x -expand 1
+ set search_clear_but [ttk::button $search_frame.button \
+ -style Flat.TButton \
+ -state disabled \
+ -image ::ICONS::16::clear_left \
+ -command "$search_entry delete 0 end" \
+ ]
+ pack $search_clear_but -side right -after $search_entry
+ pack $search_frame -fill x
+
+ # Create highlighting tags for the text widget
+ $text_widget tag configure tag_addr \
+ -foreground {#000000} -font $main_font
+ $text_widget tag configure tag_name \
+ -foreground {#0000DD} -font $main_font
+ $text_widget tag configure tag_curLine \
+ -background ${::RightPanel::selection_color_dark}
+ }
+
+ ## Adjust scrollbar
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac1 - 2nd fraction
+ # @return void
+ public method sfr_watches_scroll_set {frac0 frac1} {
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $scrollbar]} {
+ pack forget $scrollbar
+ }
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $scrollbar]} {
+ pack $scrollbar \
+ -side left \
+ -fill y \
+ -after $main_left_frame
+ }
+ $scrollbar set $frac0 $frac1
+ }
+ }
+
+ ## Validate content of search entry box at the bottom bar
+ # @parm String string - String to validate
+ # @return Bool - Always 1
+ public method sfr_watches_search_validate {string} {
+ # Check if searching is enabled
+ if {!$search_ena} {return 1}
+
+ # Adjust state of clear button (+ clear selection on the text widget)
+ if {$string == {}} {
+ $search_clear_but configure -state disabled
+ $search_entry configure -style TEntry
+ sfr_watches_select_line 1 0 hex
+ return 1
+ } {
+ $search_clear_but configure -state normal
+ }
+
+ set string [string toupper $string]
+
+ # Perform case insensitive search for the given chunk of SFR name and address
+ foreach arr {reg2idx haddr2idx} {
+ foreach str [lsort -ascii -increasing [array names $arr]] {
+ # Search successful
+ if {![string first $string $str]} {
+ $search_entry configure -style StringFound.TEntry
+ sfr_watches_select_line 1 [expr {[subst "\${${arr}(${str})}"] + 1}] hex
+ return 1
+ }
+ }
+ }
+
+ # Search failed
+ $search_entry configure -style StringNotFound.TEntry
+ return 1
+ }
+
+ ## Select line in the text widget
+ # @parm Bool search - Invoked form search validator (do not clear search entry box)
+ # @parm Int line - Target line
+ # @parm String type - Entry box to select (hex or dec)
+ # @return void
+ public method sfr_watches_select_line {search line type} {
+
+ # Unselect the last selected line and determinate cursor position
+ if {$last_selected_line} {
+ $text_widget tag remove tag_curLine 0.0 end
+ $this simulator_reg_label_set_highlighted $last_selected_line 0
+ incr last_selected_line -1
+ foreach tp {dec hex} {
+ $text_widget.${tp}_entry_$last_selected_line selection clear
+ $text_widget.${tp}_entry_$last_selected_line configure \
+ -bg {#FFFFFF} -disabledbackground {#FFFFFF}
+ }
+ set cursor [$text_widget.${type}_entry_$last_selected_line index insert]
+ } {
+ set cursor 0
+ }
+
+ # Adjust last selected line (if 0 the return)
+ set last_selected_line $line
+ if {!$line} {
+ return
+ }
+
+
+ # Highlight this line as selected in the text widget
+ $text_widget tag add tag_curLine \
+ $last_selected_line.0 \
+ $last_selected_line.0+1l
+ $text_widget see $last_selected_line.0
+
+ # Highlight SFR on this line in simulator control panel
+ $this simulator_reg_label_set_highlighted $last_selected_line 1
+
+ # Adjust background color for entry boxes at this line
+ incr line -1
+ $text_widget.dec_entry_$line configure \
+ -fg ${Simulator::normal_color} \
+ -bg ${::RightPanel::selection_color_dark} \
+ -disabledbackground ${::RightPanel::selection_color_dark}
+ $text_widget.hex_entry_$line configure \
+ -fg ${Simulator::normal_color} \
+ -bg ${::RightPanel::selection_color_dark} \
+ -disabledbackground ${::RightPanel::selection_color_dark}
+
+ # Clear search entry box and focus and entry box at this line
+ if {!$search} {
+ $text_widget.${type}_entry_$line icursor $cursor
+ $text_widget.${type}_entry_$line selection range 0 end
+ focus $text_widget.${type}_entry_$line
+ set search_ena 0
+ $search_entry delete 0 end
+ set search_ena 1
+ }
+ }
+
+ ## Validator for SFR value entry boxes
+ # @parm String type - Entry box type (hex or dec)
+ # @parm Int addr - Register address
+ # @parm String value - String to validate
+ # @return Bool - Validation result
+ public method sfr_watches_validate {type addr value} {
+ # Prevent recursion
+ if {!$validation_ena} {return 1}
+ set validation_ena 0
+
+ # Validate value
+ if {$value == {}} {
+ set value 0
+ }
+ if {$type == {hex}} {
+ if {![string is xdigit $value]} {
+ set validation_ena 1
+ return 0
+ }
+ set value [expr "0x$value"]
+ } {
+ if {![string is digit $value]} {
+ set validation_ena 1
+ return 0
+ }
+ }
+ if {$value > 255 || $value < 0} {
+ set validation_ena 1
+ return 0
+ }
+
+ # Synchronize with engine and simulator control panel
+ $this setSfr $addr [format %X $value]
+ $this SimGUI_disable_sync
+ $this Simulator_GUI_sync S $addr
+ $this SimGUI_enable_sync
+
+ # Synchronize with the other one entry box
+ if {$type == {hex}} {
+ $text_widget.dec_entry_$addr2idx($addr) delete 0 end
+ $text_widget.dec_entry_$addr2idx($addr) insert 0 $value
+ } {
+ set value [format %X $value]
+ if {[string length $value] == 1} {
+ set value "0$value"
+ }
+ $text_widget.hex_entry_$addr2idx($addr) delete 0 end
+ $text_widget.hex_entry_$addr2idx($addr) insert 0 $value
+ }
+
+ # Done
+ set validation_ena 1
+ return 1
+ }
+
+ ## Remove all SFRs for the text widget and unregister them
+ # @return void
+ private method clear_gui {} {
+ if {!$gui_initialized} {return}
+
+ # Clear SFR name label highlight in simultor contol panel
+ if {$last_selected_line} {
+ $this simulator_reg_label_set_highlighted $last_selected_line 0
+ }
+
+ # Reset object variables
+ array unset haddr2idx
+ array unset addr2idx
+ array unset reg2idx
+ set last_selected_line 0
+ set entry_count 0
+
+ # Clear the text widget
+ $text_widget delete 1.0 end
+ foreach wdg [$text_widget window names] {
+ destroy $wdg
+ }
+ }
+
+ ## Set new value of certain SFR in this panel
+ # @parm Int addr - SFR address
+ # @parm Int new_val - New SFR value
+ # @return void
+ public method sfr_watches_sync {addr new_val} {
+ if {!$gui_initialized} {return}
+
+ # Prevent recursion
+ if {!$validation_ena} {return}
+ set validation_ena 0
+
+ # Check if this SFR is avaliable here
+ if {[lsearch [array names addr2idx] $addr] == -1} {
+ set validation_ena 1
+ return
+ }
+
+ # Determinate references of HEX and DEC entry boxes
+ set hex_entry $text_widget.hex_entry_$addr2idx($addr)
+ set dec_entry $text_widget.dec_entry_$addr2idx($addr)
+
+ # Highlight entry boxes
+ set org_val [$dec_entry get]
+ if {$org_val != $new_val} {
+ $hex_entry configure -fg ${::Simulator_GUI::hcolor}
+ $dec_entry configure -fg ${::Simulator_GUI::hcolor}
+ }
+
+ # Set decimal value
+ $dec_entry delete 0 end
+ $dec_entry insert 0 $new_val
+
+ # Set hexadecimal value
+ set new_val [format %X $new_val]
+ if {[string length $new_val] == 1} {
+ set new_val "0$new_val"
+ }
+ $hex_entry delete 0 end
+ $hex_entry insert 0 $new_val
+
+ # Reenable entry box value validations
+ set validation_ena 1
+ }
+
+ ## Enable this panel
+ # @return vois
+ public method sfr_watches_enable {} {
+ if {!$gui_initialized} {return}
+ $menu entryconfigure [::mc "Set to 0x00"] -state normal
+ $menu entryconfigure [::mc "Set to 0xFF"] -state normal
+ for {set i 0} {$i < $entry_count} {incr i} {
+ $text_widget.hex_entry_$i configure -state normal
+ $text_widget.dec_entry_$i configure -state normal
+ }
+ }
+
+ ## Disable this panel
+ # @return vois
+ public method sfr_watches_disable {} {
+ if {!$gui_initialized} {return}
+ $menu entryconfigure [::mc "Set to 0x00"] -state disabled
+ $menu entryconfigure [::mc "Set to 0xFF"] -state disabled
+ for {set i 0} {$i < $entry_count} {incr i} {
+ $text_widget.hex_entry_$i configure -state disabled
+ $text_widget.dec_entry_$i configure -state disabled
+ }
+ }
+
+ ## This function shuld be call after processor was changed
+ # Reload avaliable SFRs
+ # @return void
+ public method sfr_watches_commit_new_sfr_set {} {
+ if {!$gui_initialized} {return}
+ clear_gui
+ fill_gui
+ }
+
+ ## Move selected line up
+ # @parm String type - Which entry box should be selected (hex or dec)
+ # @parm Int lines - Number of lines to move by
+ # @return void
+ public method sfr_watches_up {type lines} {
+ set line $last_selected_line
+ incr line -$lines
+ if {$line <= 0} {
+ set line $entry_count
+ }
+
+ sfr_watches_select_line 0 $line $type
+ }
+
+ ## Move selected line down
+ # @parm String type - Which entry box should be selected (hex or dec)
+ # @parm Int lines - Number of lines to move by
+ # @return void
+ public method sfr_watches_down {type lines} {
+ set line $last_selected_line
+ incr line $lines
+ if {$line >= $entry_count} {
+ set line 0
+ }
+
+ sfr_watches_select_line 0 $line $type
+ }
+}
diff --git a/lib/lib/Math.tcl b/lib/lib/Math.tcl
new file mode 100755
index 0000000..bf2be0d
--- /dev/null
+++ b/lib/lib/Math.tcl
@@ -0,0 +1,954 @@
+#!/usr/bin/tclsh
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Primarily implements convertions between numeric systems and angle units.
+# --------------------------------------------------------------------------
+
+## ----------------------------------------------------------------------
+## Converts between numeric systems and checks numbers types
+ #
+ # Supported num. systems: binary, octal, decimal, hexadecimal and ASCII.
+ # note: Excepting H->Q and Q->H, are all convertions computed
+ # directly (for speed improvement).
+ # By default maximal number length after dot is 20 (for DEC -> ...).
+ # ----------------------------------------------------------------------
+ #
+ # USAGE:
+ #
+ # puts [ NumSystem::hex2dec F.4 ] ;# --> 15.25
+ # puts [ NumSystem::hex2oct F.4 ] ;# --> 17.2
+ # puts [ NumSystem::hex2bin F.4 ] ;# --> 1111.01
+ #
+ # puts [ NumSystem::dec2hex 15.25 ] ;# --> F.4
+ # puts [ NumSystem::dec2oct 15.25 ] ;# --> 17.2
+ # puts [ NumSystem::dec2bin 15.25 ] ;# --> 1111.01
+ #
+ # puts [ NumSystem::oct2hex 17.2 ] ;# --> F.4
+ # puts [ NumSystem::oct2dec 17.2 ] ;# --> 15.25
+ # puts [ NumSystem::oct2bin 17.2 ] ;# --> 1111.01
+ #
+ # puts [ NumSystem::bin2hex 1111.01 ] ;# --> F.4
+ # puts [ NumSystem::bin2dec 1111.01 ] ;# --> 15.25
+ # puts [ NumSystem::bin2oct 1111.01 ] ;# --> 17.2
+ #
+ # puts [ NumSystem::ascii2dec @ ] ;# --> 64
+ # puts [ NumSystem::ascii2bin @ ] ;# --> 01000000
+ #
+ # puts [ NumSystem::ishex F.4 ] ;# --> 1
+ # puts [ NumSystem::isdec 15.25 ] ;# --> 1
+ # puts [ NumSystem::isoct 17.2 ] ;# --> 1
+ # puts [ NumSystem::isbin 1111.01 ] ;# --> 1
+ # -----------------------------------------------------------------------
+
+namespace eval NumSystem {
+
+ variable precision {20} ;# maximal number of digits after dot
+
+ # -----------------------------------------------------------------------
+ # NUMERIC SYSTEMS CONVERTIONS
+ # -----------------------------------------------------------------------
+
+ # HEX -> ...
+
+ ## Hexadecimal -> Decimal
+ # required procedures: `is_X', `hexoct_to_dec', `aux_hexoct_to_dec', `asserthex', `ishex'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc hex2dec {number} {
+ return [hexoct_to_dec 16 $number]
+ }
+
+ ## Hexadecimal -> Octal
+ # required procedures: `is_X', `bin2oct', `hex2bin', `asserthex', `assertbin', `ishex', isbin'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc hex2oct {number} {
+ return [bin2oct [hex2bin $number]]
+ }
+
+ ## Hexadecimal -> Binary
+ # required procedures: `asserthex', `ishex'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc hex2bin {number} {
+
+ # verify value validity
+ asserthex $number
+
+ # Number can be negative value
+ set sign {}
+ if {[string index $number 0] == {-}} {
+ set number [string range $number 1 end]
+ set sign {-}
+ }
+
+ # make it upper-case
+ set number [string toupper $number]
+
+ # split value to list of chars
+ set number [split $number ""]
+
+ # convert value
+ set result {}
+ foreach char $number {
+ switch $char {
+ {0} {append result {0000}}
+ {1} {append result {0001}}
+ {2} {append result {0010}}
+ {3} {append result {0011}}
+ {4} {append result {0100}}
+ {5} {append result {0101}}
+ {6} {append result {0110}}
+ {7} {append result {0111}}
+ {8} {append result {1000}}
+ {9} {append result {1001}}
+ {A} {append result {1010}}
+ {B} {append result {1011}}
+ {C} {append result {1100}}
+ {D} {append result {1101}}
+ {E} {append result {1110}}
+ {F} {append result {1111}}
+ {.} {append result {.}}
+ }
+ }
+
+ # return result
+ regsub {^0+} $result {} result
+ if {[regexp {\.} $result]} {
+ regsub {0+$} $result {} result
+ }
+ regsub {\.$} $result {} result
+ regsub {^\.} $result {0.} result
+ if {[string length $result] == 0} {
+ set result 0
+ }
+ return $sign$result
+ }
+
+ # DEC -> ...
+
+ ## Decimal -> Hexadecimal
+ # required procedures: `is_X', `assertdec', isdec'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc dec2hex {number} {
+ return [dec_to_X 16 $number]
+ }
+
+ ## Decimal -> Octal
+ # required procedures: `is_X', `assertdec', isdec'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc dec2oct {number} {
+ return [dec_to_X 8 $number]
+ }
+
+ ## Decimal -> Binary
+ # required procedures: `is_X', `assertdec', `isdec'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc dec2bin {number} {
+ return [dec_to_X 2 $number]
+ }
+
+ # OCT -> ...
+
+ ## Octal -> Hexadecimal
+ # required procedures: `is_X', `bin2hex', `oct2bin', `bin_to_hexoct',
+ # `aux_hexoct_to_dec', `assertoct', `assertbin',`isbin',`isoct'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc oct2hex {number} {
+ return [bin2hex [oct2bin $number]]
+ }
+
+ ## Octal -> Decimal
+ # required procedures: `is_X', `bin_to_hexoct', `aux_hexoct_to_dec', `assertoct',`isoct'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc oct2dec {number} {
+ return [hexoct_to_dec 8 $number]
+ }
+
+ ## Octal -> Binary
+ # required procedures: `is_X', `assertoct', isoct'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc oct2bin {number} {
+
+ # verify value validity
+ assertoct $number
+
+ # Number can be negative value
+ set sign {}
+ if {[string index $number 0] == {-}} {
+ set number [string range $number 1 end]
+ set sign {-}
+ }
+
+ # split value to list of chars
+ set number [split $number ""]
+
+ # convert value
+ set result {}
+ foreach char $number {
+ switch $char {
+ {0} {append result {000}}
+ {1} {append result {001}}
+ {2} {append result {010}}
+ {3} {append result {011}}
+ {4} {append result {100}}
+ {5} {append result {101}}
+ {6} {append result {110}}
+ {7} {append result {111}}
+ {.} {append result {.}}
+ }
+ }
+
+ # return result
+ regsub {^0+} $result {} result
+ if {[regexp {\.} $result]} {
+ regsub {0+$} $result {} result
+ }
+ regsub {\.$} $result {} result
+ regsub {^\.} $result {0.} result
+ if {[string length $result] == 0} {
+ set result 0
+ }
+ return $sign$result
+ }
+
+ # BIN -> ...
+
+ ## Binary -> Hexadecimal
+ # required procedures: `is_X', `assertbin', isbin', `bin_to_hexoct'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc bin2hex {number} {
+ assertbin $number ;# verify value validity
+ return [bin_to_hexoct 16 $number] ;# convert value
+ }
+
+ ## Binary -> Decimal
+ # required procedures: `is_X', `assertbin', isbin'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc bin2dec {number} {
+
+ # verify value validity
+ assertdec $number
+
+ # Number can be negative value
+ set sign {}
+ if {[string index $number 0] == {-}} {
+ set number [string range $number 1 end]
+ set sign {-}
+ }
+
+ # split value to int. part
+ regexp {^\d+} $number int
+
+ # split value to frac. part
+ if {[regexp {\.\d+$} $number frac]} {
+ set frac [string range $frac 1 end]
+ set nofrac 0
+ } {
+ set frac {}
+ set nofrac 1
+ }
+
+ # compute int. part
+ set tmp [expr [string length $int] -1]
+ regexp {^\d+} [expr pow(2,$tmp)] tmp
+ set result 0
+ foreach value [split $int ""] {
+ if {$value} {
+ set result [expr {$result+$tmp}]
+ }
+ set tmp [expr {$tmp / 2}]
+ if {$tmp == 0} {break}
+ }
+ set int $result
+
+ # compute frac. part
+ if {!$nofrac} {
+ set tmp 0.5
+ set result 0
+ foreach value [split $frac ""] {
+ if {$value} {
+ set result [expr {$result+$tmp}]
+ }
+ set tmp [expr {$tmp / 2}]
+ }
+ regexp {\d+$} $result frac
+
+ # return converted value with frac.
+ return $sign$int.$frac
+ }
+
+ # return converted value without frac.
+ return $sign$int
+ }
+
+ ## Binary -> Octal
+ # required procedures: `is_X', `assertbin', isbin', `bin_to_hexoct'
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc bin2oct {number} {
+ assertbin $number ;# verify value validity
+ return [bin_to_hexoct 8 $number] ;# convert value
+ }
+
+ ## Ascii char -> Bin
+ # required procedures: (none)
+ # @parm Char number - value to convert
+ # @return mixed - converted value or an empty string
+ proc ascii2bin {number} {
+ if {[string bytelength $number] != 1} {
+ return {}
+ }
+
+ set result {}
+ scan $number {%c} result
+ if {$result != {}} {
+ return [dec2bin $result]
+ }
+
+ return $result
+ }
+
+ ## Ascii char -> Dec
+ # required procedures: (none)
+ # @parm Char number - value to convert
+ # @return mixed - converted value or an empty string
+ proc ascii2dec {number} {
+ if {[string bytelength $number] != 1} {
+ return {}
+ }
+ set result {}
+ scan $number {%c} result
+
+ return $result
+ }
+
+ # -----------------------------------------------------------------------
+ # TYPE ASSERTION
+ # -----------------------------------------------------------------------
+
+ ## Raise error if the given string is not an hexadecimal value
+ # require procedures: `is_X',`ishex'
+ # @parm String number - string to evaluate
+ # @return mixed - void (failure) or 1 (successful)
+ proc asserthex {number} {
+ if {![ishex $number]} {
+ error "asserthex: Excepted hexadecimal value but got \"$number\""
+ } {
+ return 1
+ }
+ }
+
+ ## Raise error if the given string is not an decimal value
+ # require procedures: `is_X',`isdec'
+ # @parm String number - string to evaluate
+ # @return mixed - void (failure) or 1 (successful)
+ proc assertdec {number} {
+ if {![isdec $number]} {
+ error "assertdec: Excepted decimal value but got \"$number\""
+ } {
+ return 1
+ }
+ }
+
+ ## Raise error if the given string is not an octal value
+ # require procedures: `is_X',`isoct'
+ # @parm String number - string to evaluate
+ # @return mixed - void (failure) or 1 (successful)
+ proc assertoct {number} {
+ if {![isoct $number]} {
+ error "assertoct: Excepted octal value but got \"$number\""
+ } {
+ return 1
+ }
+ }
+
+ ## Raise error if the given string is not an binary value
+ # require procedures: `is_X',`isbin'
+ # @parm String number - string to evaluate
+ # @return mixed - void (failure) or 1 (successful)
+ proc assertbin {number} {
+ if {![isbin $number]} {
+ error "assertbin: Excepted binary value but got \"$number\""
+ } {
+ return 1
+ }
+ }
+
+ # -----------------------------------------------------------------------
+ # TYPE CHECKING
+ # -----------------------------------------------------------------------
+
+ ## Check if the given string can be an Hexadecimal value
+ # require procedure: `is_X'
+ # @parm String number - value to evaluate
+ # @return bool
+ proc ishex {number} {
+ return [is_X {^[0-9A-Fa-f\.]+$} $number]
+ }
+
+ ## Check if the given string can be an Decimal value
+ # require procedure: `is_X'
+ # @parm String number - value to evaluate
+ # @return bool
+ proc isdec {number} {
+ return [is_X {^[0-9\.]+$} $number]
+ }
+
+ ## Check if the given string can be an Octal value
+ # require procedure: `is_X'
+ # @parm String number - value to evaluate
+ # @return bool
+ proc isoct {number} {
+ return [is_X {^[0-7\.]+$} $number]
+ }
+
+ ## Check if the given string can be an Binary value
+ # require procedure: `is_X'
+ # @parm String number - value to evaluate
+ # @return bool
+ proc isbin {number} {
+ return [is_X {^[01\.]+$} $number]
+ }
+
+ # -----------------------------------------------------------------------
+ # AUXILIARY PROCEDURES
+ # -----------------------------------------------------------------------
+
+ ## Auxiliary procedure for convering hex. and oct. to dec.
+ # require procedures: `is_X',`aux_hexoct_to_dec', `assertoct', `asserthex', `ishex', `isoct'
+ # @access PRIVATE
+ # @parm base - source numeric system, posible values are: 8 and 16
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc hexoct_to_dec {base number} {
+
+ # Number can be negative value
+ set sign {}
+ if {[string index $number 0] == {-}} {
+ set number [string range $number 1 end]
+ set sign {-}
+ }
+
+ # make number upper-case
+ set number [string toupper $number]
+
+ # verify value validity
+ if {$base == 8} {
+ assertoct $number
+ set char_len 3
+ } {
+ asserthex $number
+ set char_len 4
+ }
+
+ # split value to int. part
+ regexp {^[^\.]+} $number int
+
+ # split value to frac. part
+ if {[regexp {\.[^\.]+$} $number frac]} {
+ set frac [string range $frac 1 end]
+ set nofrac 0
+ } {
+ set frac {}
+ set nofrac 1
+ }
+
+ # compute int. part
+ if {$base == 8} {
+ set int [expr "0$int"]
+ } {
+ set int [expr "0x$int"]
+ }
+
+ # compute frac. part
+ if {!$nofrac} {
+ set frac [aux_hexoct_to_dec [split $frac {}] 1.0 $base]
+ regexp {\d+$} $frac frac
+ return $sign$int.$frac
+ }
+ return $sign$int
+ }
+
+ ## Auxiliary procedure for convering hex. and oct. to dec.
+ # require procedures: none
+ # @access PRIVATE
+ # @parm List vals_list - value to convert splited to a single characters
+ # @parm Number v0 - decimal value of highes bit in the number multipled by 2
+ # @parm base - source numeric system, posible values are: 8 and 16
+ # @return Number - converted value
+ proc aux_hexoct_to_dec {vals_list v0 base} {
+ set result 0
+
+ foreach char $vals_list {
+
+ if {$base == 8} {
+ set v3 $v0
+ } {
+ set v3 [expr {$v0 / 2}]
+ }
+ set v2 [expr {$v3 / 2}]
+ set v1 [expr {$v2 / 2}]
+ set v0 [expr {$v1 / 2}]
+
+ switch $char {
+ {0} {set bool_map {0 0 0 0}}
+ {1} {set bool_map {0 0 0 1}}
+ {2} {set bool_map {0 0 1 0}}
+ {3} {set bool_map {0 0 1 1}}
+ {4} {set bool_map {0 1 0 0}}
+ {5} {set bool_map {0 1 0 1}}
+ {6} {set bool_map {0 1 1 0}}
+ {7} {set bool_map {0 1 1 1}}
+ {8} {set bool_map {1 0 0 0}}
+ {9} {set bool_map {1 0 0 1}}
+ {A} {set bool_map {1 0 1 0}}
+ {B} {set bool_map {1 0 1 1}}
+ {C} {set bool_map {1 1 0 0}}
+ {D} {set bool_map {1 1 0 1}}
+ {E} {set bool_map {1 1 1 0}}
+ {F} {set bool_map {1 1 1 1}}
+ }
+
+ foreach cond $bool_map value "$v3 $v2 $v1 $v0" {
+ if {$cond} {
+ set result [expr {$result+$value}]
+ }
+ }
+ }
+ return $result
+ }
+
+ ## Auxiliary procedure for convering bin. to hex. and oct.
+ # require procedures: none
+ # @access PRIVATE
+ # @parm Int base - target numeric system, posible values are: 8 and 16
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc bin_to_hexoct {base number} {
+
+ # Number can be negative value
+ set sign {}
+ if {[string index $number 0] == {-}} {
+ set number [string range $number 1 end]
+ set sign {-}
+ }
+
+ # set some essential variables
+ if {$base == 8} {
+ set modulo 3
+ set mod_1 2
+ set padding {}
+ set convCmd {oct_to_bin}
+ } {
+ set modulo 4
+ set mod_1 3
+ set padding {0}
+ set convCmd {hex_to_bin}
+ }
+
+ # split value to int. and frac. part
+ regexp {^\d+} $number int
+ if {[regexp {\.\d+$} $number frac]} {
+ set frac [string range $frac 1 end]
+ set nofrac 0
+ } {
+ set frac {}
+ set nofrac 1
+ }
+
+ # convert int
+ set result {}
+
+ set length [string length $int]
+ set length [expr {($length % $modulo) - 1}]
+ if {$length >= 0} {
+ set firstvalue [string range $int 0 $length]
+ set int [string range $int [expr {$length + 1}] end]
+
+ switch $length {
+ {0} {set firstvalue "${padding}00$firstvalue"}
+ {1} {set firstvalue "${padding}0$firstvalue"}
+ {2} {set firstvalue "${padding}$firstvalue"}
+ }
+
+ lappend result $firstvalue
+ }
+
+ while {$int != ""} {
+ lappend result [string range $int 0 $mod_1]
+ set int [string range $int $modulo end]
+ }
+
+ set int [$convCmd $result]
+ regsub {^0+} $int {} int
+ if {$int == {}} {set int 0}
+
+ # convert frac
+ set result {}
+ if {!$nofrac} {
+ # make list
+ set idx -1
+ while {$frac != ""} {
+ lappend result [string range $frac 0 $mod_1]
+ set frac [string range $frac $modulo end]
+ incr idx
+ }
+
+ set lastValue [lindex $result $idx]
+ switch [string length $lastValue] {
+ {1} {lset result $idx "${lastValue}${padding}00"}
+ {2} {lset result $idx "${lastValue}${padding}0"}
+ {3} {lset result $idx "${lastValue}${padding}"}
+ }
+
+ set frac [$convCmd $result]
+ regsub {0+$} $frac {} frac
+ if {$frac == {}} {set frac 0}
+
+ # return converted value with frac.
+ return $sign$int.$frac
+ }
+
+ # return converted value without frac.
+ return $sign$int
+ }
+
+ ## Auxiliary procedure for convering dec to hex, oct, bin
+ # require procedures: `is_X', `assertdec', `isdec'
+ # @access PRIVATE
+ # @parm Int base - target numeric system, posible values are: 2, 8, 10, 16
+ # @parm Number number - value to convert
+ # @return Number - converted value
+ proc dec_to_X {base number} {
+ variable precision
+
+ # verify values validity
+ if {!($base==16 || $base==10 || $base==8 || $base==2)} {
+ error "dec_to_X: Unrecognized numeric system \"$base\". Possible values are: 2, 8, 10, 16"
+ }
+ assertdec $number
+
+ # Number can be negative value
+ set sign {}
+ if {[string index $number 0] == {-}} {
+ set number [string range $number 1 end]
+ set sign {-}
+ }
+
+ # split value to int. and frac. part
+ regexp {^\d+} $number int
+ if {[regexp {\.\d+$} $number frac]} {
+ set frac [string range $frac 1 end]
+ set nofrac 0
+ } {
+ set frac {}
+ set nofrac 1
+ }
+
+ if {[string length $int] > 12} {
+ error "Unable to convert, value is too high"
+ }
+
+ # convert integer part
+ set reminder $int
+ set int ""
+ while {$reminder > 0} {
+ set tmp [expr {$reminder % $base}]
+ if {$base == 16} {
+ switch $tmp {
+ 10 {set tmp A}
+ 11 {set tmp B}
+ 12 {set tmp C}
+ 13 {set tmp D}
+ 14 {set tmp E}
+ 15 {set tmp F}
+ }
+ }
+ set int ${tmp}${int}
+ regexp {^\d+} [expr {$reminder / $base}] reminder
+ }
+ if {$int == {}} {set int 0}
+
+ # convert frac. part
+ if {!$nofrac} {
+ set reminder "0.$frac"
+ set frac ""
+ for {set i 0} {$i < $precision} {incr i} {
+ set reminder [expr {$reminder * $base}]
+ regexp {^\d+} $reminder tmp
+ set reminder [expr {$reminder - $tmp}]
+ if {$base == 16} {
+ switch $tmp {
+ 10 {set tmp A}
+ 11 {set tmp B}
+ 12 {set tmp C}
+ 13 {set tmp D}
+ 14 {set tmp E}
+ 15 {set tmp F}
+ }
+ }
+ append frac $tmp
+ if {$reminder == 0} {break}
+ }
+ if {$frac == {}} {set frac 0}
+
+ # return converted value with frac.
+ return $sign$int.$frac
+ }
+
+ # return converted value without frac.
+ return $sign$int
+ }
+
+ ## Auxiliary procedure for convering oct to bin
+ # require procedures: none
+ # @access PRIVATE
+ # @parm List vals_list - value to convert splited to single characters
+ # @return Number - converted value
+ proc oct_to_bin {vals_list} {
+
+ # iterate over items in list and traslate them
+ set result ""
+ foreach char $vals_list {
+ # convert item
+ switch $char {
+ {000} {append result 0}
+ {001} {append result 1}
+ {010} {append result 2}
+ {011} {append result 3}
+ {100} {append result 4}
+ {101} {append result 5}
+ {110} {append result 6}
+ {111} {append result 7}
+ }
+ }
+
+ # done
+ return $result
+ }
+
+ ## Auxiliary procedure for convering hex to bin
+ # require procedures: none
+ # @access PRIVATE
+ # @parm List vals_list - value to convert splited to single characters
+ # @return Number - converted value
+ proc hex_to_bin {vals_list} {
+
+ # iterate over items in list and traslate them
+ set result ""
+ foreach char $vals_list {
+ # convert item
+ switch $char {
+ {0000} {append result 0}
+ {0001} {append result 1}
+ {0010} {append result 2}
+ {0011} {append result 3}
+ {0100} {append result 4}
+ {0101} {append result 5}
+ {0110} {append result 6}
+ {0111} {append result 7}
+ {1000} {append result 8}
+ {1001} {append result 9}
+ {1010} {append result A}
+ {1011} {append result B}
+ {1100} {append result C}
+ {1101} {append result D}
+ {1110} {append result E}
+ {1111} {append result F}
+ }
+ }
+
+ # done
+ return $result
+ }
+
+ ## Auxiliary procedure for num. checking
+ # Check if the given string contain 0 or 1 dot and match the given
+ # regular expression
+ # @access PRIVATE
+ # @parm String regexpr - reg. exp. of allowed symbols
+ # @parm String number - string to evaluate
+ # return bool
+ proc is_X {regexpr number} {
+
+ # The given number can begin with minus sign
+ if {[string index $number 0] == {-}} {
+ set number [string range $number 1 end]
+ }
+
+ # 1st condition (check for allowed symbols)
+ if {![regexp $regexpr $number]} {
+ return 0
+ }
+
+ # 2nd condition (must contain maximaly one dot)
+ set cnd1 [split $number {\.}]
+ if {[llength $cnd1] > 2} {
+ return 0
+ }
+
+ # 3rd condition (dot must not be at the begining or end)
+ if {[regexp {^\.} $number]} {return 0}
+ if {[regexp {\.$} $number]} {return 0}
+
+ # return result
+ return 1
+ }
+}
+
+
+## ----------------------------------------------------------------------
+## Converts between angle units and normalizes angle values
+ #
+ # Supported angle units: rad, deg, grad
+ # note: all converted angles are normalized before convertion
+ # -----------------------------------------------------------------------
+ #
+ # USAGE:
+ #
+ # puts [ Angle::adjustAngle deg -700 ] ;# --> 20.0000000016 (should be exactly 20)
+ #
+ # puts [ Angle::rad2deg $Angle::PI] ;# --> 180.0
+ # puts [ Angle::rad2grad $Angle::PI] ;# --> 200.0
+ #
+ # puts [ Angle::deg2rad 180 ] ;# --> 3.141592654
+ # puts [ Angle::deg2grad 180 ] ;# --> 200.0
+ #
+ # puts [ Angle::grad2deg 200 ] ;# --> 180.0
+ # puts [ Angle::grad2rad 200 ] ;# --> 3.141592654
+ #
+ # puts $Angle::PI ;# --> 3.141592654
+ # -----------------------------------------------------------------------
+
+namespace eval Angle {
+
+ variable PI {3.141592654} ;# Pi
+
+ # CONVERSION OF ANGLE VALUES
+ # --------------------------
+
+ ## Radians -> Degrees
+ # require procedure: `adjustAngle'
+ # @parm Number angle - angle value to convert
+ # @return Nubmber - converted value
+ proc rad2deg {angle} {
+ variable PI
+
+ set angle [adjustAngle rad $angle]
+ return [expr {(180 / $PI) * $angle}]
+ }
+
+ ## Radians -> GRAD
+ # require procedure: `adjustAngle'
+ # @parm Number angle - angle value to convert
+ # @return Nubmber - converted value
+ proc rad2grad {angle} {
+ variable PI
+
+ set angle [adjustAngle rad $angle]
+ return [expr {(200 / $PI) * $angle}]
+ }
+
+ ## Degrees -> Radians
+ # require procedure: `adjustAngle'
+ # @parm Number angle - angle value to convert
+ # @return Nubmber - converted value
+ proc deg2rad {angle} {
+ variable PI
+
+ set angle [adjustAngle deg $angle]
+ return [expr {($PI / 180) * $angle}]
+ }
+
+ ## Degrees -> Radians
+ # require procedure: `adjustAngle'
+ # @parm Number angle - angle value to convert
+ # @return Nubmber - converted value
+ proc deg2grad {angle} {
+ set angle [adjustAngle deg $angle]
+ return [expr {(10 / 9.0) * $angle}]
+ }
+
+ ## GRAD -> Degrees
+ # require procedure: `adjustAngle'
+ # @parm Number angle - angle value to convert
+ # @return Nubmber - converted value
+ proc grad2deg {angle} {
+ set angle [adjustAngle grad $angle]
+ return [expr {0.9 * $angle}]
+ }
+
+ ## GRAD -> Radians
+ # require procedure: `adjustAngle'
+ # @parm Number angle - angle value to convert
+ # @return Nubmber - converted value
+ proc grad2rad {angle} {
+ variable PI
+
+ set angle [adjustAngle grad $angle]
+ return [expr {($PI / 200) * $angle}]
+ }
+
+ ## Ajust angle value and polarity
+ # @parm String unit - unit of angle (rad | deg | grad)
+ # @parm angle angle - value of angle
+ # @return angle - adjusted angle value
+ proc adjustAngle {unit angle} {
+ variable PI
+
+ # verify if the given angle is a valid number
+ if {![regexp {^\-?\d+(\.\d+)?$} $angle]} {
+ error "adjustAngle: Excepted integer or float but got \"$angle\""
+ }
+
+ # determinate base for division
+ switch $unit {
+ {rad} {set base [expr {$PI * 2}]}
+ {deg} {set base 360.0}
+ {grad} {set base 400.0}
+ default {error "Unrecognized option \"$unit\""}
+ }
+
+ # is negative or something else ?
+ if {$angle < 0} {set minus 1} {set minus 0}
+
+ # adjust angle value
+ set angle [expr {$angle / $base}]
+ regsub {^[-]?\d+} $angle {0} angle
+ set angle [expr {$angle * $base}]
+
+ # adjust angle polarity
+ if {$minus} {return [expr {$base - $angle}]}
+ return $angle
+ }
+}
diff --git a/lib/lib/hexeditor.tcl b/lib/lib/hexeditor.tcl
new file mode 100755
index 0000000..ceb9192
--- /dev/null
+++ b/lib/lib/hexeditor.tcl
@@ -0,0 +1,2705 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# This class provides simple hexeditor with selectable view mode
+# and optional ascii view. See constructor and section
+# "GENERAL PUBLIC INTERFACE" for more details.
+# --------------------------------------------------------------------------
+
+class HexEditor {
+ common DEBUG 0 ;# Bool: More secure input data checking
+ # Font for editor text widget(s) - normal size
+ common view_font_n [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -15 \
+ ]
+ # Font for editor headers - normal size
+ common header_font_n [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -15 \
+ -weight bold \
+ ]
+ # Font for editor headers - small size
+ common header_font_s [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ ]
+ common view_font_s $header_font_s ;# Font for editor text widget(s) - small size
+ common header_bg {#9999FF} ;# Background color for headers
+ common header_fg {#FFFFFF} ;# Foreground color for headers
+ common n_row_bg {#DDDDDD} ;# Background color for Nth rows
+ common highlight_fg {#FFAA00} ;# Foreground color for chaged values
+ common highlight_bg {#888888} ;# Background color for background highlight (variant 0)
+ common highlight_bg1 {#FFDD33} ;# Background color for background highlight (variant 1)
+ common highlight_bg2 {#FFAA00} ;# Background color for background highlight (variant 2)
+ common unprintable_fg {#FF0000} ;# Foreground color for unprintable characters in ascii view
+ common current_full_bg {#00FF00} ;# Background color for cursor in active view
+ common current_half_bg {#AAFFAA} ;# Background color for cursor in inactive view
+ ## Variables related to find dialog
+ common find_dialog_win {} ;# Widget: Find dialog
+ common find_dialog_count 0 ;# Int: Counter find dialog opens
+ common text_to_find {} ;# String: Text/Value to find
+ common where_to_search left ;# String: Where to search (left or right view)
+ ## Array: Find options
+ # fc - Bool: Find option "From cursor"
+ # bw - Bool: Find option "Backwards"
+ common find_opt
+
+ private variable left_top_button ;# ID of button in left top corner (select all)
+ private variable left_address_bar ;# ID of left address bar
+ private variable left_header ;# ID of left header (horizontal address bar)
+ private variable right_header ;# ID of right header (horizontal address bar)
+ private variable left_view ;# ID of text of left view
+ private variable right_view ;# ID of text of right view
+ private variable scrollbar ;# ID of vertical crollbar
+ private variable main_frame ;# ID of main frame (frame for all these widgets)
+
+ private variable view_font ;# Current font for left (and right) view
+ private variable header_font ;# Current font for headers
+ private variable highlighted_cells ;# Array of Bool: highlighted cells
+ private variable bg_hg ;# Array of Bool: cells with background highlight (variant 0)
+ private variable bg_hg1 ;# Array of Bool: cells with background highlight (variant 1)
+ private variable bg_hg2 ;# Array of Bool: cells with background highlight (variant 2)
+
+ private variable current_cell_changed_cmd {} ;# Command to call on event "CurrentCellChanged"
+ private variable cell_value_changed_cmd {} ;# Command to call on event "CellValueChanged"
+ private variable cell_enter_cmd {} ;# Command to call on event "CellMouseEnter"
+ private variable cell_leave_cmd {} ;# Command to call on event "CellMouseLeave"
+ private variable cell_motion_cmd {} ;# Command to call on event "CellMouseMotion"
+ private variable scroll_action_cmd {} ;# Command to call on event "Scroll"
+ private variable selection_action_cmd {}
+ private variable current_cell_changed_cmd_set 0 ;# Bool: current_cell_changed_cmd not empty
+ private variable cell_value_changed_cmd_set 0 ;# Bool: cell_value_changed_cmd not empty
+ private variable cell_enter_cmd_set 0 ;# Bool: cell_enter_cmd not empty
+ private variable cell_leave_cmd_set 0 ;# Bool: cell_leave_cmd not empty
+ private variable cell_motion_cmd_set 0 ;# Bool: cell_motion_cmd not empty
+ private variable scroll_action_cmd_set 0 ;# Bool: scroll_action_cmd not empty
+ private variable selection_action_cmd_set 0
+
+ private variable cell_under_cursor {0.0} ;# Text index of cell under mouse pointer
+ private variable in_cell 0 ;# Bool: mouse pointer in cell (see code below)
+ private variable motion_binding 0 ;# Bool: Bindings for special mouse events set
+ private variable view_mode ;# Current view mode (one of {dec hec oct bin})
+ private variable ascii_view ;# Bool: Ascii view avaliable
+ private variable address_length ;# Int: Length of addresses on left address bar
+ private variable physical_height ;# Int: Height of view in rows
+ private variable width ;# Int: Number of cells in left view in one row
+ private variable height ;# Int: Number of rows in left view
+ private variable total_capacity ;# Int: Total editor capacity in bytes
+ private variable left_view_width ;# Int: Number of charcers in left view on one row
+ private variable value_length ;# Int: Number of characters in one cell
+ private variable cur_idx 0.0 ;# TextIndex: Last text index before selection
+ private variable selected_view {} ;# ID of active view
+ private variable popup_menu ;# ID of popup menu for both views
+ private variable selection_sync_in_P 0 ;# Bool: View selection synchronization in progress
+ private variable scroll_in_progress 0 ;# Bool: Scrolling procedure in progress
+ private variable cursor_address 0 ;# Int: Address of the current cell
+ private variable top_row 1 ;# Int: Number of topmost visible row
+ private variable disabled 0 ;# Bool: Editor disabled
+ private variable last_find_index {} ;# String: Index of first matched characted (find dialog)
+ private variable scrollbar_visible 0 ;# Bool: Scrollbar visibility flag
+
+ ## Costructor
+ # @parm WidgetPath mainframe - Path where to create editor main frame
+ # @parm Int Width - Number of columns in row (max. 16)
+ # @parm Int Height - Number rows
+ # @parm Int addresslength - Number of characters on one row in left address bar
+ # @parm String mode - Initial view mode (one of {hex dec bin oct})
+ # @parm Bool ascii - Display also ascii view
+ # @parm Bool small - Use small fonts
+ # @parm Int physicalheight - Heigh of views in rows
+ # @parm Int totalcapacity - Total capacity in Bytes
+ constructor {mainframe Width Height addresslength mode ascii small physicalheight totalcapacity} {
+ # Set object variables
+ set view_mode $mode
+ set ascii_view $ascii
+ set physical_height $physicalheight
+ set address_length $addresslength
+ set width $Width
+ set height $Height
+ set total_capacity $totalcapacity
+
+ # Initalize array of highlighted cells
+ for {set i 0} {$i < $total_capacity} {incr i} {
+ set highlighted_cells($i) 0
+ set bg_hg($i) 0
+ set bg_hg1($i) 0
+ set bg_hg2($i) 0
+ }
+
+ # Validate inputs arguments
+ if {$width > 16} {
+ error "Width cannot be grater than 16"
+ }
+ if {![string is boolean $small]} {
+ error "Invalid value for argument small: $small"
+ }
+
+ # Determinate fonts
+ if {$small} {
+ set view_font $view_font_s
+ set header_font $header_font_s
+ } {
+ set view_font $view_font_n
+ set header_font $header_font_n
+ }
+
+ # Create main frame
+ set main_frame [frame $mainframe]
+ bind $main_frame <Destroy> "catch {::itcl::delete object $this}"
+
+ # Create GUI components
+ create_gui ;# Create text widgets
+ create_popup_menu ;# Create popup menu
+ create_tags ;# Create text tags
+ create_bindings ;# Create bindings
+ fill_headers ;# Fill headers with appropriate addresses
+ fill_views ;# Fill views with spaces
+
+ # Finalize GUI initialization
+ $left_view mark set insert 1.0
+ set_selected_view {left}
+ }
+
+ ## Object destructor
+ destructor {
+ catch {
+ destroy $main_frame
+ }
+ }
+
+ ## Create popup menu (for left & right view)
+ # @return void
+ private method create_popup_menu {} {
+ set popup_menu $main_frame.popup_menu
+ menuFactory {
+ {command {Copy} {Ctrl+C} 0
+ "text_copy" {editcopy} {}}
+ {command {Paste} {Ctrl+V} 0
+ "text_paste" {editpaste} {}}
+ {separator}
+ {command {Select all} {Ctrl+A} 0
+ "text_selall" {} {}}
+ {separator}
+ {command {Find} {Ctrl+F} 0
+ "find_dialog" {find} {}}
+ {command {Find next} {F3} 5
+ "find_next" {1downarrow} {}}
+ {command {Find previous} {Shift+F3} 8
+ "find_prev" {1uparrow} {}}
+ } $popup_menu 0 "$this " 0 {}
+
+ # Configure menu entries
+ $popup_menu entryconfigure [::mc "Find next"] -state disabled
+ $popup_menu entryconfigure [::mc "Find previous"] -state disabled
+ }
+
+ ## Create all hexeditor widgets expect popup menu
+ # @return void
+ private method create_gui {} {
+ # Determinate width of left view text widget and cell width
+ switch -- $view_mode {
+ {hex} {
+ set left_view_width [expr {$width * 3 - 1}]
+ set value_length 2
+ }
+ {oct} {
+ set left_view_width [expr {$width * 4 - 1}]
+ set value_length 3
+ }
+ {dec} {
+ set left_view_width [expr {$width * 4 - 1}]
+ set value_length 3
+ }
+ default {
+ error "Invalid mode: $view_mode"
+ }
+ }
+
+ # Create button "Select All" in left top corner
+ set left_top_button [button $main_frame.left_top_button \
+ -bg $header_bg -bd 0 -padx 0 -pady 0 \
+ -activebackground white -relief flat \
+ -highlightthickness 0 \
+ -command "$main_frame.left_view tag add sel 1.0 end" \
+ ]
+ DynamicHelp::add $main_frame.left_top_button -text [mc "Select all"]
+ # Create left address bar
+ set left_address_bar [text $main_frame.left_address_bar \
+ -height $physical_height -width $address_length \
+ -font $header_font -bg $header_bg \
+ -relief flat -bd 1 -fg $header_fg \
+ -highlightthickness 0 -takefocus 0 \
+ -yscrollcommand "$this scrollSet" \
+ -cursor left_ptr \
+ ]
+ grid $left_top_button -row 0 -column 0 -sticky nsew
+ grid $left_address_bar -row 1 -column 0 -sticky ns
+
+ # Create horizontal header for left view
+ set left_header [text $main_frame.left_header \
+ -height 1 -width $left_view_width \
+ -font $header_font -bg $header_bg \
+ -relief flat -bd 1 -fg $header_fg \
+ -highlightthickness 0 -takefocus 0 \
+ -cursor left_ptr \
+ ]
+ grid $left_header -row 0 -column 1
+ # Create horizontal header for ascii view
+ if {$ascii_view} {
+ grid [ttk::separator $main_frame.sep \
+ -orient horizontal \
+ ] -row 0 -rowspan 2 -column 2 -sticky ns
+
+ set right_header [text $main_frame.right_header \
+ -height 1 -width $width -bg $header_bg \
+ -font $header_font -relief flat -bd 1 \
+ -fg $header_fg -highlightthickness 0 \
+ -takefocus 0 \
+ -cursor left_ptr \
+ ]
+ grid $right_header -row 0 -column 3
+ }
+
+ # Create text widget of the left view
+ set left_view [text $main_frame.left_view \
+ -font $header_font -relief flat -bd 1 \
+ -width $left_view_width -bg white \
+ -highlightthickness 0 -height $physical_height \
+ -yscrollcommand "$this scrollSet" \
+ ]
+ grid $left_view -row 1 -column 1 -sticky ns
+ # Create text widget for ascii view
+ if {$ascii_view} {
+ set right_view [text $main_frame.right_view \
+ -font $header_font -relief flat -bd 1 \
+ -width $width -bg white \
+ -highlightthickness 0 -height $physical_height \
+ -exportselection 0 -insertwidth 0 \
+ -yscrollcommand "$this scrollSet" \
+ ]
+ grid $right_view -row 1 -column 3 -sticky ns
+ }
+
+ # Create vertical scrollbar
+ set scrollbar [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$this scroll" \
+ ]
+ set scrollbar_visible 0
+ showHideScrollbar 1
+
+ grid rowconfigure $main_frame 1 -weight 1
+ }
+
+ ## Create event bindings for all hexeditor widgets (except popup menu)
+ # @return void
+ private method create_bindings {} {
+ ## LEFT PART
+ bindtags $left_header $left_header
+ bindtags $left_address_bar $left_address_bar
+ bindtags $left_view [list $left_view . all]
+
+ foreach key {Left Right Up Down Home End Prior Next} {
+ bind $left_view <Key-$key> "$this left_view_movement 0 {$key}; break"
+ bind $left_view <Shift-Key-$key> "$this left_view_movement 1 {$key}; break"
+ }
+ for {set i 1} {$i < 21} {incr i} {
+ bind $left_view <Key-F$i> {continue}
+ }
+ bind $left_view <Control-Key> {continue}
+ bind $left_view <Alt-Key> {continue}
+ bind $left_view <Key-BackSpace> "$this left_view_movement 0 Left; break"
+ bind $left_view <Key-Menu> "$this popup_menu left %x %y %X %Y; break"
+ bind $left_view <ButtonRelease-3> "$this popup_menu left %x %y %X %Y; break"
+ bind $left_view <Key-Tab> "$this switch_views; break"
+ if {!$::MICROSOFT_WINDOWS} {
+ bind $left_view <Key-ISO_Left_Tab> "$this switch_views; break"
+ }
+ bind $left_view <KeyPress> "$this left_view_key %A; break"
+ bind $left_view <Button-1> "$this left_view_B1 %x %y; break"
+ bind $left_view <<Paste>> "$this text_paste; break"
+ bind $left_view <Control-Key-a> "$left_view tag add sel 1.0 end"
+ bind $left_view <<Selection>> "$this left_view_selection; break"
+ bind $left_view <FocusIn> "$this set_selected_view left"
+ bind $left_view <Key-Escape> {catch {%W tag remove sel 0.0 end}; break}
+ bind $left_view <Control-Key-f> "$this find_dialog; break"
+ bind $left_view <Control-Key-F> "$this find_dialog; break"
+ bind $left_view <F3> "$this find_next; break"
+ if {!$::MICROSOFT_WINDOWS} {
+ bind $left_view <XF86_Switch_VT_3> "$this find_prev; break"
+ }
+ bind $left_view <B1-Motion> "
+ $this left_view_B1_Motion %x %y
+ $this text_view_leave
+ break"
+ foreach key {
+ <ButtonRelease-1> <B1-Enter> <B1-Leave>
+ <B2-Motion> <Button-5> <Button-4>
+ <MouseWheel> <<Copy>> <Double-Button-1>
+ } {
+ bind $left_view $key "[bind Text $key]; break"
+ }
+
+ bind $left_view <Button-4> "$this scroll scroll -3 units"
+ bind $left_view <Button-5> "$this scroll scroll +3 units"
+ bind $left_address_bar <Button-4> "$this scroll scroll -3 units"
+ bind $left_address_bar <Button-5> "$this scroll scroll +3 units"
+ bind $left_address_bar <MouseWheel> "[bind Text <MouseWheel>]; break"
+
+ ## RIGHT PART
+ if {$ascii_view} {
+ bindtags $right_view [list $right_view . all]
+ bindtags $right_header $right_header
+
+ foreach key {<Copy> Double-Button-1} {
+ bind $right_view <$key> {continue}
+ }
+ for {set i 1} {$i < 21} {incr i} {
+ bind $right_view <Key-F$i> {continue}
+ }
+ foreach event {
+ Key-Prior Key-Next Shift-Key-Up Shift-Key-Down
+ Shift-Key-Home Key-Home Shift-Key-Prior Shift-Key-Next
+ Button-1 Key-Up Key-Down
+ Shift-Key-Left Shift-Key-Right Shift-Key-End
+ } {
+ bind $right_view <$event> "
+ [bind Text <$event>]
+ $this right_view_adjust_cursor
+ break"
+ }
+ bind $right_view <Key-Left> "$this right_view_movement Left"
+ bind $right_view <Key-Right> "$this right_view_movement Right"
+ bind $right_view <Key-End> "$this right_view_movement End"
+
+ bind $right_view <B1-Motion> "
+ [bind Text <B1-Motion>]
+ $this right_view_adjust_cursor
+ $this text_view_leave
+ break"
+ bind $right_view <Key-BackSpace> "
+ [bind Text <Key-Left>]
+ $this right_view_adjust_cursor
+ break"
+ bind $right_view <Key-Menu> "$this popup_menu right %x %y %X %Y; break"
+ bind $right_view <ButtonRelease-3> "$this popup_menu right %x %y %X %Y; break"
+ bind $right_view <Key-Tab> "$this switch_views; break"
+ if {!$::MICROSOFT_WINDOWS} {
+ bind $right_view <Key-ISO_Left_Tab> "$this switch_views; break"
+ }
+ bind $right_view <KeyPress> "$this right_view_key %A; break"
+ bind $right_view <<Paste>> "$this text_paste; break"
+ bind $right_view <Control-Key-a> "$right_view tag add sel 1.0 end"
+ bind $right_view <<Selection>> "$this right_view_selection; break"
+ bind $right_view <FocusIn> "$this set_selected_view right"
+ bind $right_view <Key-Escape> {catch {%W tag remove sel 0.0 end}; break}
+ bind $right_view <Control-Key-f> "$this find_dialog; break"
+ bind $right_view <Control-Key-F> "$this find_dialog; break"
+ bind $right_view <F3> "$this find_next; break"
+ if {!$::MICROSOFT_WINDOWS} {
+ bind $right_view <XF86_Switch_VT_3> "$this find_prev; break"
+ }
+ foreach key {
+ <ButtonRelease-1> <B1-Enter> <B1-Leave>
+ <MouseWheel> <<Copy>> <Double-Button-1>
+ <B2-Motion>
+ } {
+ bind $right_view $key "[bind Text $key]; break"
+ }
+
+ bind $right_view <Button-4> "$this scroll scroll -3 units"
+ bind $right_view <Button-5> "$this scroll scroll +3 units"
+ }
+ }
+
+ ## Create text tags
+ # @return void
+ private method create_tags {} {
+ #
+ ## LEFT PART
+ #
+
+ # Cursor position
+ $left_address_bar tag configure tag_current_full \
+ -font $header_font \
+ -background $current_full_bg \
+ -foreground {#000000}
+ # Cursor position for active view and inactive view
+ foreach widget [list $left_header $left_view] {
+ $widget tag configure tag_current_full \
+ -font $header_font \
+ -background $current_full_bg \
+ -foreground {#000000}
+ $widget tag configure tag_current_half \
+ -font $header_font \
+ -background $current_half_bg \
+ -foreground {#000000}
+ }
+ # Nth row backrgound
+ $left_view tag configure tag_n_row -background $n_row_bg
+ # Cell highlight
+ $left_view tag configure tag_hg \
+ -foreground $highlight_fg \
+ -font $header_font
+ $left_view tag configure tag_bg_hg \
+ -background $highlight_bg \
+ -font $header_font
+ $left_view tag configure tag_bg_hg1 \
+ -background $highlight_bg1 \
+ -font $header_font
+ $left_view tag configure tag_bg_hg2 \
+ -background $highlight_bg2 \
+ -font $header_font
+ # Other tags
+ $left_view tag configure normal_font \
+ -font $view_font
+
+ # Set tags priorities
+ $left_view tag raise sel tag_n_row
+ $left_view tag raise sel tag_current_full
+ $left_view tag raise sel tag_current_half
+ $left_view tag raise sel tag_bg_hg
+ $left_view tag raise sel tag_bg_hg1
+ $left_view tag raise sel tag_bg_hg2
+ $left_view tag raise tag_current_full normal_font
+ $left_view tag raise tag_current_half normal_font
+ $left_view tag raise tag_bg_hg normal_font
+ $left_view tag raise tag_bg_hg1 normal_font
+ $left_view tag raise tag_bg_hg2 normal_font
+ $left_view tag raise tag_bg_hg2 tag_bg_hg1
+ $left_view tag raise tag_bg_hg tag_n_row
+ $left_view tag raise tag_bg_hg1 tag_n_row
+ $left_view tag raise tag_bg_hg2 tag_n_row
+ $left_view tag raise tag_current_full tag_n_row
+ $left_view tag raise tag_current_half tag_n_row
+ $left_view tag raise tag_current_full tag_bg_hg
+ $left_view tag raise tag_current_half tag_bg_hg
+ $left_view tag raise tag_current_full tag_bg_hg1
+ $left_view tag raise tag_current_half tag_bg_hg1
+ $left_view tag raise tag_current_full tag_bg_hg2
+ $left_view tag raise tag_current_half tag_bg_hg2
+
+ #
+ ## RIGHT PART
+ #
+ if {$ascii_view} {
+ # Unprintable characters
+ $right_view tag configure tag_np \
+ -font $view_font \
+ -foreground $unprintable_fg
+
+ # Cursor position for active view
+ $right_header tag configure tag_current_full \
+ -font $header_font \
+ -background $current_full_bg \
+ -foreground {#000000}
+ # Cursor position for inactive view
+ $right_header tag configure tag_current_half \
+ -font $header_font \
+ -background $current_half_bg \
+ -foreground {#000000}
+
+ # Cursor position for active view
+ $right_view tag configure tag_current_full \
+ -font $header_font \
+ -background $current_full_bg
+ # Cursor position for inactive view
+ $right_view tag configure tag_current_half \
+ -font $header_font \
+ -background $current_half_bg
+
+ # Nth row backrgound
+ $right_view tag configure tag_n_row -background $n_row_bg
+ # Cell highlight
+ $right_view tag configure tag_hg \
+ -foreground $highlight_fg \
+ -font $header_font
+ $right_view tag configure tag_bg_hg \
+ -background $highlight_bg \
+ -font $header_font
+ $right_view tag configure tag_bg_hg1 \
+ -background $highlight_bg1 \
+ -font $header_font
+ $right_view tag configure tag_bg_hg2 \
+ -background $highlight_bg2 \
+ -font $header_font
+
+ # Other tags
+ $right_view tag configure normal_font \
+ -font $view_font
+
+ # Set tags priorities
+ $right_view tag raise sel tag_current_full
+ $right_view tag raise sel tag_current_half
+ $right_view tag raise sel tag_n_row
+ $right_view tag raise sel tag_bg_hg
+ $right_view tag raise sel tag_bg_hg1
+ $right_view tag raise sel tag_bg_hg2
+ $right_view tag raise tag_current_full normal_font
+ $right_view tag raise tag_current_half normal_font
+ $right_view tag raise tag_bg_hg normal_font
+ $right_view tag raise tag_bg_hg1 normal_font
+ $right_view tag raise tag_bg_hg2 normal_font
+ $right_view tag raise tag_bg_hg2 tag_bg_hg1
+ $right_view tag raise tag_bg_hg tag_n_row
+ $right_view tag raise tag_bg_hg1 tag_n_row
+ $right_view tag raise tag_bg_hg2 tag_n_row
+ $right_view tag raise tag_current_full tag_n_row
+ $right_view tag raise tag_current_half tag_n_row
+ $right_view tag raise tag_current_full tag_bg_hg
+ $right_view tag raise tag_current_half tag_bg_hg
+ $right_view tag raise tag_current_full tag_bg_hg1
+ $right_view tag raise tag_current_half tag_bg_hg1
+ $right_view tag raise tag_current_full tag_bg_hg2
+ $right_view tag raise tag_current_half tag_bg_hg2
+ }
+ }
+
+ ## Restore cell highlight
+ # @parm Int address - Cell address
+ # @return void
+ private method restore_cell_highlight {address} {
+ if {$highlighted_cells($address)} {
+ set highlighted_cells($address) 0
+ setHighlighted $address 1
+ }
+ if {$bg_hg($address)} {
+ set bg_hg($address) 0
+ set_bg_hg $address 1 0
+ }
+ if {$bg_hg1($address)} {
+ set bg_hg1($address) 0
+ set_bg_hg $address 1 1
+ }
+ if {$bg_hg2($address)} {
+ set bg_hg2($address) 0
+ set_bg_hg $address 1 2
+ }
+ }
+
+ ## Fill headres with addresses
+ # @return void
+ private method fill_headers {} {
+ # Left horizontal header
+ fill_left_header
+
+ # Left address bar
+ $left_address_bar delete 1.0 end
+ $left_address_bar insert end [string repeat {0} $address_length]
+ set line {}
+ set address {}
+ for {set i 1} {$i < $height} {incr i} {
+ set address [format {%X} [expr {$i * $width}]]
+ set line "\n"
+ append line [string repeat {0} \
+ [expr {$address_length - [string length $address]}]]
+ append line $address
+ $left_address_bar insert end $line
+ }
+
+ # Right horizontal header
+ set header_values [list 0 1 2 3 4 5 6 7 8 9 A B C D E F]
+ if {$ascii_view} {
+ $right_header delete 1.0 end
+ for {set i 0} {$i < $width} {incr i} {
+ $right_header insert end [lindex $header_values $i]
+ }
+ }
+ }
+
+ ## Left horizontal header with cell addresses
+ # @return void
+ private method fill_left_header {} {
+ set header_values [list 0 1 2 3 4 5 6 7 8 9 A B C D E F]
+ $left_header delete 1.0 end
+ if {$view_mode == {hex}} {
+ set space { }
+ } {
+ $left_header insert end { }
+ set space { }
+ }
+ for {set i 0} {$i < $width} {incr i} {
+ if {$i} {
+ $left_header insert end $space
+ }
+ $left_header insert end {x}
+ $left_header insert end [lindex $header_values $i]
+ }
+ }
+
+ ## Fill all views with spaces
+ # @return void
+ public method fill_views {} {
+ # Fill left view with spaces
+ $left_view delete 1.0 end
+ set line [string repeat { } $left_view_width]
+ $left_view insert end $line
+ $left_view tag add normal_font {insert linestart} {insert lineend}
+ for {set i 1} {$i < $height} {incr i} {
+ $left_view insert end "\n"
+ $left_view tag add normal_font {insert linestart} {insert lineend}
+ $left_view insert end $line
+
+ if {![expr {$i % 3}]} {
+ $left_view tag add tag_n_row \
+ [expr {$i - 1}].$left_view_width \
+ [expr {$i + 1}].0
+ }
+ }
+
+ # Fill right view with spaces
+ if {$ascii_view} {
+ $right_view delete 1.0 end
+ set line [string repeat { } $width]
+ $right_view insert end $line
+ $right_view tag add normal_font {insert linestart} {insert lineend}
+ for {set i 1} {$i < $height} {incr i} {
+ $right_view insert end "\n"
+ $right_view tag add normal_font {insert linestart} {insert lineend}
+ $right_view insert end $line
+
+ if {![expr {$i % 3}]} {
+ $right_view tag add tag_n_row \
+ [expr {$i - 1}].$left_view_width \
+ [expr {$i + 1}].0
+ }
+ }
+ }
+ }
+
+ ## Translate cell address to text indexes
+ # @parm Int address - address to translate
+ # @return List {row column_in_right_view start_col_in_left_view end_col_in_left_view}
+ private method address_to_index {address} {
+ # Local variable
+ set row [expr {$address / $width + 1}] ;# Row
+ set cell [expr {$address % $width}] ;# Column in right view
+ set start_col 0 ;# Start column in left view
+
+ # Determinate start column
+ if {$cell} {
+ if {$view_mode != {hex}} {
+ set start_col [expr {$cell * 4}]
+ } {
+ set start_col [expr {$cell * 3}]
+ }
+ }
+
+ # Determinate end column
+ set end_col $start_col
+ if {$view_mode != {hex}} {
+ incr end_col 3
+ } {
+ incr end_col 2
+ }
+
+ # Return results
+ return [list $row $cell $start_col $end_col]
+ }
+
+ ## Translate text index to address
+ # @parm String view - View from which is index to translate
+ # @parm TextIndex index - Indext to translate
+ # @return Int address
+ private method index_to_address {view index} {
+ # Left view
+ if {$view == {left}} {
+ if {$view_mode != {hex}} {
+ set step 4
+ } {
+ set step 3
+ }
+ scan [$left_view index $index] {%d.%d} row col
+ set cell [expr {($col / $step)}]
+ # Right view
+ } {
+ scan [$right_view index $index] {%d.%d} row cell
+ }
+
+ # Return result
+ incr row -1
+ return [expr {$row * $width + $cell}]
+ }
+
+ ## Normalize column in left view
+ # @parm Int col - column to normalize
+ # @return {start_column end_column cell_number_in_row}
+ private method col_to_start_end {col} {
+ if {$view_mode != {hex}} {
+ set step 4
+ } {
+ set step 3
+ }
+
+ set cell [expr {($col / $step)}]
+ set start [expr {$cell * $step}]
+ set end [expr {$start + $step - 1}]
+
+ return [list $start $end $cell]
+ }
+
+ ## Adjust cursor tags to the current cursor positions (for left view)
+ # @return void
+ private method left_view_adjust_cursor {} {
+ scan [$left_view index insert] {%d.%d} row col
+
+ set boundaries [col_to_start_end $col]
+ set col_s [lindex $boundaries 0]
+ set col_e [lindex $boundaries 1]
+ set cell [lindex $boundaries 2]
+ set cursor_address_original $cursor_address
+ set cursor_address [expr {($row - 1) * $width + $cell}]
+ if {$cursor_address >= $total_capacity} {
+ set cursor_address $cursor_address_original
+ setCurrentCell $cursor_address_original
+ return
+ }
+
+ # Clear cell highlight
+ if {$highlighted_cells($cursor_address)} {
+ setHighlighted $cursor_address 0
+ }
+ # Execute command binded to event CurrentCellChanged
+ if {$current_cell_changed_cmd_set && $cursor_address_original != $cursor_address} {
+ eval "$current_cell_changed_cmd $cursor_address"
+ }
+
+ ## Create cursor tags in right view
+ if {$ascii_view} {
+ $right_header tag remove tag_current_half 0.0 end
+ $right_header tag add tag_current_half 1.$cell 1.$cell+1c
+
+ $right_view tag remove tag_current_half 0.0 end
+ $right_view tag add tag_current_half $row.$cell "$row.$cell +1c"
+ }
+
+ ## Create cursor tags in left view
+ $left_address_bar tag remove tag_current_full 0.0 end
+ $left_address_bar tag add tag_current_full $row.0 $row.0+1l
+
+ $left_header tag remove tag_current_full 0.0 end
+ $left_header tag add tag_current_full 1.$col_s 1.$col_e
+
+ $left_view tag remove tag_current_full 0.0 end
+ $left_view tag add tag_current_full $row.$col_s $row.$col_e
+ }
+
+ ## Create binding for <Motion> and <Leave> events for left and right view
+ # @return void
+ private method bind_mouse_motions {} {
+ if {$motion_binding} {return}
+ set motion_binding 1
+
+ bind $left_view <Motion> "$this left_view_motion %x %y %X %Y"
+ bind $left_view <Leave> "$this text_view_leave"
+
+ if {$ascii_view} {
+ bind $right_view <Motion> "$this right_view_motion %x %y %X %Y"
+ bind $right_view <Leave> "$this text_view_leave"
+ }
+ }
+
+ ## Binding for event <ButtonPress-1> in left view
+ # @parm Int x - Relative horizontal position of mouse pointer
+ # @parm Int y - Relative vertical position of mouse pointer
+ # @return void
+ private method left_view_move_insert {x y} {
+ set index [$left_view index @$x,$y]
+ scan $index {%d.%d} row col
+
+ if {$view_mode != {hex}} {
+ if {($col % 4) == 3} {
+ set index [$left_view index "$index+1c"]
+ }
+ } {
+ if {($col % 3) == 2} {
+ set index [$left_view index "$index+1c"]
+ }
+ }
+ $left_view mark set insert $index
+ left_view_adjust_cursor
+ }
+
+ ## Adjust cursor tags to the current cursor positions (for right view)
+ # @return void
+ public method right_view_adjust_cursor {} {
+ if {!$ascii_view} {
+ return
+ }
+
+ scan [$right_view index insert] {%d.%d} row cell
+ if {$view_mode != {hex}} {
+ set step 4
+ } {
+ set step 3
+ }
+ set cursor_address_original $cursor_address
+ set cursor_address [expr {($row - 1) * $width + $cell}]
+ if {$cursor_address >= $total_capacity} {
+ set cursor_address [expr {$total_capacity - 1}]
+ set index [address_to_index $cursor_address]
+ set row [lindex $index 0]
+ set cell [lindex $index 1]
+ $right_view mark set insert $row.$cell
+ }
+ set col_s [expr {$cell * $step}]
+ set col_e [expr {$col_s + $step - 1}]
+
+ # Clear cell highlight
+ if {$highlighted_cells($cursor_address)} {
+ setHighlighted $cursor_address 0
+ }
+ # Execute command binded to event CurrentCellChanged
+ if {$current_cell_changed_cmd_set && $cursor_address_original != $cursor_address} {
+ eval "$current_cell_changed_cmd $cursor_address"
+ }
+
+ ## Adjust cursor tags in right view
+ $right_header tag remove tag_current_full 0.0 end
+ $right_header tag add tag_current_full 1.$cell 1.$cell+1c
+
+ $right_view tag remove tag_current_full 0.0 end
+ $right_view tag add tag_current_full $row.$cell "$row.$cell +1c"
+
+ ## Adjust cursor tags in left view
+ $left_address_bar tag remove tag_current_full 0.0 end
+ $left_address_bar tag add tag_current_full $row.0 $row.0+1l
+
+ $left_header tag remove tag_current_half 0.0 end
+ $left_header tag add tag_current_half 1.$col_s 1.$col_e
+
+ $left_view tag remove tag_current_half 0.0 end
+ $left_view tag add tag_current_half $row.$col_s $row.$col_e
+ }
+
+ ## Binding for event <KeyPress> in right view
+ # @parm String key - binary key code
+ # @return void
+ public method right_view_key {key} {
+ if {$disabled} {return}
+ if {!$ascii_view} {
+ return
+ }
+ # Key must be 8 bit printable character
+ if {![string is print -strict $key] || ([string bytelength $key] > 1)} {
+ return
+ }
+
+ # Determinate row, column and index of insertion cursor
+ set index [$right_view index insert]
+ scan $index {%d.%d} row col
+
+ # Check for valid position (insert mustn't be after the end of editor)
+ if {($row == $height) && ($col >= $width)} {
+ return
+ }
+
+ # Convert value to decimal and check for valid ASCII value
+ binary scan $key c key
+ if {$key > 126 || $key < 0} {
+ return
+ }
+
+ # Synchronize views
+ incr row -1
+ set address [expr {$row * $width + $col}]
+ setValue $address $key
+ if {$cell_value_changed_cmd_set} {
+ eval "$cell_value_changed_cmd $address $key"
+ }
+ }
+
+ ## Synchronize selection in right view with left view
+ # Binding for event <<Selection>>
+ # @return void
+ public method right_view_selection {} {
+ if {$selection_sync_in_P} {return}
+ set selection_sync_in_P 1
+
+ $left_view tag remove sel 0.0 end
+ if {![llength [$right_view tag nextrange sel 0.0]]} {
+ set selection_sync_in_P 0
+ set anything_selected 0
+ } {
+ set anything_selected 1
+ }
+
+ if {$selection_action_cmd_set} {
+ set flag $anything_selected
+ if {$flag} {
+ if {![string length [string trim [$right_view get sel.first sel.last]]]} {
+ set flag 0
+ }
+ }
+ eval "$selection_action_cmd $flag"
+ }
+
+ if {!$anything_selected} {
+ return
+ }
+
+ if {!$ascii_view} {
+ return
+ }
+
+ if {$view_mode != {hex}} {
+ set step 4
+ } {
+ set step 3
+ }
+
+ scan [$right_view index sel.first] {%d.%d} start_row start_col
+ set start_col [expr {$start_col * $step}]
+ scan [$right_view index sel.last] {%d.%d} end_row end_col
+ set end_col [expr {$end_col * $step}]
+
+ $left_view tag add sel $start_row.$start_col $end_row.$end_col
+ set selection_sync_in_P 0
+ }
+
+ ## Make scrollbar visible or not
+ # @parm Bool display - 1 == Visible; 0 == Invisible
+ # @return void
+ public method showHideScrollbar {display} {
+
+ # Show scrollbar
+ if {!$scrollbar_visible && $display} {
+ set scrollbar_visible 1
+ grid $scrollbar -row 0 -rowspan 2 -column 4 -sticky ns
+
+ # Hide scrollbar
+ } elseif {$scrollbar_visible && !$display} {
+ set scrollbar_visible 0
+ grid forget $scrollbar
+ }
+ }
+
+ ## Set scrollbar and synchronize visible area in both views
+ # text $x -yscrollcommand "$this scrollSet"
+ # @parm float fraction0 - Fraction of topmost visible area
+ # @parm float fraction1 - Fraction of bottommost visible area
+ # @return void
+ public method scrollSet {fraction0 fraction1} {
+ $scrollbar set $fraction0 $fraction1
+ scroll moveto $fraction0
+ }
+
+ ## Scroll both views, left address bar and adjust scrollbar
+ # $scrollbar -command "$this scrollSet"
+ # @parm String args - Here should be something like "moveto 0.1234"
+ # @return void
+ public method scroll args {
+ if {$scroll_in_progress} {return}
+ set scroll_in_progress 1
+
+ eval "$left_view yview $args"
+
+ set idx [$left_view index @5,5]
+ scan $idx "%d.%d" row col
+ incr row -1
+ set top_row $row
+ $left_view yview $row
+ $left_address_bar yview $row
+
+ if {$ascii_view} {
+ $right_view yview $row
+ }
+
+ if {$scroll_action_cmd_set} {
+ eval $scroll_action_cmd
+ }
+
+ update idle
+ set scroll_in_progress 0
+ }
+
+ ## Synchronize selection in left view with left view
+ # Binding for event <<Selection>>
+ # @return void
+ public method left_view_selection {} {
+ if {$selection_sync_in_P} {return}
+ set selection_sync_in_P 1
+
+ if {$ascii_view} {
+ $right_view tag remove sel 0.0 end
+ }
+ if {![llength [$left_view tag nextrange sel 0.0]]} {
+ set selection_sync_in_P 0
+ set anything_selected 0
+ } {
+ set anything_selected 1
+ }
+
+ if {$selection_action_cmd_set} {
+ set flag $anything_selected
+ if {$flag} {
+ if {![string length [string trim [$left_view get sel.first sel.last]]]} {
+ set flag 0
+ }
+ }
+ eval "$selection_action_cmd $flag"
+ }
+
+ if {!$anything_selected} {
+ return
+ }
+
+ if {!$ascii_view} {
+ return
+ }
+
+ scan [$left_view index sel.first] {%d.%d} start_row start_col
+ set start_col [lindex [col_to_start_end $start_col] 2]
+ scan [$left_view index {sel.last-1c}] {%d.%d} end_row end_col
+ set end_col [lindex [col_to_start_end $end_col] 2]
+ incr end_col
+
+ $right_view tag add sel $start_row.$start_col $end_row.$end_col
+ set selection_sync_in_P 0
+ }
+
+ ## Copy text from selected view
+ # @return void
+ public method text_copy {} {
+ if {![llength [$left_view tag nextrange sel 0.0]]} {
+ return
+ }
+
+ if {$selected_view == {left}} {
+ clipboard clear
+ clipboard append [string trim [$left_view get sel.first sel.last]]
+ } elseif {($selected_view == {right}) && $ascii_view} {
+ clipboard clear
+ clipboard append [string trim [$right_view get sel.first sel.last]]
+ }
+ }
+
+ ## Paste text to active view
+ # @return void
+ public method text_paste {} {
+ if {$disabled} {return}
+
+ # Get clipboard contents
+ if {[catch {
+ set text [clipboard get]
+ }]} {
+ set text {}
+ }
+ # If clipboard empty then return
+ if {![string length $text]} {
+ return
+ }
+
+ # Paste to left view
+ if {$selected_view == {left}} {
+ # Remove all characters invalid in current view mode
+ switch -- $view_mode {
+ {hex} {
+ regsub -all {[^0-9a-fA-F ]} $text {} text
+ set step 1
+ }
+ {oct} {
+ regsub -all {[^0-7 ]} $text {} text
+ set step 2
+ }
+ {dec} {
+ regsub -all {[^0-9 ]} $text {} text
+ set step 2
+ }
+ }
+
+ # Determinate start address
+ set address [index_to_address left [$left_view index insert]]
+
+ # Iterate over the text and convert each pair/triad of charaters
+ set len [string length $text]
+ for {set i 0} {$i < $len} {incr i $value_length} {
+ # Get character pair/triad
+ set val [string range $text $i [expr {$i + $step}]]
+ if {[string is space -strict $val]} {
+ incr address
+ if {$address >= $total_capacity} {
+ break
+ }
+ continue
+ }
+ set val [string trim $val]
+ set val [string trimleft $val 0]
+
+ # Convert value to decimal
+ if {$val == {}} {
+ set val 0
+ }
+ if {$view_mode == {hex}} {
+ set val [expr int("0x$val")]
+ } elseif {$view_mode == {oct}} {
+ set val [expr int("0$val")]
+ }
+
+ # Check for allowed range
+ if {$val < 0 || $val > 255} {
+ continue
+ }
+
+ # Set value in editor, simulator and others
+ setValue $address $val
+ if {$cell_value_changed_cmd_set} {
+ eval "$cell_value_changed_cmd $address $val"
+ }
+ incr address
+ incr i
+ if {$address >= $total_capacity} {
+ break
+ }
+ }
+
+ # Adjust insertion cursor
+ set address [address_to_index $address]
+ $left_view mark set insert [lindex $address 0].[lindex $address 2]
+ $left_view see insert
+ left_view_adjust_cursor
+
+ # Paste to right view
+ } elseif {($selected_view == {right}) && $ascii_view} {
+ # Determinate start address, row and column
+ scan [$right_view index insert] {%d.%d} row col
+ incr row -1
+ set address [expr {$row * $width + $col}]
+
+ # Iterate over characters in the text
+ foreach val [split $text {}] {
+ # Convert to decimal
+ binary scan $val c val
+ if {$val < 0 || $val > 126} {
+ incr address
+ continue
+ }
+
+ # Check for valid address
+ if {$address >= $total_capacity} {
+ break
+ }
+
+ # Set value in editor, simulator and others
+ setValue $address $val
+ if {$cell_value_changed_cmd_set} {
+ eval "$cell_value_changed_cmd $address $val"
+ }
+ incr address
+ }
+
+ # Adjust insertion cursor
+ set address [address_to_index $address]
+ $right_view mark set insert [lindex $address 0].[lindex $address 1]
+ $right_view see insert
+ right_view_adjust_cursor
+ }
+ }
+
+ ## Select all text in both views
+ # @return void
+ public method text_selall {} {
+ $left_view tag add sel 1.0 end
+ }
+
+ ## Left view event handler: <B1-Motion>
+ # @parm Int x - Relative cursor position
+ # @parm Int y - Relative cursor position
+ # @return void
+ public method left_view_B1_Motion {x y} {
+ # If x,y overlaps widget area -> abort
+ set max_x [winfo width $left_view]
+ incr max_x -3
+ set max_y [winfo height $left_view]
+ incr max_y -3
+ if {($x < 3) || ($x > $max_x) || ($y < 3) || ($y > $max_y)} {
+ return
+ }
+
+ # If x,y is conresponding to current selection -> abort
+ set target_idx [$left_view index @$x,$y]
+ if {[llength [$left_view tag nextrange sel 0.0]]} {
+ if {
+ ([$left_view compare $cur_idx == sel.first]
+ &&
+ [$left_view compare $target_idx == sel.last])
+ ||
+ ([$left_view compare $cur_idx == sel.last]
+ &&
+ [$left_view compare $target_idx == sel.first])
+ } then {
+ return
+ }
+ }
+
+ # Adjust selection
+ $left_view tag remove sel 0.0 end
+ if {[$left_view compare $cur_idx < $target_idx]} {
+ $left_view tag add sel $cur_idx $target_idx
+ } elseif {[$left_view compare $cur_idx > $target_idx]} {
+ $left_view tag add sel $target_idx $cur_idx
+ }
+
+ # Adjust cursor
+ left_view_move_insert $x $y
+ update
+ }
+
+ ## Left view event handler: <Button-1>
+ # @parm Int x - Relative cursor position
+ # @parm Int y - Relative cursor position
+ # @return void
+ public method left_view_B1 {x y} {
+ $left_view tag remove sel 0.0 end
+ focus $left_view
+ left_view_move_insert $x $y
+ set cur_idx [$left_view index @$x,$y]
+ }
+
+ ## Set active view
+ # @parm String side - "left" or "right"
+ # @return void
+ public method set_selected_view {side} {
+ if {$selected_view == $side} {
+ return
+ }
+ set selected_view $side
+
+ # Remove cursor tags
+ foreach widget [list $left_header $left_view] {
+ $widget tag remove tag_current_full 0.0 end
+ $widget tag remove tag_current_half 0.0 end
+ }
+ if {$ascii_view} {
+ foreach widget [list $right_header $right_view] {
+ $widget tag remove tag_current_full 0.0 end
+ $widget tag remove tag_current_half 0.0 end
+ }
+ }
+
+ # Create new cursor tags
+ if {$selected_view == {left}} {
+ set index [address_to_index $cursor_address]
+ $left_view mark set insert [lindex $index 0].[lindex $index 2]
+ left_view_adjust_cursor
+
+ } elseif {$ascii_view && $selected_view == {right}} {
+ set row [expr {($cursor_address / $width) + 1}]
+ set col [expr {$cursor_address % $width}]
+
+ $right_view mark set insert $row.$col
+ right_view_adjust_cursor
+ }
+ }
+
+ ## Invoke hexeditor popup menu
+ # @parm String side - "left" or "right"
+ # @parm Int x - Relative mouse pointer position
+ # @parm Int y - Relative mouse pointer position
+ # @parm Int X - Absolute mouse pointer position
+ # @parm Int Y - Absolute mouse pointer position
+ # @return void
+ public method popup_menu {side x y X Y} {
+ # Set widget to deal with
+ if {$selected_view == {left}} {
+ set widget $left_view
+ left_view_move_insert $x $y
+ } {
+ set widget $right_view
+ }
+
+ # Fucus on that widget and determinate cursor position
+ focus $widget
+ set cur_idx [$widget index @$x,$y]
+ if {$ascii_view && $selected_view == {right}} {
+ $widget mark set insert $cur_idx
+ right_view_adjust_cursor
+ }
+
+ # Configure popup menu
+ if {[llength [$widget tag nextrange sel 0.0]]} {
+ $popup_menu entryconfigure [::mc "Copy"] -state normal
+ } {
+ $popup_menu entryconfigure [::mc "Copy"] -state disabled
+ }
+ if {[catch {
+ if {[string length [clipboard get]]} {
+ $popup_menu entryconfigure [::mc "Paste"] -state normal
+ } {
+ $popup_menu entryconfigure [::mc "Paste"] -state disabled
+ }
+ }]} {
+ $popup_menu entryconfigure [::mc "Paste"] -state disabled
+ }
+
+ # Invoke popup menu
+ tk_popup $popup_menu $X $Y
+ }
+
+ ## Left view event handler: <Key>
+ # Unprintable characters, invalid and non 8 bit characters will be ignored
+ # @parm Char key - Binary code of pressed key
+ # @return void
+ public method left_view_key {key} {
+ if {$disabled} {return}
+
+ # Check if the given value is printable character
+ if {![string is print -strict $key]} {
+ return
+ }
+
+ # Determinate current row and column
+ scan [$left_view index insert] {%d.%d} row col
+ if {($row == $height) && ($col >= $left_view_width)} {
+ return
+ }
+
+ # Validate the given value
+ switch -- $view_mode {
+ {dec} {
+ if {![string is integer -strict $key]} {
+ return
+ }
+ }
+ {hex} {
+ if {![string is xdigit -strict $key]} {
+ return
+ }
+ }
+ {oct} {
+ if {![regexp {^[0-7]+$} $key]} {
+ return
+ }
+ }
+ }
+
+ # Local variables
+ set boundaries [col_to_start_end $col] ;# Tempotary variable
+ set col_s [lindex $boundaries 0] ;# Starting column
+ set col_e [lindex $boundaries 1] ;# End column
+ set cell [lindex $boundaries 2] ;# Cell number in row
+ set org_val [$left_view get $row.$col_s $row.$col_e] ;# Original cell value
+ set org_idx [$left_view index insert] ;# Original insertion index
+
+ # Replace character at current insertion index with the new one
+ $left_view delete insert {insert+1c}
+ $left_view insert insert $key
+ $left_view mark set insert {insert-1c}
+ $left_view tag add normal_font {insert linestart} {insert lineend}
+
+ # Determinate new cell value
+ set val [$left_view get $row.$col_s $row.$col_e]
+ set val [string trim $val]
+ set val [string trimleft $val 0]
+ if {$val == {}} {
+ set val 0
+ }
+
+ # Convert new cell value to decimal integer
+ if {$view_mode == {hex}} {
+ set val [expr "0x$val"]
+ } elseif {$view_mode == {oct}} {
+ set val [expr "0$val"]
+ }
+
+ # Check for valid value range
+ if {$val > 255} {
+ $left_view delete $row.$col_s $row.$col_e
+ $left_view tag add normal_font [list $row.0 linestart] [list $row.0 lineend]
+ $left_view insert $row.$col_s $org_val
+ $left_view mark set insert $org_idx
+ left_view_adjust_cursor
+ return
+ }
+
+ # Invoke pseudo-event <cell_value_changed>
+ if {$cell_value_changed_cmd_set} {
+ eval "$cell_value_changed_cmd $cursor_address $val"
+ }
+
+ # Adjust right view
+ if {$ascii_view} {
+ set char [format %c $val]
+ set cell "$row.$cell"
+ $right_view delete $cell "$cell+1c"
+ if {($val < 127) && [string is print -strict $char]} {
+ $right_view insert $cell $char
+ $right_view tag remove tag_np $cell "$cell+1c"
+ } {
+ $right_view insert $cell {.}
+ $right_view tag add tag_np $cell "$cell+1c"
+ }
+ $right_view tag add normal_font [list $cell linestart] [list $cell lineend]
+ }
+
+ # Adjust insertion cursor
+ if {($row == $height) && ($col >= ($left_view_width - 1))} {
+ left_view_adjust_cursor
+ } {
+ left_view_movement 0 Right
+ }
+ }
+
+ ## Perform certain movement action on the right (ascii) view
+ # @parm String key - Action (one of {Left Right End})
+ # @return void
+ public method right_view_movement {key} {
+ # Remove selection and determinate current column and row
+ $right_view tag remove sel 0.0 end
+ scan [$right_view index insert] {%d.%d} row col
+
+ # Determinate correction for insertion cursor
+ switch -- $key {
+ {Left} { ;# Move left by one character
+ if {$row == 1 && $col == 0} {
+ return
+ }
+
+ incr col -1
+ if {$col < 0} {
+ set col [expr {$width - 1}]
+ incr row -1
+ }
+ }
+ {Right} { ;# Move right by one character
+ if {($row == $height) && ($col >= ($width - 1))} {
+ return
+ }
+
+ incr col
+ if {$col >= $width} {
+ set col 0
+ incr row
+ }
+ }
+ {End} { ;# Move to the end of the current line
+ if {$col >= ($width - 1)} {
+ return
+ }
+
+ set col [expr {$width - 1}]
+ }
+ default { ;# CRITICAL ERROR
+ error "Unrecognized key: $key"
+ return
+ }
+ }
+
+ # Adjust insertion cursor
+ $right_view mark set insert $row.$col
+ $right_view see insert
+
+ # Adjust cursor highlighting tags
+ right_view_adjust_cursor
+ }
+
+ ## Perform certain movement action on the left view
+ # @parm Bool select - Manipulate selection
+ # @parm String key - Action (one of {Left Right Up Down Home End Prior Next})
+ # @return void
+ public method left_view_movement {select key} {
+ # Remove selection and determinate current column and row
+ $left_view tag remove sel 0.0 end
+ scan [$left_view index insert] {%d.%d} row col
+
+ # Determinate cell boundaries
+ if {$key == {Left} || $key == {Right}} {
+ set boundaries [col_to_start_end $col]
+ set col_s [lindex $boundaries 0]
+ set col_e [lindex $boundaries 1]
+ }
+
+ # Determinate correction for insertion cursor
+ switch -- $key {
+ {Left} { ;# Move left by one character
+ if {$row == 1 && $col == 0} {
+ return
+ }
+ if {$col == $col_s} {
+ set correction {-2c}
+ } {
+ set correction {-1c}
+ }
+ }
+ {Right} { ;# Move right by one character
+ incr col_e -1
+ if {($row == $height) && ($col >= ($left_view_width - 1))} {
+ return
+ }
+ if {$col == $col_e} {
+ set correction {+2c}
+ } {
+ set correction {+1c}
+ }
+ }
+ {Up} { ;# Move up by one row
+ if {!$row} {
+ return
+ }
+ set correction {-1l}
+ }
+ {Down} { ;# Move down by one row
+ if {$row == $height} {
+ return
+ }
+ set correction {+1l}
+ }
+ {Home} { ;# Move to the beginning of the current line
+ if {!$col} {
+ return
+ }
+ set correction {linestart}
+ }
+ {End} { ;# Move to the end of the current line
+ if {$col >= ($left_view_width - 1)} {
+ return
+ }
+ set correction {lineend-1c}
+ }
+ {Prior} { ;# Move up by a few lines
+ set correction {-8l}
+ }
+ {Next} { ;# Move up by a few lines
+ set correction {+8l}
+ }
+ default { ;# CRITICAL ERROR
+ error "Unrecognized key: $key"
+ return
+ }
+ }
+
+ # Adjust insertion cursor
+ $left_view mark set insert [$left_view index "insert $correction"]
+ $left_view see insert
+
+ # Adjust selection
+ if {!$select} {
+ set cur_idx [$left_view index insert]
+ } {
+ if {[$left_view compare $cur_idx <= insert]} {
+ $left_view tag add sel $cur_idx insert
+ } {
+ $left_view tag add sel insert $cur_idx
+ }
+ }
+
+ # Adjust cursor highlighting tags
+ left_view_adjust_cursor
+ }
+
+ ## Left view event handler: <Leave>
+ # Manages pseudo-event <cell_leave>
+ # @return void
+ public method text_view_leave {} {
+ if {!$in_cell} {
+ return
+ }
+
+ set in_cell 0
+ set cell_under_cursor {0.0}
+
+ if {$cell_leave_cmd_set} {
+ eval $cell_leave_cmd
+ }
+ }
+
+ ## Right view event handler: <Motion>
+ # Manages pseuso-events <cell_motion>, <cell_enter> and <cell_leave>
+ # @parm Int x - Relative mouse pointer position
+ # @parm Int y - Relative mouse pointer position
+ # @parm Int X - Absolute mouse pointer position
+ # @parm Int Y - Absolute mouse pointer position
+ # @return void
+ public method right_view_motion {x y X Y} {
+ set index [$right_view index @$x,$y]
+ set dlineinfo [$right_view dlineinfo $index]
+ if {$y > ([lindex $dlineinfo 1] + [lindex $dlineinfo 3])} {
+ text_view_leave
+ return
+ }
+ scan $index {%d.%d} row col
+
+ # Motion
+ if {$cell_under_cursor == $index} {
+ if {$cell_motion_cmd_set} {
+ eval "$cell_motion_cmd $X $Y"
+ }
+
+ # (Leave + ) Enter
+ } else {
+ if {$in_cell} {
+ if {$cell_leave_cmd_set} {
+ eval $cell_leave_cmd
+ }
+ set in_cell 0
+ }
+ if {$cell_enter_cmd_set} {
+ set address [expr {($row - 1) * $width + $col}]
+ if {$address >= $total_capacity} {
+ set address $total_capacity
+ }
+ eval "$cell_enter_cmd $address $X $Y"
+ }
+ set in_cell 1
+ }
+
+ set cell_under_cursor $index
+ }
+
+ ## Left view event handler: <Motion>
+ # Manages pseuso-events <cell_motion>, <cell_enter> and <cell_leave>
+ # @parm Int x - Relative mouse pointer position
+ # @parm Int y - Relative mouse pointer position
+ # @parm Int X - Absolute mouse pointer position
+ # @parm Int Y - Absolute mouse pointer position
+ # @return void
+ public method left_view_motion {x y X Y} {
+ set index [$left_view index @$x,$y]
+ set dlineinfo [$left_view dlineinfo $index]
+ if {$y > ([lindex $dlineinfo 1] + [lindex $dlineinfo 3])} {
+ text_view_leave
+ return
+ }
+ scan $index {%d.%d} row col
+ if {$view_mode != {hex}} {
+ set step 4
+ } {
+ set step 3
+ }
+
+ # Enter
+ if {$cell_under_cursor != $index} {
+ if {$in_cell && $cell_leave_cmd_set} {
+ eval $cell_leave_cmd
+ }
+ if {$cell_enter_cmd_set} {
+ set address [expr {($row - 1) * $width + ($col / $step)}]
+ if {$address >= $total_capacity} {
+ set address $total_capacity
+ }
+ eval "$cell_enter_cmd $address $x $y $X $Y"
+ }
+ set in_cell 1
+
+ # Motion
+ } elseif {$cell_motion_cmd_set} {
+ eval "$cell_motion_cmd $X $Y"
+ }
+
+ set cell_under_cursor $index
+ }
+
+
+ # -------------------------------------------------------------------
+ # GENERAL PUBLIC INTERFACE
+ # -------------------------------------------------------------------
+
+ ## Get editor scroll bar object reference
+ # @return Widget - Scrolbar
+ public method get_scrollbar {} {
+ return $scrollbar
+ }
+
+ ## Get editor popup menu object reference
+ # @return Widget - Popup menu
+ public method get_popup_menu {} {
+ return $popup_menu
+ }
+
+ ## Get list of values from hexeditor
+ # @parm Int start - Start address
+ # @parm Int end - End address
+ # @return List - List of decimal values (e.g. {0 226 {} {} 126 {} 6 8})
+ public method get_values {start end} {
+ # Check for allowed address range
+ if {$DEBUG} {
+ if {$end >= $total_capacity} {
+ error "Address out of range"
+ }
+ if {$end != [expr {int($end)}]} {
+ error "Address must be integer"
+ }
+ if {$start < 0} {
+ error "Address out of range"
+ }
+ if {$start != [expr {int($start)}]} {
+ error "Address must be integer"
+ }
+ }
+
+ # Determinate text indexes of area to extract
+ set index [address_to_index $start]
+ set start_row [lindex $index 0]
+ set start_col [lindex $index 2]
+ set index [address_to_index $end]
+ set end_row [lindex $index 0]
+ set end_col [lindex $index 3]
+ incr end_col
+
+ # Determinate cell legth and cell length+space
+ if {$view_mode != {hex}} {
+ set step 4
+ set len 3
+ } {
+ set step 3
+ set len 2
+ }
+
+ # Initiate extraction
+ set result {}
+ set value {}
+ for {set row $start_row} {$row <= $end_row} {incr row} {
+ # Interate over cells withing the row
+ for {set col_s $start_col} {$col_s < $left_view_width} {incr col_s $step} {
+ # Determinate cell end index
+ set col_e $col_s
+ incr col_e $len
+ if {($row == $end_row) && ($col_s == $end_col)} {
+ break
+ }
+
+ # Determinate cell value
+ set value [$left_view get $row.$col_s $row.$col_e]
+ set value [string trim $value]
+
+ # Skip conversion for empty cells
+ if {$value == {}} {
+ lappend result {}
+ continue
+ }
+
+ # Convert cell value to decimal integer
+ set value [string trimleft $value 0]
+ if {$value == {}} {
+ set value 0
+ }
+ switch -- $view_mode {
+ {dec} {
+ lappend result $value
+ }
+ {hex} {
+ lappend result [expr "0x$value"]
+ }
+ {oct} {
+ lappend result [expr "0$value"]
+ }
+ }
+ }
+ }
+
+ if {$start == $end} {
+ return [lindex $result 0]
+ } {
+ return $result
+ }
+ }
+
+ ## Set value of the specified cell
+ # @parm Int address - Cell address
+ # @parm Int value - New cell value (must be withing interval [0;255])
+ # @return void
+ public method setValue {address value} {
+ # Local variables
+ set index [address_to_index $address] ;# Text index
+ set row [lindex $index 0] ;# Row in left view
+ set cell [lindex $index 1] ;# Column in right view / cell number in row
+ set start_col [lindex $index 2] ;# Starting column in left view
+ set end_col [lindex $index 3] ;# End column in left view
+ set index [$left_view index insert] ;# Current insertion index in left view
+
+ # Empty value means clear the cell
+ if {$value == {}} {
+ # Clear cell in the left view
+ $left_view delete $row.$start_col $row.$end_col
+ if {$view_mode != {hex}} {
+ $left_view insert $row.$start_col { }
+ } {
+ $left_view insert $row.$start_col { }
+ }
+ $left_view mark set insert $index
+ $left_view tag add normal_font [list $row.0 linestart] [list $row.0 lineend]
+
+ # Clear cell in the right view
+ if {$ascii_view} {
+ $right_view delete $row.$cell $row.$end_col
+ $right_view insert $row.$cell { }
+ $right_view tag add normal_font [list $row.0 linestart] [list $row.0 lineend]
+ }
+
+ # Restore insertion cursor tags
+ if {$cursor_address == $address} {
+ if {$selected_view == {left}} {
+ left_view_adjust_cursor
+ } {
+ right_view_adjust_cursor
+ }
+ }
+
+ # Restore cell highlight
+ restore_cell_highlight $address
+
+ # Abort the rest of procedure
+ return
+ }
+
+ # Validate input address and value
+ if {$DEBUG} {
+ if {$address >= $total_capacity} {
+ error "Address out of range"
+ }
+ if {$address != [expr {int($address)}]} {
+ error "Address must be integer"
+ }
+ if {$value > 255 || $value < 0} {
+ error "Value of of range"
+ }
+ if {$value != [expr {int($value)}]} {
+ error "Value must be integer"
+ }
+ }
+
+ # Convert the given value to appropriate string
+ set original_value $value
+ switch -- $view_mode {
+ {hex} {
+ set value [format %X $value]
+ if {[string length $value] == 1} {
+ set value "0$value"
+ }
+ }
+ {oct} {
+ set value [format %o $value]
+ set len [string length $value]
+ if {$len != 3} {
+ set value "[string repeat {0} [expr {3 - $len}]]$value"
+ }
+ }
+ {dec} {
+ set value [expr $value]
+ set len [string length $value]
+ if {$len != 3} {
+ set value "[string repeat {0} [expr {3 - $len}]]$value"
+ }
+ }
+ }
+
+ # Replace current content of the cell with new value
+ $left_view delete $row.$start_col $row.$end_col
+ $left_view insert $row.$start_col $value
+ $left_view mark set insert $index
+ $left_view tag add normal_font [list $row.0 linestart] [list $row.0 lineend]
+
+ # Adjust right view
+ if {$ascii_view} {
+ set end_col $cell
+ incr end_col
+
+ # Convert to character
+ set value [format %c $original_value]
+
+ # Insert value to the text widget
+ $right_view delete $row.$cell $row.$end_col
+ if {($original_value < 127) && [string is print -strict $value]} {
+ $right_view insert $row.$cell $value
+ $right_view tag remove tag_np $row.$cell "$row.$cell+1c"
+ } {
+ $right_view insert $row.$cell {.}
+ $right_view tag add tag_np $row.$cell $row.$end_col
+ }
+ $right_view tag add normal_font [list $row.0 linestart] [list $row.0 lineend]
+
+ # Adjust cursor postion
+ scan [$right_view index {insert}] {%d.%d} row cell
+ if {$cell == $width} {
+ set cell 0
+ incr row
+ }
+ $right_view mark set insert $row.$cell
+ }
+
+ # Restore insertion cursor tags
+ if {$cursor_address == $address} {
+ if {$selected_view == {left}} {
+ left_view_adjust_cursor
+ } {
+ right_view_adjust_cursor
+ }
+ }
+
+ # Restore cell highlight
+ restore_cell_highlight $address
+ }
+
+ ## Switch view (from left to right and on the contrary)
+ # @return void
+ public method switch_views {} {
+ if {!$ascii_view} {
+ return
+ }
+ if {$selected_view == {left}} {
+ focus $right_view
+ } {
+ focus $left_view
+ }
+ }
+
+ ## Get current view (left or right)
+ # @return String - "left" or "right"
+ public method getCurrentView {} {
+ return $selected_view
+ }
+
+ ## Focus on the left view
+ # @return void
+ public method focus_left_view {} {
+ focus -force $left_view
+ }
+
+ ## Focus on the right view
+ # @return void
+ public method focus_right_view {} {
+ if {$ascii_view} {
+ focus -force $right_view
+ }
+ }
+
+ ## Set cell background highlight (as write in progress)
+ # @parm Int address - Cell address
+ # @parm Bool bool - 1 == highlight; 0 == clear highlight
+ # @parm Int type - Type of highlight (color)
+ # @return void
+ public method set_bg_hg {address bool type} {
+ # Validate input address
+ if {$DEBUG} {
+ if {$address >= $total_capacity} {
+ error "Address out of range"
+ }
+ if {$address != [expr {int($address)}]} {
+ error "Address must be integer"
+ }
+ if {![string is boolean $bool]} {
+ error "'$bool' in not booleand value"
+ }
+ }
+
+ switch -- $type {
+ 0 {
+ set arr {bg_hg}
+ set tag {tag_bg_hg}
+ }
+ 1 {
+ set arr {bg_hg1}
+ set tag {tag_bg_hg1}
+ }
+ 2 {
+ set arr {bg_hg2}
+ set tag {tag_bg_hg2}
+ }
+ }
+ if {[subst "\$${arr}($address)"] == $bool} {
+ return
+ }
+ set ${arr}($address) $bool
+
+ # Local variables
+ set index [address_to_index $address] ;# (Auxiliary variable)
+ set row [lindex $index 0] ;# Cell row
+ set cell [lindex $index 1] ;# Cell number in the row
+ set start_col [lindex $index 2] ;# Starting column
+ set end_col [lindex $index 3] ;# End column
+
+ # Create highlight
+ if {$bool} {
+ set bool {add}
+ } {
+ set bool {remove}
+ }
+ $left_view tag $bool $tag $row.$start_col $row.$end_col
+ if {$ascii_view} {
+ $right_view tag $bool $tag $row.$cell "$row.$cell+1c"
+ }
+ }
+
+ ## Set cell highlight (as changed)
+ # @parm Int address - Cell address
+ # @parm Bool bool - 1 == highlight; 0 == clear highlight
+ # @return void
+ public method setHighlighted {address bool} {
+ # Validate input address
+ if {$DEBUG} {
+ if {$address >= $total_capacity} {
+ error "Address out of range"
+ }
+ if {$address != [expr {int($address)}]} {
+ error "Address must be integer"
+ }
+ if {![string is boolean $bool]} {
+ error "'$bool' in not booleand value"
+ }
+ }
+
+ if {$highlighted_cells($address) == $bool} {
+ return
+ }
+ set highlighted_cells($address) $bool
+
+ # Local variables
+ set index [address_to_index $address] ;# (Auxiliary variable)
+ set row [lindex $index 0] ;# Cell row
+ set cell [lindex $index 1] ;# Cell number in the row
+ set start_col [lindex $index 2] ;# Starting column
+ set end_col [lindex $index 3] ;# End column
+
+ # Create highlight
+ if {$bool} {
+ set bool {add}
+ } {
+ set bool {remove}
+ }
+ $left_view tag $bool tag_hg $row.$start_col $row.$end_col
+ if {$ascii_view} {
+ $right_view tag $bool tag_hg $row.$cell "$row.$cell+1c"
+ }
+ }
+
+ ## Remove all foreground highlighting tags
+ # @return void
+ public method clearHighlighting {} {
+ for {set i 0} {$i < $total_capacity} {incr i} {
+ set highlighted_cells($i) 0
+ }
+ $left_view tag remove tag_hg 0.0 end
+ if {$ascii_view} {
+ $right_view tag remove tag_hg 0.0 end
+ }
+ }
+
+ ## Remove all background highlighting tags
+ # @parm Int type - Type of highlight (color)
+ # @return void
+ public method clearBgHighlighting {type} {
+ switch -- $type {
+ 0 {
+ set arr {bg_hg}
+ set tag {tag_bg_hg}
+ }
+ 1 {
+ set arr {bg_hg1}
+ set tag {tag_bg_hg1}
+ }
+ 2 {
+ set arr {bg_hg2}
+ set tag {tag_bg_hg2}
+ }
+ }
+ for {set i 0} {$i < $total_capacity} {incr i} {
+ set ${arr}($i) 0
+ }
+ $left_view tag remove $tag 0.0 end
+ if {$ascii_view} {
+ $right_view tag remove $tag 0.0 end
+ }
+ }
+
+ ## Get address of current cell
+ # @return Int - Address
+ public method getCurrentCell {} {
+ return $cursor_address
+ }
+
+ ## Set current cell
+ # @parm Int address - Cell address
+ # @return void
+ public method setCurrentCell {address} {
+ # Check for allowed range
+ if {$address >= $total_capacity} {
+ return
+ }
+
+ # Local variables
+ set index [address_to_index $address] ;# (Auxiliary variable)
+ set row [lindex $index 0] ;# Cell row
+ set cell [lindex $index 1] ;# Cell number in the row
+ set start_col [lindex $index 2] ;# Cell starting column
+
+ # Adjust cursor
+ set cursor_address $address
+ if {$selected_view == {left}} {
+ $left_view mark set insert $row.$start_col
+ $left_view see insert
+ left_view_adjust_cursor
+ } {
+ $right_view mark set insert $row.$cell
+ $right_view see insert
+ right_view_adjust_cursor
+ }
+ }
+
+ ## Scroll to certain cell
+ # @parm Int address - Cell address
+ # @return void
+ public method seeCell {address} {
+ # Check for allowed range
+ if {$address >= $total_capacity} {
+ return
+ }
+
+ # Local variables
+ set index [address_to_index $address] ;# (Auxiliary variable)
+ set row [lindex $index 0] ;# Cell row
+ set cell [lindex $index 1] ;# Cell number in the row
+ set start_col [lindex $index 2] ;# Cell starting column
+
+ # Adjust cursor
+ if {$selected_view == {left}} {
+ $left_view see $row.$start_col
+ } {
+ $right_view see $row.$cell
+ }
+ }
+
+ ## Bind command to pseudo-event <current_cell_changed>
+ # @parm String cmd - command to invoke from root namespace
+ # Command invocation: eval "$cmd $cursor_address"
+ # @return void
+ public method bindCurrentCellChanged {cmd} {
+ set current_cell_changed_cmd_set 1
+ set current_cell_changed_cmd $cmd
+ }
+
+ ## Bind command to pseudo-event <cell_value_changed>
+ # @parm String cmd - command to invoke from root namespace
+ # Command invocation: eval "$cmd $cursor_address $new_value"
+ # @return void
+ public method bindCellValueChanged {cmd} {
+ set cell_value_changed_cmd_set 1
+ set cell_value_changed_cmd $cmd
+ }
+
+ ## Bind command to pseudo-event <cell_enter>
+ # @parm String cmd - command to invoke from root namespace
+ # Command invocation: eval "$cmd $cursor_address $X $Y"
+ # @return void
+ public method bindCellEnter {cmd} {
+ set cell_enter_cmd_set 1
+ set cell_enter_cmd $cmd
+ bind_mouse_motions
+ }
+
+ ## Bind command to pseudo-event <cell_leave>
+ # @parm String cmd - command to invoke from root namespace
+ # Command invocation: eval "$cmd"
+ # @return void
+ public method bindCellLeave {cmd} {
+ set cell_leave_cmd_set 1
+ set cell_leave_cmd $cmd
+ bind_mouse_motions
+ }
+
+ ## Bind command to pseudo-event <cell_motion>
+ # @parm String cmd - command to invoke from root namespace
+ # Command invocation: eval "$cmd $X $Y"
+ # @return void
+ public method bindCellMotion {cmd} {
+ set cell_motion_cmd_set 1
+ set cell_motion_cmd $cmd
+ bind_mouse_motions
+ }
+
+ ## Bind command to pseudo-event <scroll_action>
+ # @parm String cmd - command to invoke from root namespace
+ # Command invocation: eval "$cmd"
+ # @return void
+ public method bindScrollAction {cmd} {
+ set scroll_action_cmd_set 1
+ set scroll_action_cmd $cmd
+ }
+
+ ## Bind command to pseudo-event <selection_action>
+ # @parm String cmd - command to invoke from root namespace
+ # Command invocation: eval "$cmd bool__something_selected_or_not"
+ # @return void
+ public method bindSelectionAction {cmd} {
+ set selection_action_cmd_set 1
+ set selection_action_cmd $cmd
+ }
+
+ ##
+ # @return
+ public method getRangeOfSelection {} {
+ if {[llength [$left_view tag nextrange sel 0.0]]} {
+ return [list \
+ [index_to_address {left} [$left_view index sel.first+1c]] \
+ [index_to_address {left} [$left_view index sel.last-1c]] \
+ ]
+ } {
+ return {}
+ }
+ }
+
+ ## Get number of topmost visible row in both views
+ # @return Int - Row number (1st row has number 1)
+ public method getTopRow {} {
+ return $top_row
+ }
+
+ ## Switch view mode (HEX, DEC etc.)
+ # @parm String newmode - New mode for left view (one of {hex oct dec})
+ # @return void
+ public method switch_mode {newmode} {
+ if {$newmode == $view_mode} {
+ return
+ }
+ set original_mode $view_mode
+ set view_mode $newmode
+ switch -- $view_mode {
+ {hex} {
+ set new_value_length 2
+ set left_view_width [expr {$width * 3 - 1}]
+ }
+ {oct} {
+ set new_value_length 3
+ set left_view_width [expr {$width * 4 - 1}]
+ }
+ {dec} {
+ set new_value_length 3
+ set left_view_width [expr {$width * 4 - 1}]
+ }
+ default {
+ error "Invalid mode: $view_mode"
+ }
+ }
+ switch -- $original_mode {
+ {hex} {
+ set value_length 2
+ set skip 3
+ }
+ {oct} {
+ set value_length 3
+ set skip 4
+ }
+ {dec} {
+ set value_length 3
+ set skip 4
+ }
+ }
+
+ $left_view configure -cursor watch
+ $left_header configure -cursor watch
+ $left_address_bar configure -cursor watch
+ if {$ascii_view} {
+ $right_header configure -cursor watch
+ $right_view configure -cursor watch
+ }
+ update
+ $left_view configure -width $left_view_width
+ $left_header configure -width $left_view_width
+
+ # Iterate over rows in left view
+ for {set row 1} {$row <= $height} {incr row} {
+ set start 0
+ set end $value_length
+ set values {}
+ set lineend [$left_view index [list $row.0 lineend]]
+
+ # Save line to list
+ for {set cell 0} {$cell < $width} {incr cell} {
+ lappend values [string trim [$left_view get $row.$start $row.$end]]
+ incr start $skip
+ incr end $skip
+ }
+ $left_view delete $row.0 $lineend
+
+ # Convert list
+ set first 1
+ set space [string repeat { } $new_value_length]
+ foreach val $values {
+ if {!$first} {
+ $left_view insert $lineend { }
+ } {
+ set first 0
+ }
+ if {$val == {}} {
+ $left_view insert $lineend $space
+ continue
+ } {
+ set val [string trimleft $val 0]
+ if {$val == {}} {
+ set val 0
+ }
+ switch -- $original_mode {
+ {hex} {
+ # HEX -> DEC
+ if {$view_mode == {dec}} {
+ set val [expr "0x$val"]
+
+ # HEX -> OCT
+ } {
+ set val [expr "0x$val"]
+ set val [format {%o} $val]
+ }
+ }
+ {dec} {
+ # DEC -> HEX
+ if {$view_mode == {hex}} {
+ set val [format %X $val]
+
+ # DEC -> OCT
+ } {
+ set val [format %o $val]
+ }
+ }
+ {oct} {
+ # OCT -> HEX
+ if {$view_mode == {hex}} {
+ set val [expr "0$val"]
+ set val [format %X $val]
+
+ # OCT -> DEC
+ } {
+ set val [expr "0$val"]
+ }
+ }
+ }
+ }
+
+ set len [string length $val]
+ if {$len < $new_value_length} {
+ set len [expr {$new_value_length - $len}]
+ set val "[string repeat 0 $len]$val"
+ }
+
+ $left_view insert $lineend $val
+ $left_view tag add normal_font [list $lineend linestart] [list $lineend lineend]
+ }
+ }
+
+ fill_left_header
+ for {set i 0} {$i < $total_capacity} {incr i} {
+ if {$highlighted_cells($i)} {
+ set highlighted_cells($i) 0
+ setHighlighted $i 1
+ }
+ if {$bg_hg($i)} {
+ set bg_hg($i) 0
+ set_bg_hg $i 1
+ }
+ }
+ $left_view configure -cursor xterm
+ $left_header configure -cursor left_ptr
+ $left_address_bar configure -cursor left_ptr
+ if {$ascii_view} {
+ $right_header configure -cursor left_ptr
+ $right_view configure -cursor xterm
+ }
+ }
+
+ ## Set hexeditor enabled/disabled state
+ # @parm Bool bool - 1 == enabled; 0 == disabled
+ # @return void
+ public method setDisabled {bool} {
+ set disabled $bool
+
+ # Set state for left view
+ if {$bool} {
+ $left_view configure -state disabled
+ $left_view configure -bg {#F8F8F8} -fg {#999999} ;#DDDDDD
+ } {
+ $left_view configure -state normal
+ $left_view configure -bg {#FFFFFF} -fg {#000000}
+ }
+
+ # Set state for right view
+ if {$ascii_view} {
+ if {$bool} {
+ $right_view configure -state disabled
+ $right_view configure -bg {#F8F8F8} -fg {#999999} ;#DDDDDD
+ } {
+ $right_view configure -state normal
+ $right_view configure -bg {#FFFFFF} -fg {#000000}
+ }
+ }
+ }
+
+ ## Get reference of left view text widget
+ # @return Widget - Text widget
+ public method getLeftView {} {
+ return $left_view
+ }
+
+ ## Get reference of right view text widget
+ # @return Widget - Text widget or {}
+ public method getRightView {} {
+ return $right_view
+ }
+
+ ## Get configuration list
+ # @return List - Configuration list
+ proc get_config {} {
+ return [list $text_to_find $find_opt(fc) $find_opt(bw)]
+ }
+
+ ## Load configuration list generated by function `get_config'
+ # @param List config - Configuration list generated by `get_config'
+ # @return void
+ proc load_config_list {config_list} {
+ # Load configuration
+ set text_to_find [lindex $config_list 0]
+ set find_opt(fc) [lindex $config_list 1]
+ set find_opt(bw) [lindex $config_list 2]
+
+ # Validate loaded configuration
+ if {![string is boolean -strict $find_opt(fc)]} {
+ set find_opt(fc) 1
+ }
+ if {![string is boolean -strict $find_opt(bw)]} {
+ set find_opt(bw) 0
+ }
+ }
+
+ ## Find next occurence of search string
+ # @return Bool - 0 == Invalid call; 1 == Valid call
+ public method find_next {} {
+ if {$last_find_index == {}} {
+ return 0
+ }
+ if {$find_opt(bw)} {
+ set result [find_FIND $last_find_index-[string length $text_to_find]c]
+ } {
+ set result [find_FIND $last_find_index]
+ }
+ return $result
+ }
+
+ ## Find previous occurence of search string
+ # @return Bool - 0 == Invalid call; 1 == Valid call
+ public method find_prev {} {
+ if {$last_find_index == {}} {
+ return 0
+ }
+
+ set backward_org $find_opt(bw)
+ set find_opt(bw) [expr {!$find_opt(bw)}]
+
+ if {$find_opt(bw)} {
+ set result [find_FIND $last_find_index-[string length $text_to_find]c]
+ } {
+ set result [find_FIND $last_find_index]
+ }
+
+ set find_opt(bw) $backward_org
+ return $result
+ }
+
+ ## Invoke dialog: Find string
+ # @return Bool - 1 == string found; 0 == string not found
+ public method find_dialog {} {
+ # Create toplevel find_dialog_window
+ if {[winfo exists $find_dialog_win]} {
+ destroy $find_dialog_win
+ }
+ incr find_dialog_count
+ set find_dialog_win [toplevel .hex_editor_find_dialog_$find_dialog_count]
+
+ ## Create top frame
+ set top_frame [frame $find_dialog_win.top_frame]
+ # Text to find
+ grid [label $top_frame.string_lbl \
+ -text [mc "Text to find"] \
+ ] -row 0 -column 0 -columnspan 4 -sticky w
+ grid [ttk::entry $top_frame.string_entry \
+ -textvariable ::HexEditor::text_to_find \
+ -width 0 \
+ ] -row 1 -column 1 -sticky we -columnspan 3
+ # Where
+ grid [label $top_frame.where_lbl \
+ -text [mc "Where"] \
+ ] -row 2 -column 0 -columnspan 2 -sticky w
+ grid [radiobutton $top_frame.radio_0 \
+ -variable ::HexEditor::where_to_search \
+ -text [mc "Left view"] -value left \
+ ] -row 3 -column 1 -sticky w
+ grid [radiobutton $top_frame.radio_1 \
+ -variable ::HexEditor::where_to_search \
+ -text [mc "Right view"] -value right \
+ ] -row 4 -column 1 -sticky w
+ set ::HexEditor::where $selected_view
+ if {!$ascii_view} {
+ $top_frame.radio_1 configure -state disabled
+ }
+ # Options
+ grid [label $top_frame.options_lbl \
+ -text [mc "Options"] \
+ ] -row 2 -column 2 -columnspan 2 -sticky w
+ grid [checkbutton $top_frame.opt_fc_chb \
+ -variable ::HexEditor::find_opt(fc) \
+ -onvalue 1 -offvalue 0 \
+ -text [mc "From cursor"] \
+ ] -row 3 -column 3 -sticky w
+ grid [checkbutton $top_frame.opt_bw_chb \
+ -variable ::HexEditor::find_opt(bw) \
+ -onvalue 1 -offvalue 0 \
+ -text [mc "Backwards"] \
+ ] -row 4 -column 3 -sticky w
+
+ # Finalize top frame creation
+ grid columnconfigure $top_frame 0 -minsize 25
+ grid columnconfigure $top_frame 1 -weight 1
+ grid columnconfigure $top_frame 2 -minsize 25
+ grid columnconfigure $top_frame 3 -weight 1
+
+ # Create and pack 'OK' and 'CANCEL' buttons
+ set buttonFrame [frame $find_dialog_win.button_frame]
+ pack [ttk::button $buttonFrame.ok \
+ -text [mc "Ok"] \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -command "$this find_FIND" \
+ ] -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -text [mc "Cancel"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "$this find_CANCEL" \
+ ] -side left
+
+ # Events binding (Enter == Find; Escape == Cancel)
+ bind $find_dialog_win <KeyRelease-Return> "$this find_FIND; break"
+ bind $find_dialog_win <KeyRelease-KP_Enter> "$this find_FIND; break"
+ bind $find_dialog_win <KeyRelease-Escape> "$this find_CANCEL; break"
+
+ # Pack dialog frames
+ pack $top_frame -fill both -anchor nw -padx 5 -pady 5
+ pack $buttonFrame -side bottom -anchor e -padx 5
+
+ # Window manager options -- modal find_dialog_window
+ wm iconphoto $find_dialog_win ::ICONS::16::find
+ wm title $find_dialog_win [mc "Find"]
+ wm minsize $find_dialog_win 260 140
+ wm transient $find_dialog_win $main_frame
+ wm protocol $find_dialog_win WM_DELETE_WINDOW "
+ grab release $find_dialog_win
+ destroy $find_dialog_win
+ "
+ update
+ grab $find_dialog_win
+ $top_frame.string_entry selection range 0 end
+ focus -force $top_frame.string_entry
+
+ tkwait window $find_dialog_win
+ if {$last_find_index == {}} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ # -------------------------------------------------------------------
+ # HELPER PROCEDURES
+ # -------------------------------------------------------------------
+
+ ## Initiate serach
+ # @return void
+ public method find_FIND args {
+ # Determinate search options
+ set start_index [lindex $args 0]
+ if {$where_to_search == {left}} {
+ set widget $left_view
+ } {
+ set widget $right_view
+ }
+ if {$find_opt(bw)} {
+ set direction {-backwards}
+ } {
+ set direction {-forwards}
+ }
+ if {$start_index == {}} {
+ if {$find_opt(fc)} {
+ set start_index [$widget index insert]
+ } {
+ set start_index 1.0
+ }
+ }
+
+ # Perform search
+ set last_find_index [$widget search $direction -nocase -- $text_to_find $start_index]
+
+ # String found
+ if {$last_find_index != {}} {
+ $popup_menu entryconfigure [::mc "Find next"] -state normal
+ $popup_menu entryconfigure [::mc "Find previous"] -state normal
+ catch {
+ $widget tag remove sel 0.0 end
+ }
+ set end_idx $last_find_index+[string length $text_to_find]c
+ $widget tag add sel $last_find_index $end_idx
+ $widget mark set insert $end_idx
+ $widget see $end_idx
+ set last_find_index $end_idx
+ set result 1
+
+ # String not found
+ } {
+ $popup_menu entryconfigure [::mc "Find next"] -state disabled
+ $popup_menu entryconfigure [::mc "Find previous"] -state disabled
+
+ if {[winfo exists $find_dialog_win]} {
+ set parent $find_dialog_win
+ } {
+ set $main_frame
+ }
+ tk_messageBox \
+ -parent $parent \
+ -type ok \
+ -icon warning \
+ -title [mc "String not found"] \
+ -message [mc "Search string '%s' not found !" $text_to_find]
+ set result 0
+ }
+
+ # Close find dialog
+ if {[winfo exists $find_dialog_win]} {
+ find_CANCEL
+ }
+
+ return $result
+ }
+
+ ## Close find dialog
+ # @return void
+ public method find_CANCEL {} {
+ grab release $find_dialog_win
+ destroy $find_dialog_win
+ }
+}
+
+## Initialize NS variables
+ # Find options
+array set ::HexEditor::find_opt {
+ fc 1
+ bw 0
+}
diff --git a/lib/lib/ihextools.tcl b/lib/lib/ihextools.tcl
new file mode 100755
index 0000000..071b178
--- /dev/null
+++ b/lib/lib/ihextools.tcl
@@ -0,0 +1,523 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides some tools for manipulating IHEX8, binary and sim files.
+# It's intented for converting between these file types and for
+# normalizing hex files.
+# --------------------------------------------------------------------------
+
+namespace eval IHexTools {
+
+ ## PUBLIC
+ variable update 0 ;# Bool: Periodicaly update GUI and increment progress
+ variable abort 0 ;# Bool: Abort currently running procedure
+ variable progress 1 ;# Int: Variable for progress bars
+ variable error_count 0 ;# Int: Count of errors
+ variable error_string {} ;# Error messages
+ variable highest_addr 0 ;# Int: Highest address in loaded IHEX file
+
+ ## PRIVATE
+ variable content ;# Array: Currently loaded data (content(0..65535) => 00..FF)
+ variable INITIALIZED 0 ;# Bool: Namespace variables initialized
+ variable data_field ;# Auxiliary variable for creating IHEX records
+ variable data_field_len ;# Auxiliary variable for creating IHEX records
+
+
+ # ----------------------------------------------------------------
+ # GENERAL PURPOSE PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Compute checksum for the given HEX field (without leading colon)
+ # @parm String hex_data - HEX field without leading colon
+ # @return String - resulting hexadecimal checksum
+ proc getCheckSum {hex_data} {
+
+ set sum 256 ;# Initial checksum
+ set hex_data [split $hex_data {}]
+
+ # Iterate over hex data
+ for {set i 0} {1} {incr i} {
+
+ # Gain 1st hex digit
+ set val [lindex $hex_data $i]
+
+ # If the 1st digit is empty -> return result
+ if {$val == {}} {
+ # Handle overflow
+ if {$sum == 256} {return {00}}
+ # Convert decimal checksum to hexadecimal
+ set sum [format "%X" $sum]
+ if {[string length $sum] == 1} {
+ set sum "0$sum"
+ }
+ return $sum
+ }
+
+ # Gain 2nd hex digit
+ incr i
+ append val [lindex $hex_data $i]
+ set val [expr "0x$val"]
+
+ # Decrement checksum
+ incr sum -$val
+
+ # Handle undeflow
+ if {$sum < 0} {incr sum 256}
+ }
+ }
+
+ ## Get maximum value for progressbar when loading hex or sim file
+ # @parm String data - input sim or hex data
+ # @return Int - number of iterations divided by 25
+ proc get_number_of_iterations {data} {
+ # Any EOL to LF
+ regsub -all {\r\n?} $data "\n" data
+
+ # Local variables
+ set result 0 ;# Resulting number
+ set index 0 ;# Last search result
+
+ # Get number of LF chracters
+ while 1 {
+ set index [string first "\n" $data $index]
+ if {$index == -1} {break}
+ incr index
+ }
+
+ # Return result
+ return [expr {$result / 25 + 1}]
+ }
+
+ ## Load IHEX 8 file into internal memory
+ # @parm String hex_data - Content of IHEX8 file to load
+ # @return Bool - result
+ proc load_hex_data {hex_data} {
+ variable INITIALIZED ;# Bool: Namespace variables initialized
+
+ variable content ;# Array: Currently loaded data
+ variable update ;# Bool: Periodicaly update GUI and increment progress
+ variable abort 0 ;# Bool: Abort currently running procedure
+ variable progress 1 ;# Int: Variable for progress bars
+ variable error_count 0 ;# Int: Count of errors
+ variable error_string {} ;# Error messages
+ variable highest_addr 0 ;# Int: Highest address in loaded IHEX file
+
+ # Initialize array of loaded data
+ if {!$INITIALIZED} {
+ free_resources
+ }
+ # Convert any EOL to LF
+ regsub -all {\r\n?} $hex_data "\n" hex_data
+
+ # Local variables
+ set lineNum 0 ;# Number of the current line
+ set eof 0 ;# Bool: EOF detected
+
+ # Iterate over HEX records
+ foreach line [split $hex_data "\n"] {
+ incr lineNum ;# Increment line number
+
+ # Skip comments
+ if {[string index $line 0] != {:}} {continue}
+
+ # Check for valid charters
+ if {![regexp {^:[0-9A-Fa-f]+$} $line]} {
+ Error $lineNum [mc "Line contains invalid characters"]
+ continue
+ }
+ # Check for odd lenght
+ set len [string length $line]
+ if {[expr {$len % 2}] != 1} {
+ Error $lineNum [mc "Line contains even number of characters"]
+ continue
+ }
+
+ # Analize HEX record
+ set len [ string range $line 1 2 ] ;# Lenght field
+ set addr [ string range $line 3 6 ] ;# Address field
+ set type [ string range $line 7 8 ] ;# Type field
+ set data [ string range $line 9 {end-2} ] ;# Data field
+ set check [ string range $line {end-1} end ] ;# Checksum field
+ set line [ string range $line 1 {end-2} ] ;# Record without ':' and checksum
+
+ # Handle record type (01 == EOF; 00 == normal record)
+ if {$type == {01}} {
+ set eof 1
+ break
+ } elseif {$type != {00}} {
+ Error $lineNum [mc "Unknown record type '%s'" $type]
+ continue
+ }
+
+ # Check for valid checksum
+ set new_check [getCheckSum $line]
+ if {$new_check != $check} {
+ Error $lineNum [mc "Bad checksum"]
+ continue
+ }
+
+ # Check for correct value of the length field
+ set len [expr "0x$len"]
+ if {([string length $data] / 2) != $len} {
+ Error $lineNum [mc "Bad length"]
+ continue
+ }
+
+ # Parse and load data field
+ set addr [expr "0x$addr"]
+ for {set i 0; set j 1} {$i < ($len * 2)} {incr i 2; incr j 2} {
+ set content($addr) [string range $data $i $j]
+ incr addr
+ }
+
+ # Store highest address
+ if {$addr > $highest_addr} {
+ set highest_addr $addr
+ }
+
+ # Update GUI and progress variable
+ if {$update} {
+ if {![expr {$lineNum % 25}]} {
+ # Conditional abort
+ if {$abort} {return 0}
+ # Update progress variable and GUI
+ incr progress
+ update
+ }
+ }
+ }
+
+ # If there is no EOF then report that as an error
+ if {!$eof} {
+ Error - [mc "Missing EOF"]
+ }
+
+ # Return result
+ if {$error_count} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Load binary file into internal memory
+ # @parm String data - Binary data to load
+ # @return Bool - result
+ proc load_bin_data {data} {
+ variable INITIALIZED ;# Bool: Namespace variables initialized
+
+ variable content ;# Array: Currently loaded data
+ variable update ;# Bool: Periodicaly update GUI and increment progress
+ variable abort 0 ;# Bool: Abort currently running procedure
+ variable progress 1 ;# Int: Variable for progress bars
+ variable error_count 0 ;# Int: Count of errors
+ variable error_string {} ;# Error messages
+
+ # Initialize array of loaded data
+ if {!$INITIALIZED} {
+ free_resources
+ }
+
+ # Check for allowed data length
+ set len [string length $data]
+ if {$len > 0x10000} {
+ Error - [mc "Data length exceeding limit 0x10000"]
+ return 0
+ }
+
+ # Load data
+ set val 0
+ for {set i 0} {$i < $len} {incr i} {
+ binary scan [string index $data $i] c val ;# bin -> dec
+ set content($i) [string range [format %X $val] end-1 end] ;# dec -> hex
+ }
+ return 1
+ }
+
+ ## Load simulator file into internal memory
+ # @parm String data - Content of simulator file to load
+ # @return Bool - result
+ proc load_sim_data {data} {
+ variable INITIALIZED ;# Bool: Namespace variables initialized
+
+ variable content ;# Array: Currently loaded data
+ variable update ;# Bool: Periodicaly update GUI and increment progress
+ variable abort 0 ;# Bool: Abort currently running procedure
+ variable progress 1 ;# Int: Variable for progress bars
+ variable error_count 0 ;# Int: Count of errors
+ variable error_string {} ;# Error messages
+
+ # Initialize array of loaded data
+ if {!$INITIALIZED} {
+ free_resources
+ }
+
+ # Adjust input data
+ regsub -all {\r\n?} $data "\n" data ;# Any EOL to LF
+ regsub -all -line {\s*#.*$} $data {} data ;# Remove comments
+ regsub {^[^\n]+\n} $data {} data ;# Discard the first line
+
+ set lineNum 0 ;# Line number
+
+ # Iterate over lines in the given data
+ foreach line [split $data "\n"] {
+ incr lineNum ;# Increment line number
+
+ # Skip empty lines
+ if {$line == {}} {continue}
+
+ # Anylize line
+ set ln [lindex $line 0] ;# Line number
+ set addr [lindex $line 1] ;# Address
+ set line [lreplace $line 0 1] ;# Processor codes
+
+ # Check for validity of line number
+ if {![string is digit -strict $ln]} {
+ Error $lineNum [mc "Invalid line number '%s'" $ln]
+ continue
+ }
+ # Check for validity of address
+ if {![string is digit -strict $addr]} {
+ Error $lineNum [mc "Invalid address '%s'" $addr]
+ continue
+ }
+ # Check for allowed characters
+ if {![regexp {^[\d \t]+$} $line] || ![llength $line]} {
+ Error $lineNum [mc "Invalid data field"]
+ continue
+ }
+
+ # Load processor codes
+ foreach val $line {
+ set content($addr) [format %X $val]
+ incr addr
+ }
+
+ # Update GUI and progress variable
+ if {$update} {
+ if {![expr {$lineNum % 25}]} {
+ # Conditional abort
+ if {$abort} {return 0}
+ # Update progress variable and GUI
+ incr progress
+ update
+ }
+ }
+ }
+
+ # Return result
+ if {$error_count} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Get loaded data as binary string
+ # @return String - Resulting binary data
+ proc get_bin_data {} {
+ variable content ;# Array: Currently loaded data
+ variable update ;# Bool: Periodicaly update GUI and increment progress
+ variable abort 0 ;# Bool: Abort currently running procedure
+ variable progress 1 ;# Int: Variable for progress bars
+
+ # Local variables
+ set addr 0 ;# Current address
+ set pad {} ;# Padding
+ set result {} ;# Resulting binary string
+
+ # Load data and convert them (16 x 4096 interations)
+ for {set j 0} {$j < 16} {incr j} {
+ for {set i 0} {$i < 4096} {incr i} {
+ # Get hexadecimal value
+ set hex $content($addr)
+ # Convert it to binary value
+ if {$hex == {}} {
+ append pad "\0"
+ } {
+ if {$pad != {}} {
+ append result $pad
+ set pad {}
+ }
+ append result [subst "\\x$hex"]
+ }
+ # Increment address
+ incr addr
+ }
+
+ # Update GUI and progress variable
+ if {$update} {
+ # Update progress variable and GUI
+ incr progress
+ update
+ # Conditional abort
+ if {$abort} {
+ return {}
+ }
+ }
+ }
+
+ # Return resulting binary string
+ return $result
+ }
+
+ ## Get loaded data as IHEX8
+ # @return String - Resulting IHEX8
+ proc get_hex_data {} {
+ variable content ;# Array: Currently loaded data
+ variable update ;# Bool: Periodicaly update GUI and increment progress
+ variable abort 0 ;# Bool: Abort currently running procedure
+ variable progress 1 ;# Int: Variable for progress bars
+ variable data_field ;# Auxiliary variable for creating IHEX records
+ variable data_field_len ;# Auxiliary variable for creating IHEX records
+
+ # Local variables
+ set pointer 0 ;# Current address
+ set data_field_len 0 ;# IHEX8 Data field lenght
+ set data_field {} ;# IHEX8 Data field
+ set result {} ;# Resulting IHEX8
+
+ # Load data (16 x 4096 interations)
+ for {set j 0} {$j < 16} {incr j} {
+ for {set i 0} {$i < 4096} {incr i} {
+ # Determinate HEX value
+ set hex $content($pointer)
+
+ # If HEX value if empty -> write record
+ if {$hex == {} && $data_field_len} {
+ create_hex_record [expr {$pointer - $data_field_len}]
+ append result $data_field
+ set data_field {}
+
+ # Append HEX value to the current data field
+ } elseif {$hex != {}} {
+ if {[string length $hex] == 1} {
+ set hex "0$hex"
+ }
+
+ append data_field $hex
+ incr data_field_len
+ }
+
+ # Increment current address
+ incr pointer
+
+ # If data field length is high -> write record
+ if {$data_field_len == ${::Compiler::Settings::max_ihex_rec_length}} {
+ create_hex_record [expr {$pointer - $data_field_len}]
+ append result $data_field
+ set data_field {}
+ }
+ }
+
+ # Update GUI and progress variable
+ if {$update} {
+ # Update progress variable and GUI
+ incr progress
+ update
+ # Conditional abort
+ if {$abort} {
+ return {}
+ }
+ }
+ }
+
+ # Append EOF and return result
+ append result {:00000001FF}
+ return $result
+ }
+
+ ## Free used resources
+ # @return void
+ proc free_resources {} {
+ variable content ;# Array: Currently loaded data
+ variable error_string {} ;# Error messages
+ variable data_field 0 ;# Auxiliary variable for creating IHEX records
+
+ # Reset array of loaded data
+ for {set i 0} {$i < 0x10000} {incr i} {
+ set content($i) {}
+ }
+ }
+
+ ## Get value of particular cell in the loaded array
+ # @parm Int addr - Must be 0..65535
+ # @return Int - -1 == Not defined; 0..255 loaded value
+ proc get_value {addr} {
+ variable content ;# Array: Currently loaded data
+
+ if {$addr < 0 || $addr > 0xFFFF} {
+ return -1
+ }
+ set result $content($addr)
+ if {$result == {}} {
+ return -1
+ } {
+ return $result
+ }
+ }
+
+
+
+ # ----------------------------------------------------------------
+ # INTERNAL AUXILIARY PROCEDURES
+ # ----------------------------------------------------------------
+
+ ## Create IHEX8 record (result -> data_field)
+ # @parm String addr - Content of address firld (decimal number)
+ # @return void
+ proc create_hex_record {addr} {
+ variable data_field ;# Auxiliary variable for creating IHEX records
+ variable data_field_len ;# Auxiliary variable for creating IHEX records
+
+ # Adjust address
+ set addr [format %X $addr]
+ set len [string length $addr]
+ if {$len != 4} {
+ set addr "[string repeat 0 [expr {4 - $len}]]$addr"
+ }
+ # Adjust lenght
+ set len [format %X $data_field_len]
+ if {[string length $len] == 1} {
+ set len "0$len"
+ }
+
+ # Create HEX field
+ set data_field ":${len}${addr}00${data_field}[getCheckSum ${len}${addr}00${data_field}]\n"
+ set data_field_len 0
+ }
+
+ ## Append error message to error_string
+ # @parm Int line - Number of line where the error occured
+ # @parm String - Error message
+ # @return void
+ proc Error {line string} {
+ variable error_count ;# Int: Count of errors
+ variable error_string ;# Error messages
+
+ incr error_count
+ append error_string [mc "Error at line %s:\t" $line] $string "\n"
+ }
+}
diff --git a/lib/lib/innerwindow.tcl b/lib/lib/innerwindow.tcl
new file mode 100755
index 0000000..f1d2505
--- /dev/null
+++ b/lib/lib/innerwindow.tcl
@@ -0,0 +1,360 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements tool for creating application inner windows. That means windows
+# which are enclosed in the main window. And which are not managed by window
+# manager but by their own implementation. These windows are inside the main
+# window and cannot be dragged outside.
+#
+# REQUIREMENTS:
+# Librararies: "Incr TCL", "BWidget", "Tk"
+# This class also requires this: "namespace import ::itcl::*"
+# --------------------------------------------------------------------------
+
+class InnerWindow {
+ ## COMMON
+ common active_titclr {#AAAAFF} ;# Color: Active background color
+ common inactive_titclr {#DDDDDD} ;# Color: Inactive background color
+ common title_bar_height 10 ;# Int: Height of the titlebar in pixels
+
+ # List: Title bar popup menu
+ common MENU {
+ {command "Shade/Unshade" "" 0 {collapse_expand}
+ {}}
+ {command "Close" "" 0 {close_window}
+ {}}
+ }
+
+ ## PRIVATE
+ private variable win_height
+ private variable max_X ;# Int: Auxiliary variable for storing max. allowed position
+ private variable max_Y ;# Int: Auxiliary variable for storing max. allowed position
+ private variable click_X ;# Int: Auxiliary variable for storing last position
+ private variable click_Y ;# Int: Auxiliary variable for storing last position
+
+ private variable close_cmd
+ private variable title_bar ;# Widget: Window title bar
+ private variable title_label ;# Widget: Label containg text "Scribble notepad"
+ private variable close_button ;# Widget: Close button
+ private variable coll_exp_but ;# Widget: Shade button
+ private variable win
+ private variable main_frame ;# Widget: Main window frame
+ private variable minim_flag 0 ;# Bool: Shaded or not
+ private variable allow_raise_win 1 ;# Bool: Allows to use command
+
+ private variable menu ;# Widget: Title bar popup menu
+ private variable menu_created 0 ;# Bool: Title bar popup menu created
+
+ private variable close_window_in_progress 0 ;# Bool: Close procedure is in progress
+
+ ## Object constructor
+ # @parm Widget path - Window path (e.g. ".window_agent_007")
+ # @parm List geometry - {W H X Y} (Coordinates are raltive to the transient window)
+ # @parm String title - Window title
+ # @parm Image icon - Window icon, {} means no icon
+ # @parm String _close_cmd - Command to execute on close in the root namespace (stack frame #0)
+ constructor {path geometry title icon _close_cmd} {
+
+ # Configure specific ttk styles
+ ttk::style configure InnerWindow_Active.TButton \
+ -background $active_titclr \
+ -padding 0 \
+ -borderwidth 1 \
+ -relief flat
+ ttk::style map InnerWindow_Active.TButton \
+ -background [list active $active_titclr] \
+ -relief [list active raised]
+
+ ttk::style configure InnerWindow_Inactive.TButton \
+ -background $inactive_titclr \
+ -padding 0 \
+ -borderwidth 1 \
+ -relief flat
+ ttk::style map InnerWindow_Inactive.TButton \
+ -background [list active $inactive_titclr] \
+ -relief [list active raised]
+
+ # Set object variables
+ set max_X 1000
+ set max_Y 1000
+ set close_cmd $_close_cmd
+
+ # Create window GUI components
+ set win [frame $path -bd 1 -relief raised -bg $active_titclr -padx 2 -pady 2]
+ set main_frame [frame $win.main_frame]
+ set menu $win.menu
+
+ ## Create title bar
+ # - Title bar frame
+ set title_bar [frame $win.title_bar \
+ -bg $active_titclr \
+ -height $title_bar_height \
+ ]
+ set title_label [label $title_bar.text \
+ -bg $active_titclr -pady 0 \
+ -compound left -text $title \
+ -cursor left_ptr \
+ ]
+ if {$icon != {}} {
+ $title_label configure -image $icon -padx 5
+ }
+ # - Button "Close"
+ set close_button [ttk::button $title_bar.close_but \
+ -style InnerWindow_Active.TButton \
+ -command "$this close_window" \
+ -image ::ICONS::16::button_cancel \
+ -takefocus 0 \
+ ]
+ DynamicHelp::add $close_button -text [mc "Close"]
+ setStatusTip -widget $close_button -text [mc "Close"]
+ # - Button "Shade"
+ set coll_exp_but [ttk::button $title_bar.col_exp_but \
+ -style InnerWindow_Flat.TButton \
+ -command "$this collapse_expand" \
+ -image ::ICONS::16::_1uparrow \
+ -takefocus 0 \
+ ]
+ DynamicHelp::add $coll_exp_but -text [mc "Shade"]
+ setStatusTip -widget $coll_exp_but -text [mc "Shade"]
+ # Pack buttons
+ pack $coll_exp_but -padx 5 -side left -pady 0 -ipady 0
+ pack $close_button -side right -pady 0 -ipady 0 -padx 3
+ pack $title_label -side left -fill x -pady 0 -ipady 0 -expand 1
+ raise $close_button
+ # Set title bar event bindings
+ bind $title_label <Double-1> "$this collapse_expand; break"
+ bind $title_label <Button-1> "$this title_B1 %X %Y"
+ bind $title_label <B1-Motion> "$this title_B1_motion %X %Y; break"
+ bind $title_label <ButtonRelease-1> "$this title_B1_release; break"
+ bind $title_label <ButtonRelease-3> "$this title_B3_release %X %Y; break"
+
+
+ pack $title_bar -fill x
+ pack $main_frame -fill both -expand 1
+
+ # Show the window
+ set win_height [lindex $geometry 1]
+ bind $win <Destroy> "catch {delete object $this}"
+ bind $main_frame <Destroy> "catch {delete object $this}"
+ bind $win <Visibility> "$this raise_win"
+ bind $win <FocusIn> "$this focusin"
+ bind $win <FocusOut> "$this focusout"
+ place $win \
+ -width [lindex $geometry 0] \
+ -height [lindex $geometry 1] \
+ -x [lindex $geometry 2] \
+ -y [lindex $geometry 3] \
+ -anchor nw
+ raise $win
+ }
+
+ ## Object destructor
+ destructor {
+ close_window
+ }
+
+ ## Withdraw the window
+ # Note: Window can be taken back to visible state using method "geometry"
+ # @see geometry
+ # @return
+ public method withdraw {} {
+ place forget $win
+ }
+
+ ## Close the window
+ # @return void
+ public method close_window {} {
+ if {$close_window_in_progress} {return}
+ set close_window_in_progress 1
+
+ uplevel #0 $close_cmd
+ destroy $win
+ }
+
+ ## Get window inner frame where to map widgets in the window
+ # @return Widget - Inner frame
+ public method get_frame {} {
+ return $main_frame
+ }
+
+ ## Get and/or set window geometry including frame and title bar
+ # @parm Int = {} - Width
+ # @parm Int = {} - Height
+ # @parm Int = {} - Relative position -- X
+ # @parm Int = {} - Relative position -- Y
+ # Note: If you want to set only certain attributes then set others as {}
+ # @return Current window geometry {W H X Y}
+ public method geometry args {
+ # Set geometry
+ if {[llength $args]} {
+ if {[string length [lindex $args 0]]} {
+ place $win -width [lindex $args 0]
+ }
+ if {[string length [lindex $args 1]]} {
+ place $win -height [lindex $args 1]
+ set win_height [lindex $args 1]
+ }
+ if {[string length [lindex $args 2]]} {
+ place $win -x [lindex $args 2]
+ }
+ if {[string length [lindex $args 3]]} {
+ place $win -y [lindex $args 3]
+ }
+ update
+ }
+
+ # Get geometry
+ return [list \
+ [winfo width $win] \
+ [winfo height $win] \
+ [winfo x $win] \
+ [winfo y $win] \
+ ]
+ }
+
+ ## Event handler: window frame <FocusIn>
+ # @return void
+ public method focusin {} {
+ update
+ foreach widget [list $title_bar $title_label $win] {
+ $widget configure -bg $active_titclr
+ }
+ foreach widget [list $close_button $coll_exp_but] {
+ $widget configure -style InnerWindow_Active.TButton
+ }
+
+ update
+ }
+
+ ## Event handler: window frame <FocusOut>
+ # @return void
+ public method focusout {} {
+ update
+ foreach widget [list $title_bar $title_label $win] {
+ $widget configure -bg $inactive_titclr
+ }
+ foreach widget [list $close_button $coll_exp_but] {
+ $widget configure -style InnerWindow_Inactive.TButton
+ }
+
+ update
+ }
+
+ ## (Un)Shade window
+ # @return void
+ public method collapse_expand {} {
+ # Object variables
+ set minim_flag [expr {!$minim_flag}]
+
+ # Shade
+ if {$minim_flag} {
+ set image _1downarrow
+ pack forget $main_frame
+ place $win -height [expr {[winfo height $win.title_bar] + 4}]
+ # Unshade
+ } {
+ set image _1uparrow
+ pack $main_frame -fill both -expand 1
+ place $win -height $win_height
+ }
+ $coll_exp_but configure -image ::ICONS::16::$image
+ }
+
+ ## Determinate whether the window is shaded or not
+ # @return Bool - 1 == Shaded; 0 == Not shaded
+ public method get_minim_flag {} {
+ return $minim_flag
+ }
+
+ ## Insure window visibility
+ # @return void
+ public method raise_win {} {
+ if {!$allow_raise_win} {return}
+ set allow_raise_win 0
+ after 1000 "catch {$this set_allow_raise_win}"
+ raise $win
+ }
+
+ ## @see raise_win
+ # @return void
+ public method set_allow_raise_win {} {
+ set allow_raise_win 1
+ }
+
+ ## Event handler: title bar <Button-1>
+ # @parm Int x - Absolute X coordinate
+ # @parm Int y - Absolute Y coordinate
+ # @return void
+ public method title_B1 {x y} {
+ set click_X [expr {[winfo x $win] - $x}]
+ set click_Y [expr {[winfo y $win] - $y}]
+
+ set max_X [winfo width .]
+ set max_Y [winfo height .]
+ incr max_X -70
+ incr max_Y -70
+
+ focus $win
+ $title_label configure -cursor fleur
+ }
+
+ ## Event handler: title bar <ButtonRelease-1>
+ # @return void
+ public method title_B1_release {} {
+ $title_label configure -cursor left_ptr
+ }
+
+ ## Event handler: title bar <ButtonRelease-3>
+ # @parm Int x - Absolute X coordinate
+ # @parm Int y - Absolute Y coordinate
+ # @return void
+ public method title_B3_release {X Y} {
+ focus $win
+
+ if {!$menu_created} {
+ menuFactory $MENU $menu 0 "$this " 0 {}
+ set menu_created 1
+ }
+
+ tk_popup $menu $X $Y
+ }
+
+ ## Event handler: title bar <B1-Motion>
+ # @parm Int x - Absolute X coordinate
+ # @parm Int y - Absolute Y coordinate
+ # @return void
+ public method title_B1_motion {x y} {
+ incr x $click_X
+ incr y $click_Y
+
+ if {$x > 0 && $x < $max_X} {
+ place $win -x $x
+ }
+ if {$y > 0 && $y < $max_Y} {
+ place $win -y $y
+ }
+ }
+}
diff --git a/lib/lib/settings.tcl b/lib/lib/settings.tcl
new file mode 100755
index 0000000..3c50466
--- /dev/null
+++ b/lib/lib/settings.tcl
@@ -0,0 +1,293 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements interface to program settings (which are stored in a file)
+# --------------------------------------------------------------------------
+
+class Settings {
+ common dir_sep [file separator] ;# Directory separator (eg. '/')
+ common count 0 ;# Counter of instances
+
+ private variable isEmpty 1 ;# Is settings array empty
+ private variable isReady 0 ;# Is interface ready
+
+ private variable directory ;# Path to directory with settings file
+ private variable filename ;# Name of file with settings related to this instance
+ private variable fileFullPath ;# Full name of settings file (including directory)
+ private variable configArray {} ;# Content of settings maneged by this interface
+
+ ## Object contructor
+ # @parm String configDir - Path to directory with settings file
+ # @parm String configFileName - Name of file with settings
+ constructor {configDir configFileName} {
+ incr count ;# increment instance conter
+
+ # Incalize object variables
+ set configArray "::Settings::S$count" ;# Array of settings
+ set directory [string trimright $configDir "/\/"] ;# Path to directory with settings file
+ set filename [string trimleft $configFileName "/\/"] ;# Name of file with settings
+ set fileFullPath "${directory}${dir_sep}${filename}" ;# Full name of settings file
+
+ # If specified file does not exist -> create it
+ if {![file exists $fileFullPath]} {
+ if {[catch {
+ file mkdir $directory
+ close [open $fileFullPath w 420]
+ }]} then {
+ return
+ } else {
+ set isReady 1
+ }
+
+ # Else check if the file is readable and writable
+ } else {
+ if {$::MICROSOFT_WINDOWS || ([file readable $fileFullPath] && [file writable $fileFullPath])} {
+ set isReady 1
+ } {
+ return
+ }
+ }
+
+ # Load settings from the file
+ reLoadConfig
+ }
+
+ ## Object destructor
+ destructor {
+ }
+
+ ## (Re)load settings from config file
+ # @return result
+ public method reLoadConfig {} {
+
+ # Check if file is readable
+ if {!$::MICROSOFT_WINDOWS && ![file readable $fileFullPath]} {
+ return 0
+ }
+
+ # Read content of config file and store it as list of lines into fileData
+ set configFile [open $fileFullPath r]
+ set fileData [read $configFile]
+ set fileData [regsub -all {\r\n} $fileData "\n"]
+ set fileData [regsub -all {\r} $fileData "\n"]
+ set fileData [split $fileData "\n"]
+ close $configFile
+
+ # Parse content of the file
+ set category {general}
+ foreach line $fileData {
+ # Local variables
+ set line [string trim $line] ;# Line of config file
+ set key {} ;# Key
+ set value {} ;# Value for the key
+
+ # Skip empty lines
+ if {$line == {}} {continue}
+
+ # Handle category declaration
+ if {[regexp {^\[\s*[\w \t]+\s*\]$} $line]} {
+ set category [string trim $line "\[\] \t"]
+
+ # Handle key and its value
+ } elseif {[regexp {^\s*[\w \t:]+\s*\=\s*\".*\"\s*$} $line]} {
+ # Determinate key
+ regexp {^\s*[\w \t:]+\s*\=} $line key
+ set key [string trim $key "=\t "]
+ # Determinate value
+ regexp {\s*\".*\"\s*$} $line value
+ set value [string trim $value]
+ regsub {^\"} $value {} value
+ regsub {\"$} $value {} value
+ regsub -all "\a" $value "\n" value
+ # Set key and value to array
+ set "$configArray\($category/$key\)" $value
+ }
+ }
+
+ # Set variable isEmpty
+ if {[array size $configArray] != 0} {
+ set isEmpty 0
+ } {
+ set isEmpty 1
+ }
+
+ # return result
+ return 1
+ }
+
+ ## Save current content of $configArray to config file
+ # @return result
+ public method saveConfig {} {
+
+ # Check if file is writable
+ if {![file writable $fileFullPath]} {
+ return 0
+ }
+
+ # Local variables
+ set configFile [open $fileFullPath w 420] ;# ID of config file chanel
+ set categories {general} ;# Name of current category
+
+ # Determinate list of categories
+ foreach key [array names $configArray] {
+ # Determinate category
+ regexp {^.+/} $key category
+ set category [string trimright $category {/}]
+ # Append category to the list
+ if {[lsearch $categories $category] == -1} {
+ lappend categories $category
+ }
+ }
+
+ # Iterate over categories and save them to the file
+ foreach category $categories {
+ # Get names of keys in current category
+ set keys [array names $configArray -regexp "$category/"]
+ # Save category declaration
+ puts $configFile "\n\[$category\]"
+ # Iterate over keys in current category
+ foreach fullKey $keys {
+ # Determinate key
+ regsub {^[^/]*/} $fullKey {} key
+ # Determinate value
+ set value [subst "\$$configArray\(\$fullKey\)"]
+ regsub -all "\n" $value "\a" value
+ # Save key and value
+ puts $configFile "$key=\"$value\""
+ }
+ }
+
+ # Done ...
+ close $configFile
+ return 1
+ }
+
+ ## Return True if config array is empty
+ # @return Bool - result
+ public method isEmpty {} {
+ return $isEmpty
+ }
+
+ ## Return True if interface is ready
+ # @return Bool - result
+ public method isReady {} {
+ return $isReady
+ }
+
+ ## Clear all settings
+ # @return void
+ public method clear {} {
+ array unset $configArray
+ }
+
+ ## Remove specified key from settings
+ # @parm String key - name of key to remove
+ # @return Bool - result
+ public method remove {key} {
+ regsub -all {_} $key {__} key
+ regsub -all {\s} $key {_} key
+
+ if {[i_contains $key]} {
+ unset "$configArray\($key\)"
+ return 1
+ } {
+ return 0
+ }
+ }
+
+ ## Return True if the specified key is defined
+ # @parm String key - key to search for
+ # @return Bool - result
+ public method contains {key} {
+ regsub -all {_} $key {__} key
+ regsub -all {\s} $key {_} key
+
+ return [i_contains $key]
+ }
+
+ ## Internal key search (Does not peform key name adjusment)
+ # @parm String key - name of key to search for
+ # @return Bool - result
+ private method i_contains {key} {
+ if {[array names $configArray -exact $key] == {}} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Get value for the given key
+ # @parm String key - Key
+ # @parm Mixed default - Default value
+ # @return Mixed - value for the given key
+ public method getValue {key default} {
+
+ # Adjust key name
+ if {![regexp {^.+/} $key]} {
+ set key "general/$key"
+ }
+ regsub -all {_} $key {__} key
+ regsub -all {\s} $key {_} key
+
+ # Check for valid key format
+ if {![regexp {^[\w:]+/[\w:]+$} $key]} {
+ return $default
+ }
+
+ # Check if the given key is defined
+ if {[i_contains $key]} {
+ return [subst "\$$configArray\(\$key\)"]
+ } {
+ return $default
+ }
+ }
+
+ ## Set value for the given key
+ # @parm String key - Key
+ # @parm Mixed value - Value
+ # @return Bool - result
+ public method setValue {key value} {
+
+ ## Check for key validity
+ if {[regexp {[\!\=\$\^\*\+\?\.\[\]\{\}\(\)]} $key]} {
+ return 0
+ }
+
+ regsub -all {_} $key {__} key
+ regsub -all {\s} $key {_} key
+
+ if {![regexp {^.+/} $key]} {
+ set key "general/$key"
+ }
+
+ if {![regexp {^[\w:]+/[\w:]+$} $key]} {
+ return 0
+ }
+
+ ## Set value
+ set "$configArray\($key\)" $value
+ return 1
+ }
+}
diff --git a/lib/main.tcl b/lib/main.tcl
new file mode 100755
index 0000000..6a0f033
--- /dev/null
+++ b/lib/main.tcl
@@ -0,0 +1,699 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Initilizator of the program
+# --------------------------------------------------------------------------
+
+# GENERAL CONSTANTS
+# -----------------------------
+encoding system {utf-8} ;# System encoding
+set LIB_DIRNAME [file normalize [file dirname $argv0]] ;# Path to directory where the *.tcl file are located
+set VERSION "1.3.7" ;# Program version
+set SHORTNAME "MCU8051IDE" ;# Program short name (without white space)
+set APPNAME "MCU 8051 IDE v$VERSION" ;# Full program name
+set MIN_TCL_VER "8.5" ;# Minimum required Tcl version
+set APPLICATION_LOADED 0 ;# True if program is loaded
+set TRANSLATION_LOADED 0 ;# Bool: Translation loaded
+set MICROSOFT_WINDOWS {} ;# Bool: Windows OS running on the host computer
+set CONFIG_DIR {} ;# Directory containing configuration files
+
+# Check for correct Tcl version
+if {[package vcompare $::tcl_version $::MIN_TCL_VER] < 0} {
+ puts stderr "ERROR: This program requires Tcl version $::MIN_TCL_VER or higher but you have Tcl $::tcl_version ."
+ puts stderr " Please install Tcl $::MIN_TCL_VER in order to run this program"
+
+ exit 1
+}
+
+## Tcl packages used by this prgram
+ # Format: {
+ # {pkg_name pkg_verison}
+ # ...
+ # }
+set LIBRARIES_TO_LOAD {
+ {BWidget 1.7}
+ {Itcl 3.4}
+ {Tcl 8.2}
+ {md5 2.0}
+ {Tk 8.5}
+ {img::png 1.3}
+ {tdom 0.8}
+ {Tclx 8.0}
+}
+
+## Bool:
+ # 1 == library TclX is avaliable
+ # 0 == library TclX is NOT avaliable
+ #
+ # TclX is used here only to handle signals (e.g. SIGINT), so the IDE can run
+ # without it, that's the reason for this variable. If TCLX_AVAILABLE is 0 then
+ # we are not able to handle signals, but everything else works normally.
+set ::TCLX_AVAILABLE 1
+
+## Determinate the host OS
+set ::MICROSOFT_WINDOWS 0
+if {[string first {Windows} ${tcl_platform(os)}] != -1} {
+ # Note:
+ # Microsoft Windows is NOT a POSIX system and because of that we need
+ # to do some workarounds here in order to make the IDE functional there.
+ set ::MICROSOFT_WINDOWS 1
+}
+
+# Set directory containing configuration files according to the host OS
+if {!$::MICROSOFT_WINDOWS} {
+ set CONFIG_DIR [file join $::env(HOME) .[string tolower ${::SHORTNAME}]]
+} {
+ set CONFIG_DIR [file join ${::env(USERPROFILE)} ".[string tolower ${::SHORTNAME}]"]
+}
+
+# Handle CLI options
+# -----------------------------
+proc mc args {return [eval "format $args"]}
+source "${::LIB_DIRNAME}/cli.tcl"
+
+# SHOW WARNING MESSAGE
+# -----------------------------
+
+if {!$::CLI_OPTION(quiet)} {
+ if {$::CLI_OPTION(nocolor)} {
+ puts "WARNING:"
+ puts "\tThis program is distributed with ABSOLUTELY NO WARRANTY !"
+ puts "\tPlease report bugs at http://mcu8051ide.sf.net"
+ puts "\tAuthor: Martin Osmera <martin.osmera@gmail.com>"
+ } {
+ puts "WARNING:"
+ puts "\tThis program is distributed with ABSOLUTELY NO WARRANTY !"
+ puts "\tPlease report bugs at \033\[34;1mhttp://mcu8051ide.sf.net\033\[m"
+ puts "\tAuthor: Martin Osmera \033\[33;1m<martin.osmera@gmail.com>\033\[m"
+ }
+}
+
+## This function should be called when some Tcl library fail to load
+ # @parm String library - Name of failed library
+ # @return void
+proc libraryLoadFailed {library} {
+
+ # Itcl workarond for Debian
+ if {$library == {Itcl}} {
+ set library_version "3.4"
+ set libname "libitcl"
+
+ set ::env(ITCL_LIBRARY) ${::LIB_DIRNAME}
+
+ puts stderr "\nERROR: Unable to load Itcl library compatible with this version of Tcl/Tk !"
+ puts stderr "Trying to workaround ..."
+
+ if {[lsearch {Linux} ${::tcl_platform(os)}] == -1} {
+ puts stderr "FATAL ERROR: Unsupported operating system. ${::tcl_platform(os)}"
+ puts stderr "You can contact author of the project at <martin.osmera@gmail.com> if you want to get you OS supported."
+ exit 1
+ }
+
+ if {[lsearch {x86_64 i386 i486 i586 i686 x86} ${::tcl_platform(machine)}] == -1} {
+ puts stderr "FATAL ERROR: Unsupported system architecture. ${::tcl_platform(machine)}"
+ puts stderr "You can contact author of the project at <martin.osmera@gmail.com> if you want to get you OS supported."
+ exit 1
+ }
+
+ puts stderr "Loading library $library for ${::tcl_platform(os)} on ${::tcl_platform(machine)} ... (filename: ${libname}${library_version}.so.${::tcl_platform(os)}.${::tcl_platform(machine)})"
+ if {[catch {load "${::LIB_DIRNAME}/${libname}${library_version}.so.${::tcl_platform(os)}.${::tcl_platform(machine)}" Itcl} error_info]} {
+ puts stderr "FAILED !"
+ puts stderr "Reason: ${error_info}"
+ puts "\nPlease try to run mcu8051ide with --check-libraries to see what's wrong."
+
+ exit 1
+ } {
+ puts stderr "WORKAROUND SUCCESSFULL ... \n(But don't be much happy about this, it is still serious failure. And please don't forget to comply to developers of your Linux distribution. Missing library is: ${library} version ${library_version})"
+ return
+ }
+
+ # Tclx workarond for Debian
+ } elseif {$library == {Tclx}} {
+ set ::TCLX_AVAILABLE 0
+ puts stderr "\nERROR: Unable to load Tclx library, functionality will be limited"
+ return
+ }
+
+ # Print error message
+ if {$::CLI_OPTION(nocolor)} {
+ puts stderr "\n\nERROR: Unable to load library $library"
+ } {
+ puts stderr "\n\n\033\[31mERROR:\033\[m Unable to load library \033\[32m$library\033\[m"
+ }
+
+ # Print tip
+ puts "\nTip: try to run mcu8051ide with --check-libraries to see what's wrong."
+
+ # Terminate the program
+ exit 1
+}
+
+# PRE-INITIALIZATION
+# -----------------------------
+# Load Tk ToolKit
+set T [lindex [time {
+ if {[catch {package require img::png 1.3}]} {
+ libraryLoadFailed "img::png"
+ }
+ if {[catch {package require Tk $::MIN_TCL_VER} errinfo]} {
+ puts stderr "Unable to initialize Tk\n$errinfo"
+ }
+}] 0]
+# Hide main window
+wm withdraw .
+update
+
+# Determinate default Fixed font
+set ::DEFAULT_FIXED_FONT {DejaVu Sans Mono}
+if {[lsearch -ascii -exact [font families] {DejaVu Sans Mono}] == -1} {
+ set ::DEFAULT_FIXED_FONT {Courier}
+}
+
+# ------------------------------------------------------------------------------
+# Microsoft Windows OS specific code
+# ------------------------------------------------------------------------------
+if {$::MICROSOFT_WINDOWS} {
+ # Print windows related warning
+ puts ""
+ puts " THE IDE WAS ORIGINALY DESIGNED FOR POSIX, SO IT IS POSSIBLE THAT SOME"
+ puts " FUNCTIONALITY WILL BE LIMITED ON YOUR OS DUE TO ABSENCE OF CERTAIN"
+ puts " POSIX FUNCTIONALITY !"
+ puts ""
+
+ # Redefine the "bind" command, because on Windows binding a callback to
+ # event, which does not exist on Windows would cause program crash
+ rename bind original_command_bind
+ proc microsoft_windows_specific_bind args {
+ if {
+ [string first {ISO_} [lindex $args 1]] != -1 ||
+ [string first {XF86_} [lindex $args 1]] != -1
+ } {
+ return
+ }
+
+ eval "original_command_bind $args"
+ }
+ rename microsoft_windows_specific_bind bind
+}
+# ------------------------------------------------------------------------------
+
+
+# Load base config file
+# -----------------------------
+
+# Load i18n library
+# (It must be loaded here because ::msgcat::mclocale must be available when
+# base config file is being loaded)
+incr T [lindex [time {
+ if {[catch {package require msgcat 1.3.4}]} {
+ libraryLoadFailed "msgcat"
+ } {
+ namespace import -force ::msgcat::*
+ }
+}] 0]
+# Check if the file exits
+if {![file exists ${::CONFIG_DIR}]} {
+ file mkdir ${::CONFIG_DIR}
+ puts "\nCreating program configuration files in directory: \"[file normalize ${::CONFIG_DIR}]\""
+ if {!$::MICROSOFT_WINDOWS} {
+ puts "Welcome in this IDE, [file tail [file normalize ~]] !"
+ } {
+ catch { ;# Make the configuration directory in Microsoft Windows hidden
+ file attributes $::CONFIG_DIR -hidden 1
+ }
+ puts "Welcome in this IDE, ${::env(USERNAME)} !"
+ }
+}
+## Open and read the file
+if {[catch {
+ set conf_file [open "${::CONFIG_DIR}/base.conf" r]
+ # File doesn't exits -> create it with default configuration
+}]} then {
+ # Default settings
+ array set GLOBAL_CONFIG [list \
+ splash 1 \
+ tips 1 \
+ language [::msgcat::mclocale] \
+ ]
+
+ # Create the file
+ if {[catch {
+ set conf_file [open "${::CONFIG_DIR}/base.conf" w]
+ puts -nonewline $conf_file [list \
+ $GLOBAL_CONFIG(splash) \
+ $GLOBAL_CONFIG(splash) \
+ $GLOBAL_CONFIG(language) \
+ ]
+ close $conf_file
+ }]} {
+ puts stderr "Unable to create base configuration file"
+ }
+ # File exits -> read configuration from it
+} else {
+ # Read file contents
+ set data [read $conf_file]
+ close $conf_file
+
+ # Set configuration acording to the file contents
+ set GLOBAL_CONFIG(splash) [lindex $data 0]
+ set GLOBAL_CONFIG(tips) [lindex $data 1]
+ set GLOBAL_CONFIG(language) [lindex $data 2]
+
+ ## Validate read values
+ if {![string is boolean -strict ${GLOBAL_CONFIG(splash)}]} {
+ set GLOBAL_CONFIG(splash) 1
+ }
+ if {![string is boolean -strict ${GLOBAL_CONFIG(tips)}]} {
+ set GLOBAL_CONFIG(tips) 1
+ }
+ # Check if the cpecified translation is valid
+ set tmp [list]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ set tmp [glob -nocomplain -types f -tails \
+ -directory "${LIB_DIRNAME}/../translations" *.msg \
+ ]
+ }
+ set translations {en}
+ foreach translation $tmp {
+ lappend translations [file rootname $translation]
+ }
+ if {[lsearch $translations ${GLOBAL_CONFIG(language)}] == -1} {
+ set GLOBAL_CONFIG(language) {en}
+ }
+}
+
+# Load translation
+# -----------------------------
+
+# Load language specific translation file
+if {!${::CLI_OPTION(notranslation)} && ${GLOBAL_CONFIG(language)} != {en}} {
+ if {[catch {
+ mclocale ${GLOBAL_CONFIG(language)}
+ mcload "${LIB_DIRNAME}/../translations/"
+
+ } result]} then {
+ puts stderr "Unable to load translation"
+ puts stderr "\tFile: '${LIB_DIRNAME}/../translations/${GLOBAL_CONFIG(language)}.msg'"
+ puts "\n"
+ puts $result
+
+ } else {
+ set ::TRANSLATION_LOADED 1
+ }
+}
+
+# CREATE SPLASH SCREEN
+# -----------------------------
+if {!$::CLI_OPTION(nosplash) && ${::GLOBAL_CONFIG(splash)}} {
+
+ # Crete toplevel window
+ toplevel .splash -class {Splash creen} -bg {#EEEEEE}
+
+ # Show image of splash creen
+ place [label .splash.bg \
+ -image [ \
+ image create photo -format png \
+ -file "${::LIB_DIRNAME}/../icons/other/splash.png" \
+ ] \
+ ] -x 0 -y 0 -width 400 -height 199
+
+ # Show status bar
+ place [label .splash.status \
+ -bg {#FFFFFF} -fg {#0000FF} \
+ -text [mc "Initializing %s" $APPNAME] \
+ ] -x 200 -y 180 -anchor center
+
+ # Set window parameters
+ wm geometry .splash "=400x199+[expr {[winfo screenwidth .] / 2 - 200}]+[expr {[winfo screenheight .] / 2 - 100}]"
+ wm overrideredirect .splash 1
+
+ # Click on splash creen destroys it
+ bind .splash <1> {wm withdraw .splash}
+
+ # Done ..
+ update
+}
+
+
+# BASIC FUNCTIONS
+# -----------------------------
+
+## Print content of $T in mili seconds ($T must contain value in [us])
+ # @return void
+proc time_in_msec {} {
+ global T ;# Time in microseconds
+
+ # Determinate number of miliseconds
+ set msec [lindex $T 0]
+ set msec [expr {$msec / 1000}]
+
+ # print the message
+ if {!$::CLI_OPTION(quiet)} {
+ if {$::CLI_OPTION(nocolor)} {
+ puts "... $msec ms"
+ } {
+ puts "... \033\[33m$msec ms\033\[m"
+ }
+ }
+}
+
+## Print some initialization message (splash screen and CLI)
+ # @parm String message - text of the message
+ # @return void
+proc showInitMessage {message} {
+
+ # Change content of splash screen status bar
+ if {!${::CLI_OPTION(nosplash)} && ${::GLOBAL_CONFIG(splash)}} {
+ if {[winfo exists .splash.status]} {
+ .splash.status configure -text [string trim $message]
+ update
+ }
+ }
+
+ # Print message to console output
+ if {!${::CLI_OPTION(quiet)}} {
+ if {${::CLI_OPTION(nocolor)}} {
+ puts -nonewline $message
+ } {
+ puts -nonewline "\033\[37m$message\033\[m"
+ }
+
+ puts -nonewline [string repeat { } [expr {38 - [string length $message]}]]
+ flush stdout
+ }
+}
+
+## Set status bar tip for some widget
+ # Usage:
+ # setStatusTip -widget $some_widget -text "some text"
+ #
+ # @return void
+proc setStatusTip args {
+
+ # Local variables
+ set widgetIsSet 0 ;# True if widget is set
+ set textIsSet 0 ;# True if text is set
+ set argsLength [llength $args] ;# Number of arguments
+ set widget {} ;# ID of widget specified by argument '-widget'
+ set helpText {} ;# Help text specified by argument '-text'
+
+ # Iterate over given arguments and evaluate them
+ for {set i 0} {$i < $argsLength} {incr i} {
+ # Currently parsed argument
+ set arg [lindex $args $i]
+ # Decide what $arg means
+ switch -- $arg {
+ -widget { ;# ID of the widget
+
+ # check if that widget wasn't already specified
+ if {$widgetIsSet} {
+ error "Widget has been already specified"
+ }
+
+ # Check if widget's ID follow the arument
+ incr i
+ if {$i >= $argsLength} {
+ error "Expected widget name after -widget option"
+ }
+
+ # Set ID of the widget
+ set widget [lindex $args $i]
+ if {![winfo exists $widget]} {
+ error "The specified widget does not exist"
+ }
+
+ # Widget is now set
+ set widgetIsSet 1
+ }
+
+ -text { ;# The help text
+
+ # Check if help text follow the argument
+ incr i
+ if {$i >= $argsLength} {
+ error "Expected text after -text option"
+ }
+
+ # Set the help text
+ set helpText [lindex $args $i]
+
+ # Help text is now set
+ set textIsSet 1
+ }
+
+ default { ;# Unrecognized opton -> invoke ERROR
+ error "Invalid argument '$arg', possible options are -widget and -text"
+ }
+ }
+ }
+
+ # Ckeck if both aruments are properly specified
+ if {!$widgetIsSet || !$textIsSet} {
+ error "You must specify text and widget"
+ }
+
+ # Create binding
+ bind $widget <Enter> "Sbar -freeze {$helpText}"
+ bind $widget <Leave> "Sbar {}"
+}
+
+
+
+# INITIALIZATION
+# -----------------------------
+
+# Show "first line message"
+if {!$CLI_OPTION(quiet)} {
+ if {$CLI_OPTION(nocolor)} {
+ puts [mc "\nInitializing MCU 8051 IDE %s" $VERSION]
+ } {
+ puts [mc "\nInitializing \033\[1mMCU 8051 IDE \033\[32m%s\033\[m" $VERSION]
+ }
+}
+
+## Load libraries
+showInitMessage [mc "\tLoading libraries"]
+incr T [lindex [time {
+ # Iterate over list of libraries and lod each of them
+ foreach library $::LIBRARIES_TO_LOAD {
+ # Loading successful
+ if {[catch {package require [lindex $library 0] [lindex $library 1]}]} {
+ libraryLoadFailed [lindex $library 0]
+ # Loading failed
+ } {
+ if {!$::CLI_OPTION(nosplash)} update
+ }
+ }
+
+ if {$::MICROSOFT_WINDOWS} { ;# Load dde - Dynamic Data Exchange on Microsoft Windows
+ package require dde
+ }
+
+ # Import NS for managing OOP in Tcl
+ namespace import -force ::itcl::*
+}] 0]
+
+# Look for some external programs
+foreach program {
+ urxvt vim emacs kwrite gedit nano dav
+ le sdcc indent doxygen asl asem doxywizard
+ as31 sdcc-sdcc gvim
+ } {
+ if {[auto_execok $program] == {}} {
+ set ::PROGRAM_AVALIABLE($program) 0
+ } {
+ set ::PROGRAM_AVALIABLE($program) 1
+ }
+}
+time_in_msec ;# Print time info
+
+## Load program sources
+showInitMessage [mc "\tLoading program sources"]
+set T [time {
+ source "${::LIB_DIRNAME}/lib/innerwindow.tcl" ;# Tool for creating inner windows
+ source "${::LIB_DIRNAME}/dialogs/errorhandler.tcl" ;# Background error handler
+ source "${::LIB_DIRNAME}/dialogs/my_tk_messageBox.tcl" ;# A replacement for tk_messageBox
+ source "${::LIB_DIRNAME}/lib/settings.tcl" ;# Settings management
+ source "${::LIB_DIRNAME}/project.tcl" ;# Project management
+ source "${::LIB_DIRNAME}/dialogs/fsd.tcl" ;# File selection dialog
+ source "${::LIB_DIRNAME}/X.tcl" ;# GUI <==> Implementation Interface
+ source "${::LIB_DIRNAME}/configdialogs/configdialogs.tcl";# Configuration dialogs
+ source "${::LIB_DIRNAME}/editor/editor.tcl" ;# Source code editor
+ source "${::LIB_DIRNAME}/lib/Math.tcl" ;# Special mathematical operations
+ source "${::LIB_DIRNAME}/compiler/compiler.tcl" ;# 8051 Assemly language compiler
+ source "${::LIB_DIRNAME}/dialogs/tips.tcl" ;# Tips on startup
+ source "${::LIB_DIRNAME}/lib/hexeditor.tcl" ;# Hexadecimal editor
+ source "${::LIB_DIRNAME}/utilities/hexeditdlg.tcl" ;# Hexadecimal editor dialog
+ source "${::LIB_DIRNAME}/environment.tcl" ;# Main window "trappings" (menu and such)
+ source "${::LIB_DIRNAME}/rightpanel/rightpanel.tcl" ;# Right panel
+ source "${::LIB_DIRNAME}/leftpanel/filelist.tcl" ;# Left and middle panel
+ source "${::LIB_DIRNAME}/simulator/simulator.tcl" ;# MCU Simulator
+ source "${::LIB_DIRNAME}/bottompanel/bottomnotebook.tcl";# Bottom panel
+ source "${::LIB_DIRNAME}/maintab.tcl" ;# Central widget
+ source "${::LIB_DIRNAME}/lib/ihextools.tcl" ;# Tools for manipulating Intel 8 HEX
+ source "${::LIB_DIRNAME}/utilities/symbol_viewer.tcl" ;# Assembly symbols viewer
+ source "${::LIB_DIRNAME}/utilities/eightsegment.tcl" ;# 8-segment LED display editor
+ source "${::LIB_DIRNAME}/utilities/asciichart.tcl" ;# ASCII chart
+ source "${::LIB_DIRNAME}/utilities/notes.tcl" ;# Scribble notepad
+ source "${::LIB_DIRNAME}/utilities/baseconvertor.tcl" ;# Base convertor
+ source "${::LIB_DIRNAME}/utilities/speccalc.tcl" ;# Special calculator for x51 MCU's
+ source "${::LIB_DIRNAME}/utilities/rs232debugger.tcl" ;# UART/RS232 applications debugger
+}]
+time_in_msec ;# Print time info
+
+# CHECK FOR VALIDITY OF THE MCU DATABASE
+if {${::X::avaliable_processors} == {}} {
+ destroy .splash
+ bell
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [mc "FATAL ERROR"] \
+ -message [mc "MCUs database file is currupted,\nthis program cannot run without it.\nPlease reinstall MCU 8051 IDE."]
+ exit 1
+}
+
+# Load global configuration
+loadApplicationConfiguration
+
+# Initialize GUI environment
+iconbar_redraw ;# Main toolbar
+mainmenu_redraw ;# Main menu
+shortcuts_reevaluate ;# Key shortcuts
+
+## Remove splash screen
+destroy .splash
+if {$CLI_OPTION(minimalized)} {
+ wm state . iconic
+} {
+ wm deiconify .
+}
+
+# Configure signal handling
+if {$::TCLX_AVAILABLE} {
+ proc signal_handler {signal_name} {
+ global cntrlc_flag
+ puts stdout [mc "\nExiting on signal %s" $signal_name]
+ if {[catch {::X::__exit 1}]} {
+ exit 1
+ }
+ }
+
+ signal trap SIGINT {signal_handler SIGINT}
+ signal trap SIGTERM {signal_handler SIGTERM}
+}
+
+
+# ---------------------------------------------------------
+# Ugly job ... dirty workarounds and such a shit ... :(
+# ---------------------------------------------------------
+
+catch {
+ NoteBook .foo
+ proc NoteBook::_getoption {path page option} {
+ if {$option == {-background}} {
+ return {#eeeeee}
+ }
+
+ set value [Widget::cget $path.f$page $option]
+ if {![string length $value]} {
+ set value [Widget::cget $path $option]
+ }
+
+ return $value
+ }
+ destroy .foo
+}
+
+# ---------------------------------------------------------
+
+
+## Open the last session
+# Print message
+showInitMessage [mc "\tOpening last session"]
+flush stdout
+# Evaluate new geometry of the main window
+update
+evaluate_new_window_geometry
+# Open projects of last session
+set T [time {
+ foreach project_file $::CONFIG(OPENED_PROJECTS) {
+ if {![Project::open_project_file $project_file]} {
+ tk_messageBox \
+ -title [mc "File not found"] \
+ -icon warning \
+ -type ok \
+ -message [mc "Unable to open project file:\n\"%s\"" $project_file]
+ }
+ }
+}]
+
+# Reopen base convertors
+foreach cfg $::CONFIG(BASE_CONVERTORS) {
+ if {[catch {
+ set obj [::X::__base_convertor]
+ ::X::$obj set_config $cfg
+ }]} {
+ puts stderr {}
+ puts stderr $::errorInfo
+ }
+}
+
+time_in_msec ;# Print time info
+
+# Create binding for panes management
+bind . <Configure> {X::redraw_panes}
+# Print final message
+if {!$CLI_OPTION(quiet)} {
+ puts [mc "%s is now operational\n" $APPNAME]
+}
+
+# Program is now operational
+set ::Compiler::in_IDE 1
+set APPLICATION_LOADED 1
+set X::critical_procedure_in_progress 0
+update idle
+X::redraw_panes
+foreach project ${::X::openedProjects} {
+ $project filelist_adjust_size_of_tabbar
+ $project ensure_that_both_editors_are_properly_initialized
+}
+# Focus on the active editor
+if {${::X::actualProject} != {}} {
+ update
+ focus [${::X::actualProject} editor_procedure {} cget -editor]
+ focus [${::X::actualProject} editor_procedure {} Configure {}]
+ focus [${::X::actualProject} editor_procedure {} highlight_visible_area {}]
+}
+
+# Just workaround for disapearing main menu
+raise .
+
+# Correct strange behavior concerning restoration of the last window size and position
+if {$::MICROSOFT_WINDOWS} {
+ update
+ wm geometry . $::CONFIG(WINDOW_GEOMETRY)
+}
diff --git a/lib/maintab.tcl b/lib/maintab.tcl
new file mode 100755
index 0000000..57f0351
--- /dev/null
+++ b/lib/maintab.tcl
@@ -0,0 +1,425 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Manages central widget of this program, each instance of this class
+# stands for one project
+# --------------------------------------------------------------------------
+
+source "${::LIB_DIRNAME}/pale/pale.tcl" ;# Peripheral Abstraction Layer Engine
+
+class MainTab {
+ inherit FileList BottomNoteBook Pale
+
+ public variable fileList_Pane ;# ID of pane window containing list of files and editor
+ public variable top_Pane ;# ID of pane window containing fileList_Pane and right panel
+ public variable main_Pane ;# ID of pane window containing top_Pane and bottom panel
+ public variable rightPanel ;# ID of right panel container
+
+ public variable projectName ;# Name of project related to this instance
+ public variable projectPath ;# Path to directory where the project file is located
+ public variable projectFile ;# Name of the project file
+ public variable procData ;# Processor definition list
+ public variable avaliable_SFR ;# List of SFR and SFB which are avaliable on the choosen MCU
+
+ # Compiler configuration related variables
+ private variable PCC_native_assembler ;# --> ::Compiler::Settings::*
+ private variable PCC_selected_assembler ;# --> ::ExternalCompiler::selected_assembler
+ private variable PCC_ASEM51_config ;# --> ::ExternalCompiler::assembler_ASEM51_config
+ private variable PCC_ASEM51_addcfg ;# --> ::ExternalCompiler::assembler_ASEM51_addcfg
+ private variable PCC_ASL_config ;# --> ::ExternalCompiler::assembler_ASL_config
+ private variable PCC_ASL_addcfg ;# --> ::ExternalCompiler::assembler_ASL_addcfg
+ private variable PCC_AS31_config ;# --> ::ExternalCompiler::assembler_AS31_config
+ private variable PCC_AS31_addcfg ;# --> ::ExternalCompiler::assembler_AS31_addcfg
+ private variable PCC_sdcc_bool_opt ;# --> ::ExternalCompiler::sdcc_bool_options
+ private variable PCC_sdcc_str_opt ;# --> ::ExternalCompiler::sdcc_string_options
+ private variable PCC_sdcc_opt_str_opt ;# --> ::ExternalCompiler::sdcc_optional_string_options
+ private variable PCC_sdcc_scs_str_opt ;# --> ::ExternalCompiler::sdcc_scs_string_options
+
+ ## Project information variables
+ # (P - project; G - general)
+ public variable P_information_version ;# Project version
+ public variable P_information_date ;# Date of last project update
+ public variable G_information_authors ;# List of project authors
+ public variable G_information_copyright ;# Project copyright information
+ public variable G_information_licence ;# Project licence information
+ public variable P_option_mcu_type ;# Processor type (e.g. AT89C51RC)
+ public variable P_option_clock ;# Project default simulator clock rate
+ public variable P_option_mcu_xdata ;# Size of external data memory
+ public variable P_option_mcu_xcode ;# Size of external program memory
+ public variable P_option_main_file ;# Project main source file
+
+ public variable project_description ;# Project decription text
+ public variable todoText ;# Content of TODO list
+ public variable calculatorList ;# List of values for calculator (see class Calculator)
+ public variable other_options ;# Other options
+ public variable projectFiles ;# List of project source code files
+
+ private variable mainTab ;# NoteBook tab identifier (container)
+
+ ## Object constructor
+ # @parm String projectpath - Path to directory where the project file is located
+ # @parm String projectfile - Name of the project file
+ # @parm List dataList - Data extracted from project file (see NS Project)
+ constructor {ProjectName projectpath projectfile dataList} {
+ set projectName $ProjectName
+
+ #
+ ## PARSE PROJECT DATA
+ #
+
+ set i 0
+ foreach info {version date} {
+ regsub -all {\\\}} [regsub -all {\\\{} [lindex $dataList "0 $i"] "{"] "}" P_information_$info
+ incr i
+ }
+
+ set i 0
+ foreach info {authors copyright licence} {
+ regsub -all {\\\}} [regsub -all {\\\{} [lindex $dataList "1 $i"] "{"] "}" G_information_$info
+ incr i
+ }
+
+ set P_option_mcu_type [lindex $dataList {2 0}]
+ set P_option_clock [lindex $dataList {2 1}]
+ set P_option_mcu_xdata [lindex $dataList {2 2}]
+ set P_option_mcu_xcode [lindex $dataList {2 3}]
+
+ set watches_file [lindex $dataList {3 0}]
+ set scenario_file [lindex $dataList {3 1}]
+ set P_option_main_file [lindex $dataList {3 2}]
+ set editor_sw_lock [lindex $dataList {3 3}]
+ set graphList [lindex $dataList 4]
+
+ set project_description [lindex $dataList {5 0}]
+ regsub -all {\\\{} $project_description "{" project_description
+ regsub -all {\\\}} $project_description "}" project_description
+ set todoText [lindex $dataList {5 1}]
+ regsub -all {\\\{} $todoText "{" todoText
+ regsub -all {\\\}} $todoText "}" todoText
+ set calculatorList [lindex $dataList 6]
+ set other_options [lindex $dataList 7]
+
+ # Load compiler configurations
+ if {[llength [lindex $dataList 8]]} {
+ array set PCC_native_assembler [lindex $dataList {8 0}]
+ set PCC_selected_assembler [lindex $dataList {8 1}]
+ array set PCC_ASEM51_config [lindex $dataList {8 2}]
+ array set PCC_ASEM51_addcfg [lindex $dataList {8 3}]
+ array set PCC_ASL_config [lindex $dataList {8 4}]
+ array set PCC_ASL_addcfg [lindex $dataList {8 5}]
+ array set PCC_sdcc_bool_opt [lindex $dataList {8 6}]
+ array set PCC_sdcc_str_opt [lindex $dataList {8 7}]
+ array set PCC_sdcc_opt_str_opt [lindex $dataList {8 8}]
+ array set PCC_sdcc_scs_str_opt [lindex $dataList {8 9}]
+
+ if {[llength [lindex $dataList 8]] > 10} {
+ array set PCC_AS31_config [lindex $dataList {8 10}]
+ array set PCC_AS31_addcfg [lindex $dataList {8 11}]
+ }
+ } {
+ retrieve_compiler_settings
+ }
+
+ set projectFiles [lindex $dataList 9]
+
+ # Load default values if the given values is not valid
+ if {[lsearch ${::X::avaliable_processors} $P_option_mcu_type] == -1} {
+ set P_option_mcu_type [lindex ${X::project_edit_defaults} {0 1}]
+ puts stderr "Unsupported processor type -- setting to [lindex ${X::project_edit_defaults} {0 1}]"
+ }
+ set procData [SelectMCU::get_processor_details $P_option_mcu_type]
+ if {$procData == {}} {
+ wm withdraw .
+ tk_messageBox \
+ -icon error \
+ -type ok \
+ -title [mc "FATAL ERROR"] \
+ -message [mc "MCUs database file is currupted,\nthis program cannot run without it.\nPlease reinstall MCU 8051 IDE."]
+ exit 1
+ }
+ refresh_project_avaliable_SFR
+ if {![string is digit -strict $P_option_mcu_xdata] || $P_option_mcu_xdata > 0xFFFF} {
+ set P_option_mcu_xdata 0
+ puts "Invalid XDATA capacity -- setting to 0"
+ }
+ if {
+ ![string is digit -strict $P_option_mcu_xcode]
+ ||
+ $P_option_mcu_xcode > [expr {0xFFFF - ([lindex $procData 2] * 1024)}]
+ } {
+ set P_option_mcu_xcode 0
+ puts "Invalid XCODE capacity -- setting to 0"
+ }
+ if {[lindex $procData 0] != {yes}} {
+ set P_option_mcu_xdata 0
+ }
+ if {[lindex $procData 1] != {yes}} {
+ set P_option_mcu_xcode 0
+ }
+ if {[regexp {^\d+$} $P_option_clock]} {
+ if {$P_option_clock > 99999} {
+ set P_option_clock [lindex ${X::project_edit_defaults} {1 1}]
+ puts stderr "Clock value must be below 99999 -- setting to [lindex ${X::project_edit_defaults} {1 1}]"
+ }
+ } {
+ set P_option_clock [lindex ${X::project_edit_defaults} {1 1}]
+ puts stderr "Invalid clock value -- setting to [lindex ${X::project_edit_defaults} {1 1}]"
+ }
+ if {![string is boolean -strict $editor_sw_lock]} {
+ puts stderr "Invalid file switching lock value -- setting to 1"
+ set editor_sw_lock 1
+ }
+
+ # set some object variables
+ set projectPath $projectpath
+ set projectFile $projectfile
+
+ # create higher-level container
+ set mainTab [.mainFrame.mainNB insert end \
+ [string trimleft $this {:}] \
+ -text $projectName \
+ -image ::ICONS::16::kcmdevices \
+ -raisecmd "X::switch_project $this" \
+ ]
+
+ # Some workaround -- only a "cosmetic" matter
+ catch {
+ .mainFrame.mainNB.c bind p:[string trimleft $this {:}] <Enter> {}
+ }
+
+ # create paned windows
+ set main_Pane [panedwindow $mainTab.main_Pane \
+ -orient vertical \
+ -sashwidth 2 \
+ -showhandle 0 \
+ -opaqueresize 1 \
+ -sashrelief flat \
+ ]
+ set top_Pane [panedwindow $main_Pane.top_Pane \
+ -orient horizontal \
+ -sashwidth 2 \
+ -showhandle 0 \
+ -opaqueresize 1 \
+ -sashrelief flat \
+ ]
+ set fileList_Pane [panedwindow $top_Pane.fileList_Pane \
+ -orient horizontal \
+ -sashwidth 2 \
+ -showhandle 0 \
+ -opaqueresize 1 \
+ -sashrelief flat \
+ ]
+
+ # Initalize mainTab
+ set bottom_pane [frame $main_Pane.bottomNB]
+ set rightPanel [frame $top_Pane.rightPanel]
+
+ # Insert all widgets at places where there should be
+ $top_Pane add $fileList_Pane
+ $top_Pane add $rightPanel
+ $main_Pane add $top_Pane
+ $main_Pane add $bottom_pane
+
+ # Intialize all panels
+ simulator_initialize_mcu
+ Initialize_rightPanel $rightPanel $top_Pane $watches_file
+ initiate_BottomNoteBook $bottom_pane $main_Pane $todoText $calculatorList $graphList
+ initiate_FileList $fileList_Pane $projectPath $projectFiles $editor_sw_lock
+
+ # Adjust progress dialog invoked from procedure initiate_FileList
+ catch {.prgDl configure -command {puts stderr "Unable to abort at this stage !"}}
+ set ::FileList::open_files_cur_file {Finishing ...}
+
+ # Pack main pane
+ pack $main_Pane -expand 1 -fill both
+
+ # Raise last tab in mainNB
+ .mainFrame.mainNB raise [string trimleft $this {:}]
+
+ # Take care of proper geometry management
+ bottomNB_redraw_pane
+ right_panel_redraw_pane
+ todo_panel_redraw_pane
+ filelist_adjust_size_of_tabbar
+
+ # Highlight all loaded source codes, import breakpoints and bookmarks etc.
+ filelist_global_highlight
+
+ ensure_that_both_editors_are_properly_initialized
+
+ # Load scenario file
+ if {[pale_open_scenario $scenario_file] == 1} {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to open VHW file:\n\"%s\"" $filename]
+ }
+
+ # (just workaround ...)
+ $this rightPanel_refresh_font_settings 1
+
+ # Destroy progress dialog invoked from procedure initiate_FileList
+ catch {destroy .prgDl}
+ }
+
+ ## Object destructor
+ destructor {
+ .mainFrame.mainNB delete [string trimleft $this {:}]
+ }
+
+ ## Kill all child processes
+ # @return void
+ public method kill_childern {} {
+ $this terminal_kill_childern
+ $this filelist_kill_childern
+ $this hw_man_kill_childern
+ }
+
+ ## Refresh list of avaliable SFR and SFB
+ # @return void
+ public method refresh_project_avaliable_SFR {} {
+ set avaliable_SFR [concat [lindex $procData 43] {
+ R0 R1 R2 R3 R4 R5 R6 R7
+ B ACC A TMOD TH0 TH1 SP DPL DPH PCON
+ TL0 TL1 AB DPTR
+ RXD TXD INT0 INT1 T0 T1 WR RD
+
+ PSW C CY AC F0 RS1 RS0 OV P
+ IE EA ET1 EX1 ET0 EX0
+ IP PT1 PX1 PT0 PX0
+ TCON TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
+ }] ;# REGISTER BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0
+
+ foreach editor [$this cget -editors] {
+ $editor refresh_avaliable_SFR
+ }
+ }
+
+ ## Adjust the compilers settings to the current project configuration
+ # @return void
+ public method adjust_compiler_settings {} {
+ # Native assembler
+ foreach key [array names PCC_native_assembler] {
+ set ::Compiler::Settings::$key $PCC_native_assembler($key)
+ }
+
+ ## Preferred assembler
+ set ::ExternalCompiler::selected_assembler $PCC_selected_assembler
+ ## ASEM-51
+ array set ::ExternalCompiler::assembler_ASEM51_config \
+ [array get PCC_ASEM51_config]
+ array set ::ExternalCompiler::assembler_ASEM51_addcfg \
+ [array get PCC_ASEM51_addcfg]
+ ## ASL
+ array set ::ExternalCompiler::assembler_ASL_config \
+ [array get PCC_ASL_config]
+ array set ::ExternalCompiler::assembler_ASL_addcfg \
+ [array get PCC_ASL_addcfg]
+ ## AS31
+ array set ::ExternalCompiler::assembler_AS31_config \
+ [array get PCC_AS31_config]
+ array set ::ExternalCompiler::assembler_AS31_addcfg \
+ [array get PCC_AS31_addcfg]
+ ## SDCC
+ # Copy boolean options
+ array set ::ExternalCompiler::sdcc_bool_options \
+ [array get PCC_sdcc_bool_opt]
+ # Copy string options
+ array set ::ExternalCompiler::sdcc_string_options \
+ [array get PCC_sdcc_str_opt]
+ # Copy optional strings
+ array set ::ExternalCompiler::sdcc_optional_string_options \
+ [array get PCC_sdcc_opt_str_opt]
+ # Copy semicolon separated optional string options
+ array set ::ExternalCompiler::sdcc_scs_string_options \
+ [array get PCC_sdcc_scs_str_opt]
+ }
+
+ ## Adjust the current project configuration to the compilers settings
+ # @return void
+ public method retrieve_compiler_settings {} {
+ # Native assembler
+ foreach key ${::configDialogs::compiler::defaults} {
+ set key [lindex $key 0]
+ set PCC_native_assembler($key) [subst "\$::Compiler::Settings::$key"]
+ }
+ set PCC_native_assembler(WARNING_LEVEL) \
+ ${::Compiler::Settings::WARNING_LEVEL}
+ set PCC_native_assembler(max_ihex_rec_length) \
+ ${::Compiler::Settings::max_ihex_rec_length}
+
+ ## Preferred assembler
+ set PCC_selected_assembler $::ExternalCompiler::selected_assembler
+ ## ASEM-51
+ array set PCC_ASEM51_config \
+ [array get ::ExternalCompiler::assembler_ASEM51_config]
+ array set PCC_ASEM51_addcfg \
+ [array get ::ExternalCompiler::assembler_ASEM51_addcfg]
+ ## ASL
+ array set PCC_ASL_config \
+ [array get ::ExternalCompiler::assembler_ASL_config]
+ array set PCC_ASL_addcfg \
+ [array get ::ExternalCompiler::assembler_ASL_addcfg]
+ ## AS31
+ array set PCC_AS31_config \
+ [array get ::ExternalCompiler::assembler_AS31_config]
+ array set PCC_AS31_addcfg \
+ [array get ::ExternalCompiler::assembler_AS31_addcfg]
+
+ ## SDCC
+ # Copy boolean options
+ array set PCC_sdcc_bool_opt \
+ [array get ::ExternalCompiler::sdcc_bool_options]
+ # Copy string options
+ array set PCC_sdcc_str_opt \
+ [array get ::ExternalCompiler::sdcc_string_options]
+ # Copy optional strings
+ array set PCC_sdcc_opt_str_opt \
+ [array get ::ExternalCompiler::sdcc_optional_string_options]
+ # Copy semicolon separated optional string options
+ array set PCC_sdcc_scs_str_opt \
+ [array get ::ExternalCompiler::sdcc_scs_string_options]
+ }
+
+ ## Get compilers configuration (intended for project saving)
+ # @return void
+ public method get_compiler_config {} {
+ return [list \
+ [array get PCC_native_assembler]\
+ $PCC_selected_assembler \
+ [array get PCC_ASEM51_config] \
+ [array get PCC_ASEM51_addcfg] \
+ [array get PCC_ASL_config] \
+ [array get PCC_ASL_addcfg] \
+ [array get PCC_sdcc_bool_opt] \
+ [array get PCC_sdcc_str_opt] \
+ [array get PCC_sdcc_opt_str_opt]\
+ [array get PCC_sdcc_scs_str_opt]\
+ [array get PCC_AS31_config] \
+ [array get PCC_AS31_addcfg] \
+ ]
+ }
+}
diff --git a/lib/pale/leddisplay.tcl b/lib/pale/leddisplay.tcl
new file mode 100755
index 0000000..55b13a5
--- /dev/null
+++ b/lib/pale/leddisplay.tcl
@@ -0,0 +1,707 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements PALE VHW component "LED display"
+#
+# Consists of:
+# INTERNAL APPLICATION LOGIC
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM PALE ENGINE
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+# --------------------------------------------------------------------------
+
+class LedDisplay {
+ inherit VirtualHWComponent
+
+ # Font: Font to be used in the panel -- bold
+ common cb_font [font create -weight bold -size -10 -family {helvetica}]
+ common COMPONENT_NAME "LED Display" ;# Name of this component
+ common CLASS_NAME "LedDisplay" ;# Name of this class
+ common COMPONENT_ICON {leddisplay} ;# Icon for this panel (16x16)
+
+ ## Colors for display segments
+ # There are 6 lists (red orange yellow green blue purple)
+ # and each of them contain 3 colors (semi-dim bright dim)
+ common COLORS {
+ {#AA5555 #FF0000}
+ {#AAAA55 #FF8800}
+ {#AAAA55 #FFFF00}
+
+ {#55AA55 #00FF00}
+ {#5555AA #0000FF}
+ {#AA55AA #8800FF}
+ }
+
+ # Configuration menu
+ common CONFMENU {
+ {cascade {Common electrode} 7 "diode" .ca false 1 {
+ {radiobutton "Common anode" {}
+ ::LedDisplay::cfg_common_anode 1
+ "common_electrode_chanded" 7 ""}
+ {radiobutton "Common catode" {}
+ ::LedDisplay::cfg_common_anode 0
+ "common_electrode_chanded" 7 ""}
+ }}
+ {cascade {Color} 0 "colorize" .color false 1 {
+ {radiobutton "Red" {}
+ ::LedDisplay::color {red}
+ "color_changed" 0 ""}
+ {radiobutton "Orange" {}
+ ::LedDisplay::color {orange}
+ "color_changed" 0 ""}
+ {radiobutton "Yellow" {}
+ ::LedDisplay::color {yellow}
+ "color_changed" 0 ""}
+ {radiobutton "Green" {}
+ ::LedDisplay::color {green}
+ "color_changed" 0 ""}
+ {radiobutton "Blue" {}
+ ::LedDisplay::color {blue}
+ "color_changed" 0 ""}
+ {radiobutton "Purple" {}
+ ::LedDisplay::color {purple}
+ "color_changed" 0 ""}
+ }}
+ {separator}
+ {command {Show help} {} 5 "show_help" {help}
+ "Show brief help"}
+ {separator}
+ {command {Save configuration} {} 0 "save_as" {filesave}
+ "Save configuration into a file"}
+ {command {Load configuration} {} 0 "load_from" {fileopen}
+ "Load configuration from a file"}
+ }
+
+ private variable conf_led_color {red} ;# Color: Selected color for LED's
+
+ private variable leds ;# Array of CanvasObject (polygon): leds(segment_num) --> LED polygon
+ private variable wires ;# Array of CanvasObject (line): Wire connection LED with uC
+ private variable connection_port ;# Array of Int: Index is key number, value is port number or {-}
+ private variable connection_pin ;# Array of Int: Index is key number, value is bit number or {-}
+ private variable common_anode 1 ;# Bool: 1 == common anode; 0 == common catode
+
+ # ------------------------------------------------------------------
+ # INTERNAL APPLICATION LOGIC
+ # ------------------------------------------------------------------
+
+ ## Object constructor
+ # @parm Object _project - Project object
+ constructor {_project} {
+ # Set object variables identifing this component (see the base class)
+ set component_name $COMPONENT_NAME
+ set class_name $CLASS_NAME
+ set component_icon $COMPONENT_ICON
+
+ # Set other object variables
+ set project $_project
+ array set connection_port {0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -}
+ array set connection_pin {0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -}
+
+ # Inform PALE
+ $project pale_register_output_device $this
+ $project pale_set_modified
+
+ # Create panel GUI
+ create_gui
+ mcu_changed
+ on_off [$project pale_is_enabled]
+
+ # ComboBoxes to default state
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_b$i current 0
+ $canvas_widget.cb_p$i current 0
+ }
+ }
+
+ ## Object destructor
+ destructor {
+ # Inform PALE
+ $project pale_unregister_output_device $this
+
+ # Destroy GUI
+ destroy $win
+ }
+
+ ## Create GUI of this panel
+ # @return void
+ private method create_gui {} {
+ # Create panel window and canvas widget
+ set win [toplevel .leddisplay$count -class $component_name -bg {#EEEEEE}]
+ set canvas_widget [canvas $win.canvas \
+ -bg white -width 0 -height 0 \
+ -highlightthickness 0 \
+ ]
+
+ # Draw display and wires
+ draw_8_segment 85 30
+ draw_wires 0 -10
+
+ # Create ComboBoxes
+ set cb_p_x0 200
+ set cb_b_x0 200
+ set cb_p_x1 40
+ set cb_b_x1 40
+ set y_0 30
+ set y_1 120
+ set y_inc 30
+ for {set i 0} {$i < 8} {incr i} {
+ if {$i == 0} {
+ set y $y_0
+ set cb_p_x $cb_p_x0
+ set cb_b_x $cb_b_x0
+ } elseif {$i == 4} {
+ set y $y_1
+ set y_inc -$y_inc
+ set cb_p_x $cb_p_x1
+ set cb_b_x $cb_b_x1
+ }
+
+ $canvas_widget create window $cb_p_x $y -anchor e \
+ -window [ttk::combobox $canvas_widget.cb_p$i \
+ -width 1 \
+ -font $cb_font \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_p$i <<ComboboxSelected>> "$this reconnect $i"
+
+ $canvas_widget create window $cb_b_x $y -anchor w \
+ -window [ttk::combobox $canvas_widget.cb_b$i \
+ -width 1 \
+ -font $cb_font \
+ -values {- 0 1 2 3 4 5 6 7} \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_b$i <<ComboboxSelected>> "$this reconnect $i"
+
+ bindtags $canvas_widget.cb_p$i \
+ [list $canvas_widget.cb_p$i TCombobox all .]
+ bindtags $canvas_widget.cb_b$i \
+ [list $canvas_widget.cb_b$i TCombobox all .]
+
+ incr y $y_inc
+ }
+
+ # Create "ON/OFF" button
+ set start_stop_button [ttk::button $canvas_widget.start_stop_button \
+ -command "$this on_off_button_press" \
+ -style Flat.TButton \
+ -width 3 \
+ ]
+ DynamicHelp::add $canvas_widget.start_stop_button \
+ -text [mc "Turn HW simulation on/off"]
+ setStatusTip -widget $start_stop_button -text [mc "Turn HW simulation on/off"]
+ bind $start_stop_button <Button-3> "$this on_off_button_press; break"
+ $canvas_widget create window 115 2 -window $start_stop_button -anchor nw
+ bindtags $start_stop_button [list $start_stop_button TButton all .]
+
+ # Create configuration menu button
+ set conf_button [ttk::button $canvas_widget.conf_but \
+ -image ::ICONS::16::configure \
+ -style FlatWhite.TButton \
+ -command "$this config_menu" \
+ ]
+ setStatusTip -widget $conf_button -text [mc "Configure"]
+ $canvas_widget create window 113 2 -window $conf_button -anchor ne
+ bindtags $conf_button [list $conf_button TButton all .]
+
+ # Print labels
+ $canvas_widget create text 40 5 \
+ -text [mc "PORT"] \
+ -font $cb_font \
+ -anchor ne
+ $canvas_widget create text 50 5 \
+ -text [mc "BIT"] \
+ -font $cb_font \
+ -anchor nw
+ $canvas_widget create text 200 5\
+ -text [mc "PORT"] \
+ -font $cb_font \
+ -anchor ne
+ $canvas_widget create text 210 5\
+ -text [mc "BIT"] \
+ -font $cb_font \
+ -anchor nw
+
+ $canvas_widget create text 5 155\
+ -text [mc "Note"] \
+ -font $cb_font \
+ -anchor w
+ $canvas_widget create window 40 155 \
+ -window [ttk::entry $canvas_widget.usr_note \
+ -validate all \
+ -validatecommand "$this set_modified" \
+ ] \
+ -width 180 -anchor w
+ bindtags $canvas_widget.usr_note \
+ [list $canvas_widget.usr_note TEntry $win all .]
+
+ # Pack canvas
+ pack $canvas_widget -fill both -expand 1
+
+ # Set window parameters
+ wm geometry $win =230x170
+ wm iconphoto $win ::ICONS::16::$component_icon
+ wm title $win "[mc $component_name] - [string trim $project {:}] - MCU 8051 IDE"
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "$this close_window"
+ bindtags $win [list $win Toplevel all .]
+ }
+
+ ## Reconnect the specified LED to another port pin
+ # @parm Int i - LED number (0..7)
+ # @return void
+ public method reconnect {i} {
+ # Adjust connections
+ set connection_port($i) [$canvas_widget.cb_p$i get]
+ set connection_pin($i) [$canvas_widget.cb_b$i get]
+ if {$connection_pin($i) != {-}} {
+ set connection_pin($i) [expr {7 - $connection_pin($i)}]
+ }
+
+ # Change state of the device
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state]
+ }
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## LED's common electrode chanded
+ # @return void
+ public method common_electrode_chanded {} {
+ set common_anode ${::LedDisplay::cfg_common_anode}
+
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state]
+ }
+ set_modified
+ }
+
+ ## LED color changed
+ # @return void
+ public method color_changed {} {
+ set conf_led_color ${::LedDisplay::color}
+
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state]
+ }
+ set_modified
+ }
+
+ ## Draw wires conneting LED's with uC (ComboBoxes)
+ # @parm Int x - X origin coordinate
+ # @parm Int y - Y origin coordinate
+ # @return void
+ private method draw_wires {x y} {
+ set coords {
+ {
+ 120 40 180 40
+ } {
+ 145 70 180 70
+ } {
+ 140 100 180 100
+ } {
+ 110 125 110 130 180 130
+ } {
+ 87 110 82 110 82 130 50 130
+ } {
+ 91 75 82 75 82 100 50 100
+ } {
+ 116 78 116 70 50 70
+ } {
+ 138 125 138 150 5 150 5 40 30 40
+ }
+ }
+
+ # Transform coordinates -- adjust them to the given origin
+ #+ Draw wires
+ for {set i 0} {$i < 8} {incr i} {
+ set coordinates [list]
+ set local_coords [lindex $coords $i]
+ set len [llength $local_coords]
+
+ # Adjust
+ for {set m 0; set n 1} {$n < $len} {incr m 2; incr n 2} {
+ lappend coordinates \
+ [expr {[lindex $local_coords $m] + $x}]
+ lappend coordinates \
+ [expr {[lindex $local_coords $n] + $y}]
+ }
+
+ # Draw
+ set wires($i) [$canvas_widget create line \
+ $coordinates -width 1 -fill #000000 \
+ ]
+ }
+ }
+
+ ## Draw LED display
+ # @parm Int x - X origin coordinate
+ # @parm Int y - Y origin coordinate
+ # @return void
+ private method draw_8_segment {x y} {
+ set coords {
+ {
+ 19 7 25 1 47 1 53 7 53 8
+ 47 14 25 14 19 8
+ } {
+ 55 9 62 16 58 34 50 42 44 36
+ 49 15 55 9
+ } {
+ 50 45 57 52 53 70 46 77 45 77
+ 39 71 44 51 50 45
+ } {
+ 15 73 38 73 44 79 37 86 15 86
+ 9 80 9 79
+ } {
+ 7 78 15 70 19 52 12 45 5 52
+ 1 72
+ } {
+ 12 42 20 34 25 16 17 9 10 16
+ 6 36
+ } {
+ 14 43 20 37 42 37 48 43 48 44
+ 42 50 20 50 14 44
+ }
+ }
+
+ # Transform coordinates -- adjust them to the given origin
+ #+ Draw LED polygons -- for segments A..G
+ for {set i 0} {$i < 7} {incr i} {
+ set coordinates [list]
+ set local_coords [lindex $coords $i]
+ set len [llength $local_coords]
+
+ # Adjust
+ for {set m 0; set n 1} {$n < $len} {incr m 2; incr n 2} {
+ lappend coordinates \
+ [expr {[lindex $local_coords $m] + $x}]
+ lappend coordinates \
+ [expr {[lindex $local_coords $n] + $y}]
+ }
+
+ # Draw
+ set leds($i) [$canvas_widget create polygon \
+ $coordinates -width 0 -fill #888888 \
+ ]
+ }
+
+ # Transform coordinates -- adjust them to the given origin
+ #+ Draw LED oval -- for segment P (point)
+ set leds(7) [$canvas_widget create oval \
+ [expr {49 + $x}] [expr {77 + $y}] \
+ [expr {58 + $x}] [expr {86 + $y}] \
+ -width 0 -fill #888888 \
+ ]
+
+ # Print segment labels
+ foreach coords {{35 7} {53 25} {48 62} {26 79} {10 61} {15 25} {31 43}} \
+ text {A B C D E F G} \
+ {
+ $canvas_widget create text \
+ [expr {[lindex $coords 0] + $x}] \
+ [expr {[lindex $coords 1] + $y}] \
+ -text $text -fill {#FFFFFF} \
+ -font $::smallfont
+ }
+ }
+
+ ## Determinate which port pin is connected to the specified LED
+ # @parm Int i - LED number
+ # @return List - {port_number bit_number}
+ private method which_port_pin {i} {
+ return [list $connection_port($i) $connection_pin($i)]
+ }
+
+ ## Handle "ON/OFF" button press
+ # Turn whole PALE system on or off
+ # @return void
+ public method on_off_button_press {} {
+ $project pale_all_on_off
+ }
+
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE
+ # ------------------------------------------------------------------
+
+ ## Simulated MCU has been changed
+ # @return void
+ public method mcu_changed {} {
+ # Refresh lists of possible values in port selection ComboBoxes
+ set avaliable_ports [concat - [$project pale_get_avaliable_ports]]
+
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_p$i configure -values $avaliable_ports
+
+ if {[lsearch -ascii -exact $avaliable_ports $connection_port($i)] == -1} {
+ $canvas_widget.cb_p$i current 0
+ set connection_port($i) {-}
+ }
+ }
+ }
+
+ ## Accept new state of ports
+ # @parm List state - Port states ( 5 x {8 x bit} -- {bit0 bit1 bit2 ... bit7} )
+ # @return void
+ #
+ # Possible bit values:
+ # '|' - High frequency
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ # '0' - Logical 0
+ # '1' - Logical 1
+ public method new_state {state} {
+ # Determinate index of LED color in list COLORS
+ set color_idx [lsearch -ascii -exact \
+ {red orange yellow green blue purple} \
+ $conf_led_color \
+ ]
+
+ # Iterate over 8 segments
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin $i]
+
+ # Not connected
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ $canvas_widget itemconfigure $leds($i) -fill {#888888}
+ $canvas_widget itemconfigure $wires($i) -fill {#000000}
+ continue
+ }
+
+ # Determinate wire and LED color
+ switch -- [lindex $state $pp] {
+ {0} { ;# Logical 0
+ if {$common_anode} {
+ set segment_color {2}
+ } {
+ set segment_color {0}
+ }
+ set wire_color {#00FF00}
+ }
+ {1} { ;# Logical 1
+ if {$common_anode} {
+ set segment_color {0}
+ } {
+ set segment_color {2}
+ }
+ set wire_color {#FF0000}
+ }
+ {=} { ;# High forced to low
+ set segment_color {0}
+ set wire_color {#FF00AA}
+ }
+ {} { ;# Not connected
+ set segment_color {0}
+ set wire_color {#000000}
+ }
+ {?} { ;# No volatge
+ set segment_color {0}
+ set wire_color {#888888}
+ }
+ default {
+ set segment_color {1}
+ set wire_color {#FF8800}
+ }
+ }
+
+ # Determinate segment color (true color, not just number)
+ if {!$segment_color} {
+ set segment_color {#888888}
+ } {
+ incr segment_color -1
+ set segment_color [lindex $COLORS [list $color_idx $segment_color]]
+ }
+
+ # Change segment and wire color
+ $canvas_widget itemconfigure $leds($i) -fill $segment_color
+ $canvas_widget itemconfigure $wires($i) -fill $wire_color
+ }
+ }
+
+ ## Withdraw panel window from the screen
+ # @return void
+ public method withdraw_window {} {
+ wm withdraw $win
+ }
+
+ ## Get panel configuration list (usable with method "set_config")
+ # @return List - configuration list
+ public method get_config {} {
+ return [list \
+ $class_name \
+ [list \
+ [array get connection_port] \
+ [array get connection_pin] \
+ [wm geometry $win] \
+ [$canvas_widget.usr_note get] \
+ $conf_led_color \
+ $common_anode \
+ ] \
+ ]
+ }
+
+ ## Set panel configuration from list gained from method "get_config"
+ # @parm List state - Configuration list
+ # @return void
+ public method set_config {state} {
+ if {[catch {
+ # Load connections to the MCU
+ array set connection_port [lindex $state 0]
+ array set connection_pin [lindex $state 1]
+
+ # Restore window geometry
+ if {[string length [lindex $state 2]]} {
+ wm geometry $win [lindex $state 2]
+ }
+
+ # Load user note
+ $canvas_widget.usr_note delete 0
+ $canvas_widget.usr_note insert 0 [lindex $state 3]
+
+ # Restore LED's configuration
+ set conf_led_color [lindex $state 4]
+ set common_anode [lindex $state 5]
+ if {$common_anode == {}} {
+ set common_anode 1
+ }
+
+ # Restore state of ComboBoxes
+ for {set i 0} {$i < 8} {incr i} {
+ ## PIN
+ set pin $connection_pin($i)
+ if {$pin != {-}} {
+ set pin [expr {7 - $pin}]
+ }
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_b$i cget -values] \
+ $pin \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_b$i current $idx
+
+ ## PORT
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_p$i cget -values] \
+ $connection_port($i) \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_p$i current $idx
+ }
+
+ # Accept new state of ports
+ new_state [$project pale_get_true_state]
+ update
+
+ # Fail
+ }]} then {
+ puts "Unable to load config for $class_name"
+ return 0
+
+ # Success
+ } else {
+ clear_modified
+ return 1
+ }
+ }
+
+ ## Simulated MCU has been reseted
+ # @return void
+ public method reset {} {
+ new_state [$project pale_get_true_state]
+ }
+
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+ # ------------------------------------------------------------------
+
+ ## This method is called before configuration menu invocation
+ # @return void
+ public method config_menu_special {} {
+ set ::${class_name}::color $conf_led_color
+ set ::${class_name}::cfg_common_anode $common_anode
+ }
+
+ ## This method is called after configuration menu has beed created
+ # @return void
+ public method create_config_menu_special {} {
+ foreach item { Red Orange Yellow Green Blue Purple } \
+ color { #DD0000 #DD8800 #DDDD00 #00DD00 #0000DD #8800DD } \
+ {
+ $conf_menu.color entryconfigure [::mc $item] -foreground $color
+ }
+ }
+
+ ## This method is called to fill in the help dialog
+ # @parm Widget text_widget - Target text widget
+ # @return void
+ #
+ # Note: There is defined text tag "tag_bold" in the text widget
+ public method show_help_special {text_widget} {
+ $text_widget insert insert [mc "Virtual LED display with common anode (default) or catode. Each segment can be connected to any port pin of the simulated uC. Connections with the uC are made with ComboBoxes on the bottom of the panel. Panel configuration can be saved to a file (with extension vhc). And can be loaded from that file later.\n\n"]
+
+ set color_idx [lsearch -ascii -exact \
+ {red orange yellow green blue purple} \
+ $conf_led_color \
+ ]
+
+ $text_widget insert insert [mc "LED states:"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc "\n "]
+ $text_widget window create insert -pady 1 -create "frame $text_widget.f0 -bd 1 -width 14 -height 16 -bg #888888"
+ $text_widget insert insert [mc " Off\n "]
+ $text_widget window create insert -pady 1 -create "frame $text_widget.f1 -bd 1 -width 14 -height 16 -bg [lindex $COLORS [list $color_idx 0]]"
+ $text_widget insert insert [mc " Fast blinking\n "]
+ $text_widget window create insert -pady 1 -create "frame $text_widget.f2 -bd 1 -width 14 -height 16 -bg [lindex $COLORS [list $color_idx 1]]"
+ $text_widget insert insert [mc " Shining\n "]
+ }
+
+ ## This method is called before panel window closure
+ # @return void
+ public method close_window_special {} {
+ }
+
+ ## Commit new on/off state
+ # @return void
+ public method on_off_special {} {
+ if {!$drawing_on} {
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget itemconfigure $leds($i) -fill {#888888}
+ $canvas_widget itemconfigure $wires($i) -fill {#000000}
+ }
+ } {
+ new_state [$project pale_get_true_state]
+ }
+ }
+}
diff --git a/lib/pale/ledmatrix.tcl b/lib/pale/ledmatrix.tcl
new file mode 100755
index 0000000..b739f53
--- /dev/null
+++ b/lib/pale/ledmatrix.tcl
@@ -0,0 +1,982 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements PALE VHW component "LED matrix"
+#
+# Consists of:
+# INTERNAL APPLICATION LOGIC
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM PALE ENGINE
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+# --------------------------------------------------------------------------
+
+class LedMatrix {
+ inherit VirtualHWComponent
+
+ # Font: Font to be used in the panel -- bold
+ common cb_font [font create -weight bold -size -10 -family {helvetica}]
+ common COMPONENT_NAME "LED matrix" ;# Name of this component
+ common CLASS_NAME "LedMatrix" ;# Name of this class
+ common COMPONENT_ICON {ledmatrix} ;# Icon for this panel (16x16)
+
+ # Configuration menu
+ common CONFMENU {
+ {cascade {Fade out interval} 5 "player_time" .dim false 1 {
+ {radiobutton "0" {}
+ ::LedMatrix::dim_interval 0
+ "dim_interval_changed" -1
+ "Set LED dim interval to 0 instruction cycles"}
+ {radiobutton "5" {}
+ ::LedMatrix::dim_interval 5
+ "dim_interval_changed" -1
+ "Set LED dim interval to 5 instruction cycles"}
+ {radiobutton "10" {}
+ ::LedMatrix::dim_interval 10
+ "dim_interval_changed" -1
+ "Set LED dim interval to 10 instruction cycles"}
+ {radiobutton "20" {}
+ ::LedMatrix::dim_interval 20
+ "dim_interval_changed" -1
+ "Set LED dim interval to 20 instruction cycles"}
+ {radiobutton "50" {}
+ ::LedMatrix::dim_interval 50
+ "dim_interval_changed" -1
+ "Set LED dim interval to 50 instruction cycles"}
+ {radiobutton "100" {}
+ ::LedMatrix::dim_interval 100
+ "dim_interval_changed" -1
+ "Set LED dim interval to 100 instruction cycles"}
+ {radiobutton "200" {}
+ ::LedMatrix::dim_interval 200
+ "dim_interval_changed" -1
+ "Set LED dim interval to 200 instruction cycles"}
+ {radiobutton "500" {}
+ ::LedMatrix::dim_interval 500
+ "dim_interval_changed" -1
+ "Set LED dim interval to 500 instruction cycles"}
+ {radiobutton "1000" {}
+ ::LedMatrix::dim_interval 1000
+ "dim_interval_changed" -1
+ "Set LED dim interval to 1000 instruction cycles"}
+ }}
+ {cascade {Mapping} 5 "matrix2" .mapping false 1 {
+ {radiobutton "Random" {}
+ ::LedMatrix::matrix_mapping 0
+ "matrix_mapping_changed" -1
+ "Random access to the matrix (default)"}
+ {radiobutton "Row" {}
+ ::LedMatrix::matrix_mapping 1
+ "matrix_mapping_changed" -1
+ "When a particular row is activated, it's previous state is forgotten"}
+ {radiobutton "Column" {}
+ ::LedMatrix::matrix_mapping 2
+ "matrix_mapping_changed" -1
+ "When a particular column is activated, it's previous state is forgotten"}
+ }}
+ {cascade {Color} 0 "colorize" .color false 1 {
+ {radiobutton "Red" {}
+ ::LedMatrix::color {red}
+ "color_changed" 0 ""}
+ {radiobutton "Orange" {}
+ ::LedMatrix::color {orange}
+ "color_changed" 0 ""}
+ {radiobutton "Yellow" {}
+ ::LedMatrix::color {yellow}
+ "color_changed" 0 ""}
+ {radiobutton "Green" {}
+ ::LedMatrix::color {green}
+ "color_changed" 0 ""}
+ {radiobutton "Blue" {}
+ ::LedMatrix::color {blue}
+ "color_changed" 0 ""}
+ {radiobutton "Purple" {}
+ ::LedMatrix::color {purple}
+ "color_changed" 0 ""}
+ }}
+ {cascade {Light up when} 0 "ledgreen" .cond false 1 {
+ {radiobutton "Row 0 & Column 0" {}
+ ::LedMatrix::cond {0 0}
+ "cond_changed" 0
+ "Light up LED when both wires are in low"}
+ {radiobutton "Row 0 & Column 1" {}
+ ::LedMatrix::cond {0 1}
+ "cond_changed" 0
+ "Light up LED when row wire is in low and column wire is in high"}
+ {radiobutton "Row 1 & Column 0" {}
+ ::LedMatrix::cond {1 0}
+ "cond_changed" 0
+ "Light up LED when row wire is in high and column wire is in low"}
+ {radiobutton "Row 1 & Column 1" {}
+ ::LedMatrix::cond {1 1}
+ "cond_changed" 0
+ "Light up LED when both wires are in high"}
+ }}
+ {separator}
+ {command {All fade out} {} 0 "dim_all" {ledgray}
+ "Dim all leds"}
+ {command {Show help} {} 5 "show_help" {help}
+ "Show brief help"}
+ {separator}
+ {command {Save configuration} {} 0 "save_as" {filesave}
+ "Save configuration into a file"}
+ {command {Load configuration} {} 0 "load_from" {fileopen}
+ "Load configuration from a file"}
+ }
+
+ private variable conf_dim_interval 50 ;# Int: Interval to dim LED's in instruction cycles
+ private variable conf_matrix_mapping 0 ;# Int: Type of matrix mapping: 0 == Random; 1 == Row; 2 == Column
+ private variable conf_led_color {red} ;# Color: Selected color for LED's
+ ## List of Bool: LED light up condition
+ # Index 0 - Row must be in: 1 == log. 1; 0 = log. 0
+ # Index 1 - Column must be in: 1 == log. 1; 0 = log. 0
+ private variable conf_led_cond {0 0}
+ private variable leds ;# Array of CanvasObject (image): LED's, leds(row,column)
+ private variable col ;# Array of CanvasObject (line): Column wires
+ private variable row ;# Array of CanvasObject (line): Row wires
+ private variable prev_state ;# List: Previous port states
+ private variable connection_port ;# Array of Int: Index is key number, value is port number or {-}
+ private variable connection_pin ;# Array of Int: Index is key number, value is bit number or {-}
+
+
+ # ------------------------------------------------------------------
+ # INTERNAL APPLICATION LOGIC
+ # ------------------------------------------------------------------
+
+ ## Object constructor
+ # @parm Object _project - Project object
+ constructor {_project} {
+ # Set object variables identifing this component (see the base class)
+ set component_name $COMPONENT_NAME
+ set class_name $CLASS_NAME
+ set component_icon $COMPONENT_ICON
+
+ # Set other object variables
+ set project $_project
+ array set connection_port {
+ R0 - R1 - R2 - R3 - R4 - R5 - R6 - R7 -
+ C0 - C1 - C2 - C3 - C4 - C5 - C6 - C7 -
+ }
+ array set connection_pin {
+ R0 - R1 - R2 - R3 - R4 - R5 - R6 - R7 -
+ C0 - C1 - C2 - C3 - C4 - C5 - C6 - C7 -
+ }
+ for {set j 0} {$j < 8} {incr j} {
+ for {set i 0} {$i < 8} {incr i} {
+ set prev_state($j,$i) 0
+ }
+ }
+
+ # Inform PALE
+ $project pale_register_output_device $this
+ $project pale_set_modified
+
+ # Create panel GUI
+ create_gui
+ mcu_changed
+ on_off [$project pale_is_enabled]
+
+ # ComboBoxes to default state
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_r_b$i current 0
+ $canvas_widget.cb_r_p$i current 0
+
+ $canvas_widget.cb_c_b$i current 0
+ $canvas_widget.cb_c_p$i current 0
+ }
+ }
+
+ ## Object destructor
+ destructor {
+ # Inform PALE
+ $project pale_unregister_output_device $this
+
+ # Destroy GUI
+ destroy $win
+ }
+
+ ## Reconnect the specified wire to another port pin
+ # @parm Char col_or_row - 'C' => Column; 'R' => Row
+ # @parm Int i - Wire number (0..7)
+ # @return void
+ public method reconnect {col_or_row i} {
+ # Row
+ if {$col_or_row == {R}} {
+ set connection_port(R$i) [$canvas_widget.cb_r_p$i get]
+ set connection_pin(R$i) [$canvas_widget.cb_r_b$i get]
+ if {$connection_pin(R$i) != {-}} {
+ set connection_pin(R$i) [expr {7 - $connection_pin(R$i)}]
+ }
+ # Column
+ } {
+ set connection_port(C$i) [$canvas_widget.cb_c_p$i get]
+ set connection_pin(C$i) [$canvas_widget.cb_c_b$i get]
+ if {$connection_pin(C$i) != {-}} {
+ set connection_pin(C$i) [expr {7 - $connection_pin(C$i)}]
+ }
+ }
+
+ # Change state of the device
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state] 1
+ }
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## LED matrix mapping type changed (meaningfull for multiplexed mode)
+ # @return void
+ public method matrix_mapping_changed {} {
+ set conf_matrix_mapping ${::LedMatrix::matrix_mapping}
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## LED dim interval changed (meaningfull for multiplexed mode)
+ # @return void
+ public method dim_interval_changed {} {
+ set conf_dim_interval ${::LedMatrix::dim_interval}
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## LED color was changed
+ # @return void
+ public method color_changed {} {
+ set conf_led_color ${::LedMatrix::color}
+
+
+ # Change state of the device
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state] 1
+ }
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## LED light up condition was changed
+ # @return void
+ public method cond_changed {} {
+ set conf_led_cond ${::LedMatrix::cond}
+
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state]
+ }
+ set_modified
+ }
+
+ ## Dim all LED's and reset their prevoius states
+ # @return void
+ public method dim_all {} {
+ for {set i 0} {$i < 8} {incr i} {
+ for {set j 0} {$j < 8} {incr j} {
+ if {$prev_state($j,$i)} {
+ set prev_state($j,$i) 0
+ $canvas_widget itemconfigure $leds($j,$i) \
+ -image ::ICONS::16::ledgray
+ }
+ }
+ }
+ }
+
+ ## Create GUI of this panel
+ # @return void
+ private method create_gui {} {
+ # Create panel window and canvas widget
+ set win [toplevel .ledmatrix$count -class $component_name -bg {#EEEEEE}]
+ set canvas_widget [canvas $win.canvas \
+ -bg white -width 0 -height 0 \
+ -highlightthickness 0 \
+ ]
+
+ # Create column wires
+ set led_sep 15
+ set sep 25
+ set y_0 100
+ set x_0 85
+ set y_1 [expr {$y_0 + 10}]
+ set x_1 [expr {$x_0 + 35}]
+
+ set cb_x $x_0
+ set cb_y [expr {$y_0 - 80}]
+
+ set x $x_1
+ set y $y_1
+ incr y -$led_sep
+ for {set i 0} {$i < 8} {incr i} {
+ set fin [expr {$cb_y + 30 + abs($x - $cb_x)}]
+ set col($i) [$canvas_widget create line \
+ $cb_x [expr {$cb_y + 20}] \
+ $cb_x [expr {$cb_y + 30}] \
+ $x $fin $x [expr {$y - 8}] \
+ -fill {#000000} -width 1 \
+ ]
+ lappend col($i) [$canvas_widget create text $x $y \
+ -text $i -font $cb_font -fill {#000000} \
+ ]
+ incr x $led_sep
+ incr cb_x $sep
+ }
+
+ # Create row wires
+ set cb_x $x_0
+ set cb_y $y_0
+ incr cb_y -$sep
+ incr cb_x -55
+
+ set x $x_1
+ set y $y_1
+ incr x -$led_sep
+ for {set i 0} {$i < 8} {incr i} {
+ set fin [expr {$cb_x + 30 + abs($y - $cb_y)}]
+ set row($i) [$canvas_widget create line \
+ $cb_x $cb_y [expr {$cb_x + 30}] $cb_y \
+ $fin $y [expr {$x - 8}] $y \
+ -fill {#000000} -width 1 \
+ ]
+ lappend row($i) [$canvas_widget create text $x $y \
+ -font $cb_font -fill {#000000} \
+ -text [lindex {A B C D E F G H} $i] \
+ ]
+
+ incr y $led_sep
+ incr cb_y $sep
+ }
+
+ # Create LED's
+ set y $y_1
+ set x $x_1
+ for {set j 0} {$j < 8} {incr j} {
+ for {set i 0} {$i < 8} {incr i} {
+ set leds($j,$i) [$canvas_widget create image $x $y \
+ -image ::ICONS::16::ledgray \
+ ]
+ incr x $led_sep
+ }
+ incr y $led_sep
+ set x $x_1
+ }
+
+ # Create row ComboBoxes
+ set x $x_0
+ set y $y_0
+ incr y -$sep
+ incr x -55
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget create window $x $y -anchor e \
+ -window [ttk::combobox $canvas_widget.cb_r_p$i \
+ -width 1 \
+ -font $cb_font \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_r_p$i <<ComboboxSelected>> "$this reconnect R $i"
+
+ $canvas_widget create window $x $y -anchor w \
+ -window [ttk::combobox $canvas_widget.cb_r_b$i \
+ -width 1 \
+ -font $cb_font \
+ -values {- 0 1 2 3 4 5 6 7} \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_r_b$i <<ComboboxSelected>> "$this reconnect R $i"
+
+ bindtags $canvas_widget.cb_r_p$i \
+ [list $canvas_widget.cb_r_p$i TCombobox all .]
+ bindtags $canvas_widget.cb_r_b$i \
+ [list $canvas_widget.cb_r_b$i TCombobox all .]
+
+ incr y $sep
+ }
+
+ # Create column ComboBoxes
+ set x $x_0
+ set cb_p_y [expr {$y_0 - 85}]
+ set cb_b_y [expr {$y_0 - 65}]
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget create window $x $cb_p_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_c_p$i \
+ -width 1 \
+ -font $cb_font \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_c_p$i <<ComboboxSelected>> "$this reconnect C $i"
+
+ $canvas_widget create window $x $cb_b_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_c_b$i \
+ -width 1 \
+ -font $cb_font \
+ -values {- 0 1 2 3 4 5 6 7} \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_c_b$i <<ComboboxSelected>> "$this reconnect C $i"
+
+ bindtags $canvas_widget.cb_c_p$i \
+ [list $canvas_widget.cb_c_p$i TCombobox all .]
+ bindtags $canvas_widget.cb_c_b$i \
+ [list $canvas_widget.cb_c_b$i TCombobox all .]
+
+ incr x $sep
+ }
+
+ # Create labels
+ set x $x_0
+ set y $y_0
+ incr y -$sep
+ incr x -55
+
+ $canvas_widget create text 70 $cb_p_y \
+ -text [mc "PORT"] \
+ -font $cb_font \
+ -anchor e
+ $canvas_widget create text 70 $cb_b_y \
+ -text [mc "BIT"] \
+ -font $cb_font \
+ -anchor e
+ $canvas_widget create text [expr {$x_0 - 53}] [expr {$y_0 - 2*$sep}] \
+ -text [mc "PORT"] \
+ -font $cb_font \
+ -anchor ne
+ $canvas_widget create text [expr {$x_0 - 50}] [expr {$y_0 - 2*$sep}] \
+ -text [mc "BIT"] \
+ -font $cb_font \
+ -anchor nw
+
+ $canvas_widget create text 5 273 \
+ -text [mc "Note"] \
+ -font $cb_font \
+ -anchor w
+ $canvas_widget create window 40 273 \
+ -window [ttk::entry $canvas_widget.usr_note \
+ -validate all \
+ -validatecommand "$this set_modified" \
+ ] \
+ -width 230 -anchor w
+ bindtags $canvas_widget.usr_note \
+ [list $canvas_widget.usr_note TEntry $win all .]
+
+
+ # Create "ON/OFF" button
+ set start_stop_button [ttk::button $canvas_widget.start_stop_button \
+ -command "$this on_off_button_press" \
+ -style Flat.TButton \
+ -width 3 \
+ ]
+ DynamicHelp::add $canvas_widget.start_stop_button \
+ -text [mc "Turn HW simulation on/off"]
+ setStatusTip -widget $start_stop_button -text [mc "Turn HW simulation on/off"]
+ bind $start_stop_button <Button-3> "$this on_off_button_press; break"
+ $canvas_widget create window 2 20 -window $start_stop_button -anchor sw
+ bindtags $start_stop_button [list $start_stop_button TButton all .]
+
+ # Create configuration menu button
+ set conf_button [ttk::button $canvas_widget.conf_but \
+ -image ::ICONS::16::configure \
+ -style FlatWhite.TButton \
+ -command "$this config_menu" \
+ ]
+ setStatusTip -widget $conf_button -text [mc "Configure"]
+ $canvas_widget create window 2 20 -window $conf_button -anchor nw
+ bindtags $conf_button [list $conf_button TButton all .]
+
+ # Pack canvas
+ pack $canvas_widget -fill both -expand 1
+
+ # Set window parameters
+ wm geometry $win =275x285
+ wm iconphoto $win ::ICONS::16::$component_icon
+ wm title $win "[mc $component_name] - [string trim $project {:}] - MCU 8051 IDE"
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "$this close_window"
+ bindtags $win [list $win Toplevel all .]
+ }
+
+ ## Determinate which port pin is connected to the specified wire
+ # @parm Char col_or_row - 'C' => Column; 'R' => Row
+ # @parm Int i - Wire number (0..7)
+ # @return List - {port_number bit_number}
+ private method which_port_pin {col_or_row i} {
+ return [list $connection_port(${col_or_row}${i}) $connection_pin(${col_or_row}${i})]
+ }
+
+ ## Handle "ON/OFF" button press
+ # Turn whole PALE system on or off
+ # @return void
+ public method on_off_button_press {} {
+ $project pale_all_on_off
+ }
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE
+ # ------------------------------------------------------------------
+
+ ## Simulated MCU has been changed
+ # @return void
+ public method mcu_changed {} {
+ # Refresh lists of possible values in port selection ComboBoxes
+ set avaliable_ports [concat - [$project pale_get_avaliable_ports]]
+
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_r_p$i configure -values $avaliable_ports
+ $canvas_widget.cb_c_p$i configure -values $avaliable_ports
+
+ if {[lsearch -ascii -exact $avaliable_ports $connection_port(R$i)] == -1} {
+ $canvas_widget.cb_r_p$i current 0
+ set connection_port(R$i) {-}
+ }
+ if {[lsearch -ascii -exact $avaliable_ports $connection_port(C$i)] == -1} {
+ $canvas_widget.cb_c_p$i current 0
+ set connection_port(C$i) {-}
+ }
+ }
+ }
+
+ ## Accept new state of ports
+ # @parm List state - Port states ( 5 x {8 x bit} -- {bit0 bit1 bit2 ... bit7} )
+ # @parm Bool preserve_prvious_state = 0 - Preserve previous state of component
+ # @return void
+ #
+ # Possible bit values:
+ # '|' - High frequency
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ # '0' - Logical 0
+ # '1' - Logical 1
+ public method new_state {state {preserve_prvious_state 0}} {
+ # Change column wire colors
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin C $i]
+
+ # Not connected
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ foreach item $col($i) {
+ $canvas_widget itemconfigure $item -fill {#000000}
+ }
+ continue
+ }
+
+ # Determinate wire color
+ switch -- [lindex $state $pp] {
+ {0} { ;# Logical 0
+ set wire_color {#00FF00}
+ }
+ {1} { ;# Logical 1
+ set wire_color {#FF0000}
+ }
+ {=} { ;# High forced to low
+ set wire_color {#FF00AA}
+ }
+ {} { ;# Not connected
+ set wire_color {#000000}
+ }
+ {?} { ;# No volatge
+ set wire_color {#888888}
+ }
+ default {
+ set wire_color {#FF8800}
+ }
+ }
+
+ # Change wire color
+ foreach item $col($i) {
+ $canvas_widget itemconfigure $item -fill $wire_color
+ }
+ }
+
+ # Change row wire colors
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin R $i]
+
+ # Not connected
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ foreach item $row($i) {
+ $canvas_widget itemconfigure $item -fill {#000000}
+ }
+ continue
+ }
+
+ # Determinate wire color
+ switch -- [lindex $state $pp] {
+ {0} { ;# Logical 0
+ set wire_color {#00FF00}
+ }
+ {1} { ;# Logical 1
+ set wire_color {#FF0000}
+ }
+ {=} { ;# High forced to low
+ set wire_color {#FF00AA}
+ }
+ {} { ;# Not connected
+ set wire_color {#000000}
+ }
+ {?} { ;# No volatge
+ set wire_color {#888888}
+ }
+ default {
+ set wire_color {#FF8800}
+ }
+ }
+
+ # Change wire color
+ foreach item $row($i) {
+ $canvas_widget itemconfigure $item -fill $wire_color
+ }
+ }
+
+ ## Change LED colors
+ # Iterate over rows
+ for {set j 0} {$j < 8} {incr j} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin R $j]
+
+ # Not connected
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget itemconfigure \
+ $leds($j,$i) \
+ -image ::ICONS::16::ledgray
+ }
+ continue
+ }
+
+ # Determinate row state in this way:
+ #+ row_state = 0 => Dim
+ #+ row_state = 1 => Half dim
+ #+ row_state = 2 => Brighten
+ set row_state [lindex $state $pp]
+ switch -- $row_state {
+ {0} { ;# Logical 0
+ if {[lindex $conf_led_cond 0]} {
+ set row_state 0
+ } {
+ set row_state 2
+ }
+ }
+ {1} { ;# Logical 1
+ if {[lindex $conf_led_cond 0]} {
+ set row_state 2
+ } {
+ set row_state 0
+ }
+ }
+ {?} { ;# No volatge
+ set row_state 0
+ }
+ {=} { ;# High forced to low
+ set row_state 0
+ }
+ {} { ;# Not connected
+ set row_state 0
+ }
+ default {
+ set row_state 1
+ }
+ }
+
+ # Iterate over rows
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin C $i]
+
+ # Not connected
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ $canvas_widget itemconfigure $leds($j,$i) -image ::ICONS::16::ledgray
+ continue
+ }
+
+ # Determinate LED color
+ switch -- [lindex $state $pp] {
+ {0} { ;# Logical 0
+ if {[lindex $conf_led_cond 1]} {
+ set image 0 ;# ledgray
+ } {
+ set image 1 ;# shining LED
+ }
+ }
+ {1} { ;# Logical 1
+ if {[lindex $conf_led_cond 1]} {
+ set image 1 ;# shining LED
+ } {
+ set image 0 ;# ledgray
+ }
+ }
+ {?} { ;# No volatge
+ set image 0 ;# ledgray
+ }
+ {=} { ;# High forced to low
+ set image 0 ;# ledgray
+ }
+ {} { ;# Not connected
+ set image 0 ;# ledgray
+ }
+ default {
+ switch -- $row_state {
+ {0} {
+ set image 0 ;# ledgray
+ }
+ {1} {
+ set image 0 ;# ledgray
+ }
+ {2} {
+ set image 2 ;# ledgray${conf_led_color}
+ }
+ }
+ }
+ }
+
+ # Adjust previous states of LEDs to the type of matrix mapping
+ if {$conf_matrix_mapping == 1} {
+ if {$row_state == 2} {
+ set prev_state($j,$i) 0
+ }
+ } elseif {$conf_matrix_mapping == 2} {
+ if {$image == 1} {
+ set prev_state($j,$i) 0
+ }
+ }
+
+ # Translate "shine" to appropriate color
+ if {$image == 1} { ;# shining LED
+ switch -- $row_state {
+ {0} {
+ set image 0 ;# ledgray
+ }
+ {1} {
+ set image 2 ;# ledgray${conf_led_color}
+ }
+ {2} {
+ set image 3 ;# led${conf_led_color}
+ }
+ }
+ }
+
+ ## LED's dims with delay ...
+ # Dim with delay
+ if {$image == 0} {
+ if {$prev_state($j,$i)} {
+ if {!$preserve_prvious_state} {
+ incr prev_state($j,$i) -1
+ }
+ if {$prev_state($j,$i)} {
+ set image 4 ;# led${conf_led_color}2
+ }
+ }
+ # Light up now
+ } elseif {$image == 3} {
+ if {!$preserve_prvious_state} {
+ set prev_state($j,$i) $conf_dim_interval
+ }
+ }
+
+ switch -- $image {
+ 0 {set image "ledgray"}
+ 1 {set image ""}
+ 2 {set image "ledgray${conf_led_color}"}
+ 3 {set image "led${conf_led_color}"}
+ 4 {set image "led${conf_led_color}2"}
+ }
+
+ # Change LED color
+ $canvas_widget itemconfigure $leds($j,$i) \
+ -image ::ICONS::16::$image
+ }
+ }
+ }
+
+ ## Withdraw panel window from the screen
+ # @return void
+ public method withdraw_window {} {
+ wm withdraw $win
+ }
+
+ ## Get panel configuration list (usable with method "set_config")
+ # @return List - configuration list
+ public method get_config {} {
+ return [list \
+ $class_name \
+ [list \
+ [array get connection_port] \
+ [array get connection_pin] \
+ [wm geometry $win] \
+ [$canvas_widget.usr_note get] \
+ $conf_led_color \
+ $conf_dim_interval \
+ $conf_led_cond \
+ $conf_matrix_mapping \
+ ] \
+ ]
+ }
+
+ ## Set panel configuration from list gained from method "get_config"
+ # @parm List state - Configuration list
+ # @return void
+ public method set_config {state} {
+ if {[catch {
+ # Load connections to the MCU
+ array set connection_port [lindex $state 0]
+ array set connection_pin [lindex $state 1]
+
+ # Restore window geometry
+ if {[string length [lindex $state 2]]} {
+ wm geometry $win [lindex $state 2]
+ }
+
+ # Load user note
+ $canvas_widget.usr_note delete 0
+ $canvas_widget.usr_note insert 0 [lindex $state 3]
+
+ # Restore LED's configuration
+ set conf_led_color [lindex $state 4]
+ set conf_dim_interval [lindex $state 5]
+ set conf_led_cond [lindex $state 6]
+ set conf_matrix_mapping [lindex $state 7]
+
+ if {$conf_matrix_mapping == {}} {
+ set conf_matrix_mapping 0
+ }
+
+ # Restore state of ComboBoxes
+ foreach foo {R C} bar {r c} {
+ for {set i 0} {$i < 8} {incr i} {
+ ## PIN
+ set pin $connection_pin(${foo}${i})
+ if {$pin != {-}} {
+ set pin [expr {7 - $pin}]
+ }
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_${bar}_b$i cget -values] \
+ $pin \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_${bar}_b$i current $idx
+
+ ## PORT
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_${bar}_p$i cget -values] \
+ $connection_port(${foo}$i) \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_${bar}_p$i current $idx
+ }
+ }
+
+ # Accept new state of ports
+ new_state [$project pale_get_true_state]
+ update
+
+ # Fail
+ }]} then {
+ puts "Unable to load config for $class_name"
+ return 0
+
+ # Success
+ } else {
+ clear_modified
+ return 1
+ }
+ }
+
+ ## Simulated MCU has been reseted
+ # @return void
+ public method reset {} {
+ dim_all
+ new_state [$project pale_get_true_state]
+ }
+
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+ # ------------------------------------------------------------------
+
+ ## This method is called before configuration menu invocation
+ # @return void
+ public method config_menu_special {} {
+ set ::${class_name}::dim_interval $conf_dim_interval
+ set ::${class_name}::matrix_mapping $conf_matrix_mapping
+ set ::${class_name}::color $conf_led_color
+ set ::${class_name}::cond $conf_led_cond
+ }
+
+ ## This method is called after configuration menu has beed created
+ # @return void
+ public method create_config_menu_special {} {
+ foreach item { Red Orange Yellow Green Blue Purple } \
+ color { #DD0000 #DD8800 #DDDD00 #00DD00 #0000DD #8800DD } \
+ {
+ $conf_menu.color entryconfigure [::mc $item] -foreground $color
+ }
+ }
+
+ ## This method is called to fill in the help dialog
+ # @parm Widget text_widget - Target text widget
+ # @return void
+ #
+ # Note: There is defined text tag "tag_bold" in the text widget
+ public method show_help_special {text_widget} {
+ $text_widget insert insert [mc "This tool consists of 64 LED's. Each of them can be connected to any port pin of the simulated uC. Connections with the uC are made with ComboBoxes. Panel configuration can be saved to a file (with extension vhc). And can be loaded from that file later. Condition on which a LED lights up and LED colors are configurable. Also fade out interval is configurable.\n\n"]
+
+ $text_widget insert insert [mc "LED states:"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc "\n "]
+ $text_widget image create insert -image ::ICONS::16::ledgray
+ $text_widget insert insert [mc " Off\n "]
+ $text_widget image create insert -image ::ICONS::16::ledgray${conf_led_color}
+ $text_widget insert insert [mc " Fast blinking\n "]
+ $text_widget image create insert -image ::ICONS::16::led${conf_led_color}
+ $text_widget insert insert [mc " Shining\n "]
+ $text_widget image create insert -image ::ICONS::16::led${conf_led_color}2
+ $text_widget insert insert [mc " Fading out"]
+ }
+
+ ## This method is called before panel window closure
+ # @return void
+ public method close_window_special {} {
+ }
+
+ ## Commit new on/off state
+ # @return void
+ public method on_off_special {} {
+ if {!$drawing_on} {
+ for {set j 0} {$j < 8} {incr j} {
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget itemconfigure $leds($j,$i) \
+ -image ::ICONS::16::ledgray
+ }
+ }
+ } {
+ new_state [$project pale_get_true_state] 1
+ }
+ }
+}
diff --git a/lib/pale/ledpanel.tcl b/lib/pale/ledpanel.tcl
new file mode 100755
index 0000000..a05bb79
--- /dev/null
+++ b/lib/pale/ledpanel.tcl
@@ -0,0 +1,543 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements PALE VHW component "LED panel"
+#
+# Consists of:
+# INTERNAL APPLICATION LOGIC
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM PALE ENGINE
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+# --------------------------------------------------------------------------
+
+class LedPanel {
+ inherit VirtualHWComponent
+
+ # Font: Font to be used in the panel -- bold
+ common cb_font [font create -weight bold -size -10 -family {helvetica}]
+ common COMPONENT_NAME "LED panel" ;# Name of this component
+ common CLASS_NAME "LedPanel" ;# Name of this class
+ common COMPONENT_ICON {ledpanel} ;# Icon for this panel (16x16)
+
+ # Configuration menu
+ common CONFMENU {
+ {cascade {Color} 0 "colorize" .color false 1 {
+ {radiobutton "Red" {}
+ ::LedPanel::color {red}
+ "color_changed" 0 ""}
+ {radiobutton "Orange" {}
+ ::LedPanel::color {orange}
+ "color_changed" 0 ""}
+ {radiobutton "Yellow" {}
+ ::LedPanel::color {yellow}
+ "color_changed" 0 ""}
+ {radiobutton "Green" {}
+ ::LedPanel::color {green}
+ "color_changed" 0 ""}
+ {radiobutton "Blue" {}
+ ::LedPanel::color {blue}
+ "color_changed" 0 ""}
+ {radiobutton "Purple" {}
+ ::LedPanel::color {purple}
+ "color_changed" 0 ""}
+ }}
+ {separator}
+ {command {Show help} {} 5 "show_help" {help}
+ "Show brief help"}
+ {separator}
+ {command {Save configuration} {} 0 "save_as" {filesave}
+ "Save configuration into a file"}
+ {command {Load configuration} {} 0 "load_from" {fileopen}
+ "Load configuration from a file"}
+ }
+
+
+ private variable conf_led_color {red} ;# Color: Selected color for LED's
+ private variable leds ;# Array of CanvasObject (image): LED's
+ private variable connection_port ;# Array of Int: Index is key number, value is port number or {-}
+ private variable connection_pin ;# Array of Int: Index is key number, value is bit number or {-}
+
+
+ # ------------------------------------------------------------------
+ # INTERNAL APPLICATION LOGIC
+ # ------------------------------------------------------------------
+
+ ## Object constructor
+ # @parm Object _project - Project object
+ constructor {_project} {
+ # Set object variables identifing this component (see the base class)
+ set component_name $COMPONENT_NAME
+ set class_name $CLASS_NAME
+ set component_icon $COMPONENT_ICON
+
+ # Set other object variables
+ set project $_project
+ array set connection_port {0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -}
+ array set connection_pin {0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -}
+
+ # Inform PALE
+ $project pale_register_output_device $this
+ $project pale_set_modified
+
+ # Create panel GUI
+ create_gui
+ mcu_changed
+ on_off [$project pale_is_enabled]
+
+ # ComboBoxes to default state
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_b$i current 0
+ $canvas_widget.cb_p$i current 0
+ }
+ }
+
+ ## Object destructor
+ destructor {
+ # Inform PALE
+ $project pale_unregister_output_device $this
+
+ # Destroy GUI
+ destroy $win
+ }
+
+ ## Reconnect the specified LED to another port pin
+ # @parm Int i - LED number (0..7)
+ # @return void
+ public method reconnect {i} {
+ # Adjust connections
+ set connection_port($i) [$canvas_widget.cb_p$i get]
+ set connection_pin($i) [$canvas_widget.cb_b$i get]
+ if {$connection_pin($i) != {-}} {
+ set connection_pin($i) [expr {7 - $connection_pin($i)}]
+ }
+
+ # Change state of the device
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state]
+ }
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## LED color changed
+ # @return void
+ public method color_changed {} {
+ set conf_led_color ${::LedPanel::color}
+
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state]
+ }
+ set_modified
+ }
+
+ ## Create GUI of this panel
+ # @return void
+ private method create_gui {} {
+ # Create panel window and canvas widget
+ set win [toplevel .ledpanel$count -class $component_name -bg {#EEEEEE}]
+ set canvas_widget [canvas $win.canvas \
+ -bg white -width 0 -height 0 \
+ -highlightthickness 0 \
+ ]
+
+ # Print labels
+ set led_y 35
+ set cb_p_y 65
+ set cb_b_y 85
+ set usr_n_y 105
+ set x 50
+ $canvas_widget create text 5 $cb_p_y \
+ -text [mc "PORT"] \
+ -font $cb_font \
+ -anchor w
+ $canvas_widget create text 5 $cb_b_y \
+ -text [mc "BIT"] \
+ -font $cb_font \
+ -anchor w
+ $canvas_widget create text 5 $usr_n_y \
+ -text [mc "Note"] \
+ -font $cb_font \
+ -anchor w
+ $canvas_widget create window 208 $usr_n_y \
+ -window [ttk::entry $canvas_widget.usr_note \
+ -validate all \
+ -validatecommand "$this set_modified" \
+ ] \
+ -width 330
+ bindtags $canvas_widget.usr_note \
+ [list $canvas_widget.usr_note TEntry $win all .]
+
+ # Create LES's and ComboBoxes
+ for {set i 0} {$i < 8} {incr i} {
+ set leds($i) [$canvas_widget create image $x $led_y \
+ -image ::ICONS::16::ledgray \
+ ]
+
+ incr x 6
+
+ $canvas_widget create window $x $cb_p_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_p$i \
+ -width 1 \
+ -font $cb_font \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_p$i <<ComboboxSelected>> "$this reconnect $i"
+
+ $canvas_widget create window $x $cb_b_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_b$i \
+ -width 1 \
+ -font $cb_font \
+ -values {- 0 1 2 3 4 5 6 7} \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_b$i <<ComboboxSelected>> "$this reconnect $i"
+
+ bindtags $canvas_widget.cb_p$i \
+ [list $canvas_widget.cb_p$i TCombobox all .]
+ bindtags $canvas_widget.cb_b$i \
+ [list $canvas_widget.cb_b$i TCombobox all .]
+
+ incr x 6
+ draw_led $x 10
+
+ incr x 30
+ }
+
+ # Create "ON/OFF" button
+ set start_stop_button [ttk::button $canvas_widget.start_stop_button \
+ -command "$this on_off_button_press" \
+ -style Flat.TButton \
+ -width 3 \
+ ]
+ DynamicHelp::add $canvas_widget.start_stop_button \
+ -text [mc "Turn HW simulation on/off"]
+ setStatusTip -widget $start_stop_button -text [mc "Turn HW simulation on/off"]
+ bind $start_stop_button <Button-3> "$this on_off_button_press; break"
+ $canvas_widget create window 22 2 -window $start_stop_button -anchor nw
+ bindtags $start_stop_button [list $start_stop_button TButton all .]
+
+ # Create configuration menu button
+ set conf_button [ttk::button $canvas_widget.conf_but \
+ -image ::ICONS::16::configure \
+ -style FlatWhite.TButton \
+ -command "$this config_menu" \
+ ]
+ setStatusTip -widget $conf_button -text [mc "Configure"]
+ $canvas_widget create window 20 2 -window $conf_button -anchor ne
+ bindtags $conf_button [list $conf_button TButton all .]
+
+ # Pack canvas
+ pack $canvas_widget -fill both -expand 1
+
+ # Set window parameters
+ wm geometry $win =380x120
+ wm iconphoto $win ::ICONS::16::$component_icon
+ wm title $win "[mc $component_name] - [string trim $project {:}] - MCU 8051 IDE"
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "$this close_window"
+ bindtags $win [list $win Toplevel all .]
+ }
+
+ ## Draw LED and resistor symbol
+ # @parm Int x - X origin coordinate
+ # @parm Int y - Y origin coordinate
+ # @return void
+ private method draw_led {x y} {
+ $canvas_widget create line \
+ [expr {4 + $x}] [expr {2 + $y}] \
+ [expr {6 + $x}] [expr {0 + $y}] \
+ [expr {8 + $x}] [expr {2 + $y}] \
+ [expr {6 + $x}] [expr {0 + $y}] \
+ [expr {6 + $x}] [expr {6 + $y}] \
+ [expr {8 + $x}] [expr {6 + $y}] \
+ [expr {8 + $x}] [expr {17 + $y}]\
+ [expr {4 + $x}] [expr {17 + $y}]\
+ [expr {4 + $x}] [expr {6 + $y}] \
+ [expr {6 + $x}] [expr {6 + $y}] \
+ [expr {4 + $x}] [expr {6 + $y}] \
+ [expr {4 + $x}] [expr {17 + $y}]\
+ [expr {6 + $x}] [expr {17 + $y}]\
+ [expr {6 + $x}] [expr {37 + $y}]\
+ [expr {6 + $x}] [expr {28 + $y}]\
+ [expr {0 + $x}] [expr {28 + $y}]\
+ [expr {12 + $x}] [expr {28 + $y}]\
+ [expr {6 + $x}] [expr {28 + $y}]\
+ [expr {6 + $x}] [expr {27 + $y}]\
+ [expr {0 + $x}] [expr {21 + $y}]\
+ [expr {12 + $x}] [expr {21 + $y}]\
+ [expr {6 + $x}] [expr {27 + $y}]\
+ [expr {6 + $x}] [expr {37 + $y}]\
+ [expr {0 + $x}] [expr {43 + $y}]\
+ -fill {#888888}
+
+ $canvas_widget create line \
+ [expr {14 + $x}] [expr {22 + $y}]\
+ [expr {17 + $x}] [expr {19 + $y}]\
+ [expr {15 + $x}] [expr {19 + $y}]\
+ [expr {17 + $x}] [expr {19 + $y}]\
+ [expr {17 + $x}] [expr {21 + $y}]\
+ -fill {#888888}
+
+ $canvas_widget create line \
+ [expr {14 + $x}] [expr {26 + $y}]\
+ [expr {17 + $x}] [expr {23 + $y}]\
+ [expr {15 + $x}] [expr {23 + $y}]\
+ [expr {17 + $x}] [expr {23 + $y}]\
+ [expr {17 + $x}] [expr {25 + $y}]\
+ -fill {#888888}
+ }
+
+ ## Determinate which port pin is connected to the specified LED
+ # @parm Int i - LED number
+ # @return List - {port_number bit_number}
+ private method which_port_pin {i} {
+ return [list $connection_port($i) $connection_pin($i)]
+ }
+
+ ## Handle "ON/OFF" button press
+ # Turn whole PALE system on or off
+ # @return void
+ public method on_off_button_press {} {
+ $project pale_all_on_off
+ }
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE
+ # ------------------------------------------------------------------
+
+ ## Simulated MCU has been changed
+ # @return void
+ public method mcu_changed {} {
+ # Refresh lists of possible values in port selection ComboBoxes
+ set avaliable_ports [concat - [$project pale_get_avaliable_ports]]
+
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_p$i configure -values $avaliable_ports
+
+ if {[lsearch -ascii -exact $avaliable_ports $connection_port($i)] == -1} {
+ $canvas_widget.cb_p$i current 0
+ set connection_port($i) {-}
+ }
+ }
+ }
+
+ ## Accept new state of ports
+ # @parm List state - Port states ( 5 x {8 x bit} -- {bit0 bit1 bit2 ... bit7} )
+ # @return void
+ #
+ # Possible bit values:
+ # '|' - High frequency
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ # '0' - Logical 0
+ # '1' - Logical 1
+ public method new_state {state} {
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin $i]
+
+ # Not connected
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ $canvas_widget itemconfigure $leds($i) -image ::ICONS::16::ledgray
+ continue
+ }
+
+ # Change LED color
+ switch -- [lindex $state $pp] {
+ {0} { ;# Logical 0
+ set image led${conf_led_color}
+ }
+ {1} { ;# Logical 1
+ set image ledgray
+ }
+ {?} { ;# No volatge
+ set image ledgray
+ }
+ {=} { ;# High forced to low
+ set image ledgray
+ }
+ {} { ;# Not connected
+ set image ledgray
+ }
+ default {
+ set image ledgray${conf_led_color}
+ }
+ }
+ $canvas_widget itemconfigure $leds($i) -image ::ICONS::16::$image
+ }
+ }
+
+ ## Withdraw panel window from the screen
+ # @return void
+ public method withdraw_window {} {
+ wm withdraw $win
+ }
+
+ ## Get panel configuration list (usable with method "set_config")
+ # @return List - configuration list
+ public method get_config {} {
+ return [list \
+ $class_name \
+ [list \
+ [array get connection_port] \
+ [array get connection_pin] \
+ [wm geometry $win] \
+ [$canvas_widget.usr_note get] \
+ $conf_led_color \
+ ] \
+ ]
+ }
+
+ ## Set panel configuration from list gained from method "get_config"
+ # @parm List state - Configuration list
+ # @return void
+ public method set_config {state} {
+ if {[catch {
+ # Load connections to the MCU
+ array set connection_port [lindex $state 0]
+ array set connection_pin [lindex $state 1]
+
+ # Restore window geometry
+ if {[string length [lindex $state 2]]} {
+ wm geometry $win [lindex $state 2]
+ }
+
+ # Load user note
+ $canvas_widget.usr_note delete 0
+ $canvas_widget.usr_note insert 0 [lindex $state 3]
+
+ # Restore LED's configuration
+ set conf_led_color [lindex $state 4]
+
+ # Restore state of ComboBoxes
+ for {set i 0} {$i < 8} {incr i} {
+ ## PIN
+ set pin $connection_pin($i)
+ if {$pin != {-}} {
+ set pin [expr {7 - $pin}]
+ }
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_b$i cget -values] \
+ $pin \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_b$i current $idx
+
+ ## PORT
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_p$i cget -values] \
+ $connection_port($i) \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_p$i current $idx
+ }
+
+ # Accept new state of ports
+ new_state [$project pale_get_true_state]
+ update
+
+ # Fail
+ }]} then {
+ puts "Unable to load config for $class_name"
+ return 0
+
+ # Success
+ } else {
+ clear_modified
+ return 1
+ }
+ }
+
+ ## Simulated MCU has been reseted
+ # @return void
+ public method reset {} {
+ new_state [$project pale_get_true_state]
+ }
+
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+ # ------------------------------------------------------------------
+
+ ## This method is called before configuration menu invocation
+ # @return void
+ public method config_menu_special {} {
+ set ::${class_name}::color $conf_led_color
+ }
+
+ ## This method is called after configuration menu has beed created
+ # @return void
+ public method create_config_menu_special {} {
+ foreach item { Red Orange Yellow Green Blue Purple } \
+ color { #DD0000 #DD8800 #DDDD00 #00DD00 #0000DD #8800DD } \
+ {
+ $conf_menu.color entryconfigure [::mc $item] -foreground $color
+ }
+ }
+
+ ## This method is called to fill in the help dialog
+ # @parm Widget text_widget - Target text widget
+ # @return void
+ #
+ # Note: There is defined text tag "tag_bold" in the text widget
+ public method show_help_special {text_widget} {
+ $text_widget insert insert [mc "This tool consists of 8 LED's. Each of them can be connected to any port pin of the simulated uC. Connections with the uC are made with ComboBoxes on the bottom of the panel. Panel configuration can be saved to a file (with extension vhc). And can be loaded from that file later. LED colors are configurable.\n\n"]
+
+ $text_widget insert insert [mc "LED states:"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc "\n "]
+ $text_widget image create insert -image ::ICONS::16::ledgray
+ $text_widget insert insert [mc " Off\n "]
+ $text_widget image create insert -image ::ICONS::16::ledgray${conf_led_color}
+ $text_widget insert insert [mc " Fast blinking\n "]
+ $text_widget image create insert -image ::ICONS::16::led${conf_led_color}
+ $text_widget insert insert [mc " Shining"]
+ }
+
+ ## This method is called before panel window closure
+ # @return void
+ public method close_window_special {} {
+ }
+
+ ## Commit new on/off state
+ # @return void
+ public method on_off_special {} {
+ if {!$drawing_on} {
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget itemconfigure $leds($i) \
+ -image ::ICONS::16::ledgray
+ }
+ } {
+ new_state [$project pale_get_true_state]
+ }
+ }
+}
diff --git a/lib/pale/matrixkeypad.tcl b/lib/pale/matrixkeypad.tcl
new file mode 100755
index 0000000..186ead0
--- /dev/null
+++ b/lib/pale/matrixkeypad.tcl
@@ -0,0 +1,889 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements PALE VHW component "Matrix Keypad"
+#
+# Consists of:
+# INTERNAL APPLICATION LOGIC
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM PALE ENGINE
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+# --------------------------------------------------------------------------
+
+class MatrixKeyPad {
+ inherit VirtualHWComponent
+
+ # Font: Font to be used in the panel -- bold
+ common cb_font [font create \
+ -weight bold \
+ -size -10 \
+ -family {helvetica} \
+ ]
+ # Font: Font to be used in the panel -- normal weight
+ common cb_font_n [font create \
+ -size -10 \
+ -family {helvetica} \
+ ]
+
+ common COMPONENT_NAME "Matrix Keypad" ;# Name of this component
+ common CLASS_NAME "MatrixKeyPad" ;# Name of this class
+ common COMPONENT_ICON {matrixkeypad} ;# Icon for this panel (16x16)
+
+ # Configuration menu
+ common CONFMENU {
+ {checkbutton "Radio buttons" {} {::MatrixKeyPad::menu_radio_buttons}
+ 1 0 0 {value_radio_buttons_changed}
+ ""}
+ {separator}
+ {command {Show help} {} 5 "show_help" {help}
+ "Show brief help"}
+ {separator}
+ {command {Save configuration} {} 0 "save_as" {filesave}
+ "Save configuration into a file"}
+ {command {Load configuration} {} 0 "load_from" {fileopen}
+ "Load configuration from a file"}
+ }
+
+ private variable radio_buttons ;# Bool: Disallow key combinations
+ private variable keys ;# Array of Bool: Indicates key press
+ private variable wire
+ private variable wire_o
+ private variable rect ;# Array of CanvasObject (rectangle): Key rectangles
+ private variable lever ;# Array of CanvasObject (line): Key levers
+ private variable text ;# Array of CanvasObject (text): Key descriptions
+ private variable lines_o
+ private variable lines
+
+ private variable row_wire
+ private variable col_wire
+
+ private variable connection_port ;# Array of Int: Index is key number, value is port number or {-}
+ private variable connection_pin ;# Array of Int: Index is key number, value is bit number or {-}
+ private variable enaged ;# Array of Bool: enaged(port_num,bit_num) --> Is connected to this device ?
+
+
+ # ------------------------------------------------------------------
+ # INTERNAL APPLICATION LOGIC
+ # ------------------------------------------------------------------
+
+ ## Object constructor
+ # @parm Object _project - Project object
+ constructor {_project} {
+ # Set object variables identifing this component (see the base class)
+ set component_name $COMPONENT_NAME
+ set class_name $CLASS_NAME
+ set component_icon $COMPONENT_ICON
+
+ # Set other object variables
+ set project $_project
+ set radio_buttons 1
+ array set connection_port {0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -}
+ array set connection_pin {0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -}
+ array set keys {
+ 0 0 1 0 2 0 3 0
+ 4 0 5 0 6 0 7 0
+ 8 0 9 0 10 0 11 0
+ 12 0 13 0 14 0 15 0
+ }
+ for {set port 0} {$port < 5} {incr port} {
+ for {set bit 0} {$bit < 8} {incr bit} {
+ set enaged($port,$bit) 0
+ }
+ }
+
+ # Inform PALE
+ $project pale_register_input_device $this
+ $project pale_set_modified
+
+ # Create panel GUI
+ create_gui
+ mcu_changed
+ on_off [$project pale_is_enabled]
+
+ # ComboBoxes to default state
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_b$i current 0
+ $canvas_widget.cb_p$i current 0
+ }
+ }
+
+ ## Object destructor
+ destructor {
+ # Inform PALE
+ $project pale_unregister_input_device $this
+
+ # Destroy GUI
+ destroy $win
+ }
+
+ ## Reevaluate array of MCU port pins engaged by this device
+ # @return void
+ private method evaluete_enaged_pins {} {
+ # Mark all as disengaged and infrom PALE
+ for {set port 0} {$port < 5} {incr port} {
+ for {set bit 0} {$bit < 8} {incr bit} {
+ if {$enaged($port,$bit)} {
+ $project pale_disengage_pin_by_input_device $port $bit $this
+ set enaged($port,$bit) 0
+ }
+ }
+ }
+
+ # Find the engaged ones and infrom PALE
+ for {set i 0} {$i < 8} {incr i} {
+ set port $connection_port($i)
+ set bit $connection_pin($i)
+
+ if {$port == {-} || $bit == {-}} {
+ continue
+ }
+
+ set enaged($port,$bit) 1
+ $project pale_engage_pin_by_input_device $port $bit $this
+ }
+ }
+
+ ## Reconnect the specified key to another port pin
+ # @parm Int i - Connection wire number ({0..3} => Row; {4..7} => Column)
+ # @return void
+ public method reconnect {i} {
+ # Adjust connections
+ set connection_port($i) [$canvas_widget.cb_p$i get]
+ set connection_pin($i) [$canvas_widget.cb_b$i get]
+ if {$connection_pin($i) != {-}} {
+ set connection_pin($i) [expr {7 - $connection_pin($i)}]
+ }
+
+ # Reevaluate array of MCU port pins engaged by this device
+ evaluete_enaged_pins
+
+ # Inform PALE system about the change in order
+ #+ to make immediate change in device states
+ if {$drawing_on} {
+ $project pale_reevaluate_IO
+ }
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## Create GUI of this panel
+ # @return void
+ private method create_gui {} {
+ # Create panel window and canvas widget
+ set win [toplevel .matrixkeypad$count -class $component_name -bg {#EEEEEE}]
+ set canvas_widget [canvas $win.canvas \
+ -bg white -width 0 -height 0 \
+ -highlightthickness 0 \
+ ]
+
+ # Create labels
+ $canvas_widget create text 33 20 \
+ -text [mc "PORT"] \
+ -font $cb_font \
+ -anchor e
+ $canvas_widget create text 35 20 \
+ -text [mc "BIT"] \
+ -font $cb_font \
+ -anchor w
+
+ $canvas_widget create text 80 175 \
+ -text [mc "PORT"] \
+ -font $cb_font \
+ -anchor e
+ $canvas_widget create text 80 195 \
+ -text [mc "BIT"] \
+ -font $cb_font \
+ -anchor e
+
+ $canvas_widget create text 5 220 \
+ -text [mc "Note"] \
+ -font $cb_font \
+ -anchor w
+ $canvas_widget create window 35 220 \
+ -window [ttk::entry $canvas_widget.usr_note \
+ -validate all \
+ -validatecommand "$this set_modified" \
+ ] \
+ -width 180 -anchor w
+ bindtags $canvas_widget.usr_note \
+ [list $canvas_widget.usr_note TEntry $win all .]
+
+ # Draw wires connecting keys to rows and columns
+ set sep 37
+ set x_0 65
+ set y 5
+ set i 0
+ set x $x_0
+ for {set row 0} {$row < 4} {incr row} {
+ for {set col 0} {$col < 4} {incr col} {
+ draw_key $x $y $i
+ incr i
+ incr x $sep
+ }
+ incr y $sep
+ set x $x_0
+ }
+ draw_col_row_wires -10 -25
+
+ # Create ComboBoxes on rows
+ set x 30
+ set y 40
+ for {set i 0} {$i < 4} {incr i} {
+ $canvas_widget create window $x $y -anchor e \
+ -window [ttk::combobox $canvas_widget.cb_p$i \
+ -width 1 \
+ -font $cb_font \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_p$i <<ComboboxSelected>> "$this reconnect $i"
+
+ $canvas_widget create window $x $y -anchor w \
+ -window [ttk::combobox $canvas_widget.cb_b$i \
+ -width 1 \
+ -font $cb_font \
+ -values {- 0 1 2 3 4 5 6 7} \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_b$i <<ComboboxSelected>> "$this reconnect $i"
+
+ bindtags $canvas_widget.cb_p$i \
+ [list $canvas_widget.cb_p$i TCombobox all .]
+ bindtags $canvas_widget.cb_b$i \
+ [list $canvas_widget.cb_b$i TCombobox all .]
+
+ incr y $sep
+ }
+
+ # Create ComboBoxes on columns
+ set cb_p_y 175
+ set cb_b_y 195
+ set x 95
+ for {set i 4} {$i < 8} {incr i} {
+ $canvas_widget create window $x $cb_p_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_p$i \
+ -width 1 \
+ -font $cb_font \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_p$i <<ComboboxSelected>> "$this reconnect $i"
+
+ $canvas_widget create window $x $cb_b_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_b$i \
+ -width 1 \
+ -font $cb_font \
+ -values {- 0 1 2 3 4 5 6 7} \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_b$i <<ComboboxSelected>> "$this reconnect $i"
+
+ bindtags $canvas_widget.cb_p$i \
+ [list $canvas_widget.cb_p$i TCombobox all .]
+ bindtags $canvas_widget.cb_b$i \
+ [list $canvas_widget.cb_b$i TCombobox all .]
+
+ incr x $sep
+ }
+
+ # Create "ON/OFF" button
+ set start_stop_button [ttk::button $canvas_widget.start_stop_button \
+ -command "$this on_off_button_press" \
+ -style Flat.TButton \
+ -width 3 \
+ ]
+ DynamicHelp::add $canvas_widget.start_stop_button \
+ -text [mc "Turn HW simulation on/off"]
+ setStatusTip -widget $start_stop_button -text [mc "Turn HW simulation on/off"]
+ bind $start_stop_button <Button-3> "$this on_off_button_press; break"
+ $canvas_widget create window 22 190 -window $start_stop_button -anchor w
+ bindtags $start_stop_button [list $start_stop_button TButton all .]
+
+ # Create configuration menu button
+ set conf_button [ttk::button $canvas_widget.conf_but \
+ -image ::ICONS::16::configure \
+ -style FlatWhite.TButton \
+ -command "$this config_menu" \
+ ]
+ setStatusTip -widget $conf_button -text [mc "Configure"]
+ $canvas_widget create window 20 190 -window $conf_button -anchor e
+ bindtags $conf_button [list $conf_button TButton all .]
+
+ # Pack canvas
+ pack $canvas_widget -fill both -expand 1
+
+ # Set window parameters
+ wm geometry $win =225x235
+ wm iconphoto $win ::ICONS::16::$component_icon
+ wm title $win "[mc $component_name] - [string trim $project {:}] - MCU 8051 IDE"
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "$this close_window"
+ bindtags $win [list $win Toplevel all .]
+ }
+
+ ## Draw wires connecting keys to rows and columns
+ # @parm Int x_0 - Origin -- X coordinate
+ # @parm Int y_0 - Origin -- Y coordinate
+ # @return void
+ private method draw_col_row_wires {x_0 y_0} {
+ # Columns
+ set x $x_0
+ set y $y_0
+ for {set i 0} {$i < 4} {incr i} {
+ set col_wire($i) [list]
+
+ lappend col_wire($i) [$canvas_widget create line\
+ [expr {$x + 107}] [expr {$y + 37}] \
+ [expr {$x + 107}] [expr {$y + 190}] \
+ -fill #000000 -width 1 \
+ ]
+
+ for {set j 0} {$j < 4} {incr j} {
+ lappend col_wire($i) [$canvas_widget create line\
+ [expr {$x + 100}] [expr {$y + 37}] \
+ [expr {$x + 107}] [expr {$y + 37}] \
+ -fill #000000 -width 1 \
+ ]
+ if {$j != 0} {
+ lappend col_wire($i) [$canvas_widget create oval\
+ [expr {$x + 105}] [expr {$y + 35}] \
+ [expr {$x + 109}] [expr {$y + 39}] \
+ -fill #000000 -width 0 \
+ ]
+ }
+ incr y 37
+ }
+ set y $y_0
+ incr x 37
+ }
+
+ # Rows
+ set x $x_0
+ set y $y_0
+ for {set i 0} {$i < 4} {incr i} {
+ set row_wire($i) [list]
+
+ lappend row_wire($i) [$canvas_widget create line\
+ [expr {$x + 200}] [expr {$y + 64}] \
+ [expr {$x + 30}] [expr {$y + 64}] \
+ -fill #000000 -width 1 \
+ ]
+
+ for {set j 0} {$j < 4} {incr j} {
+ lappend row_wire($i) [$canvas_widget create line\
+ [expr {$x + 88}] [expr {$y + 60}] \
+ [expr {$x + 88}] [expr {$y + 64}] \
+ -fill #000000 -width 1 \
+ ]
+ if {$j == 3} {
+ break
+ }
+
+ lappend row_wire($i) [$canvas_widget create oval\
+ [expr {$x + 86}] [expr {$y + 62}] \
+ [expr {$x + 90}] [expr {$y + 66}] \
+ -fill #000000 -width 0 \
+ ]
+ incr x 37
+ }
+ set x $x_0
+ incr y 37
+ }
+ }
+
+ ## Handle click on a virtual key
+ # @parm Int i - Key number
+ # @return void
+ public method key_click {i} {
+ # Adjust state of the key
+ set keys($i) [expr {!$keys($i)}]
+ key_state_changed $i
+
+ # Release all other keys if the panel was configured to use radio buttons
+ if {$radio_buttons} {
+ for {set j 0} {$j < 16} {incr j} {
+ if {$j == $i} {
+ continue
+ }
+ if {$keys($j)} {
+ set keys($j) 0
+ key_state_changed $j
+ }
+ }
+ }
+
+ # Inform PALE system about the change in order
+ #+ to make immediate change in device states
+ if {$drawing_on} {
+ $project pale_reevaluate_IO
+ }
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## Adjust GUI to new state of a virtual key
+ # @parm Int i - Key number
+ # @return void
+ private method key_state_changed {i} {
+ # Key pressed
+ if {$keys($i)} {
+ $canvas_widget itemconfigure $lever(0$i) -fill #FFFFFF
+ $canvas_widget itemconfigure $lever(1$i) -fill #000000
+ $canvas_widget itemconfigure $text($i) -font $cb_font
+ $canvas_widget itemconfigure $rect($i) -outline #333333 -width 2
+
+ # Key released
+ } {
+ $canvas_widget itemconfigure $lever(0$i) -fill #000000
+ $canvas_widget itemconfigure $lever(1$i) -fill #FFFFFF
+ $canvas_widget itemconfigure $text($i) -font $cb_font_n
+ $canvas_widget itemconfigure $rect($i) -outline #CCCCCC -width 1
+ }
+ }
+
+ ## Handle mouse pointer enter on a virtual key
+ # @parm Int i - Key number
+ # @return void
+ public method key_leave {i} {
+ if {$keys($i)} {
+ set color {#333333}
+ } {
+ set color {#CCCCCC}
+ }
+ $canvas_widget itemconfigure $rect($i) -outline $color
+ }
+
+ ## Handle mouse pointer leave on a virtual key
+ # @parm Int i - Key number
+ # @return void
+ public method key_enter {i} {
+ $canvas_widget itemconfigure $rect($i) -outline {#0000FF}
+ }
+
+ ## Draw virtual key on the panel canvas
+ # @parm Int x - X coordinate of top left corner of the key
+ # @parm Int y - Y coordinate of top left corner of the key
+ # @parm Int i - Key number
+ # @return void
+ private method draw_key {x y i} {
+ # Draw rectangle sorrounding the key
+ set rect($i) [$canvas_widget create rectangle \
+ [expr {$x + 1}] [expr {$y + 1}] \
+ [expr {$x + 25}] [expr {$y + 29}] \
+ -width 1 -outline #CCCCCC -fill #FFFFFF \
+ ]
+
+ # Print key label
+ set text($i) [$canvas_widget create text \
+ [expr {$x + 20}] [expr {$y + 15}] \
+ -font $cb_font_n \
+ -text [lindex {1 2 3 A 4 5 6 B 7 8 9 C * 0 # D} $i] \
+ ]
+
+ # Draw lever in the key
+ set lever(1$i) [$canvas_widget create line \
+ [expr {$x + 11}] [expr {$y + 22}] \
+ [expr {$x + 11}] [expr {$y + 6}] \
+ -width 1 -fill #FFFFFF \
+ ]
+ set lever(0$i) [$canvas_widget create line \
+ [expr {$x + 10}] [expr {$y + 22}] \
+ [expr {$x + 5}] [expr {$y + 6}] \
+ -width 1 -fill #000000 \
+ ]
+
+ # Draw lines connecting the key to the column
+ set lines($i) [$canvas_widget create line \
+ [expr {$x + 16}] [expr {$y + 7}] \
+ [expr {$x + 25}] [expr {$y + 7}] \
+ -width 1 -fill #000000 \
+ ]
+ set lines_o($i) [$canvas_widget create oval \
+ [expr {$x + 11}] [expr {$y + 5}] \
+ [expr {$x + 15}] [expr {$y + 9}] \
+ -width 1 -outline #000000 \
+ ]
+
+ # Draw lines connecting the key to the row
+ set wire($i) [$canvas_widget create line \
+ [expr {$x + 13}] [expr {$y + 26}] \
+ [expr {$x + 13}] [expr {$y + 30}] \
+ -width 1 -fill #000000 \
+ ]
+ set wire_o($i) [$canvas_widget create oval \
+ [expr {$x + 11}] [expr {$y + 21}] \
+ [expr {$x + 15}] [expr {$y + 25}] \
+ -width 1 -outline #000000 \
+ ]
+
+ # Set event bindings for the key
+ foreach items [list \
+ $rect($i) $lines_o($i) $wire_o($i) \
+ $lever(0$i) $lever(1$i) $text($i) \
+ $lines($i) $wire($i) \
+ ] {
+ foreach item $items {
+ $canvas_widget bind $item <Enter> "$this key_enter $i"
+ $canvas_widget bind $item <Leave> "$this key_leave $i"
+ $canvas_widget bind $item <Button-1> "$this key_click $i"
+ }
+ }
+ }
+
+ ## Determinate which port pin is connected to the specified key
+ # @parm Int i - Key number
+ # @return List - {port_number bit_number}
+ private method which_port_pin {i} {
+ return [list $connection_port($i) $connection_pin($i)]
+ }
+
+ ## Handle "ON/OFF" button press
+ # Turn whole PALE system on or off
+ # @return void
+ public method on_off_button_press {} {
+ $project pale_all_on_off
+ }
+
+ ## Determinate color for wires
+ # @parm Char state - Wire state
+ # @return Color - Wire color
+ private method which_color {state} {
+ switch -- $state {
+ {} { ;# Not connected
+ return {#000000}
+ }
+ {0} { ;# Logical 0
+ return {#00FF00}
+ }
+ {1} { ;# Logical 1
+ return {#FF0000}
+ }
+ {=} { ;# High forced to low
+ return {#FF00AA}
+ }
+ {?} { ;# No volatge
+ return {#888888}
+ }
+ default {
+ return {#FF8800}
+ }
+ }
+ }
+
+ ## Value of configuration menu variable "menu_radio_buttons" has been changed
+ # @return void
+ public method value_radio_buttons_changed {} {
+ set radio_buttons $::MatrixKeyPad::menu_radio_buttons
+ }
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE
+ # ------------------------------------------------------------------
+
+ ## Simulated MCU has been changed
+ # @return void
+ public method mcu_changed {} {
+ # Refresh lists of possible values in port selection ComboBoxes
+ set avaliable_ports [concat - [$project pale_get_avaliable_ports]]
+
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_p$i configure -values $avaliable_ports
+
+ if {[lsearch -ascii -exact $avaliable_ports $connection_port($i)] == -1} {
+ $canvas_widget.cb_p$i current 0
+ set connection_port($i) {-}
+ }
+ }
+ }
+
+ ## Evaluate new state of ports
+ # @parm List state - Port states ( 5 x {8 x bit} -- {bit0 bit1 bit2 ... bit7} )
+ # @return state - New port states modified by this device
+ # format is the same as parameter $state
+ #
+ # Possible bit values:
+ # '|' - High frequency
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ # '0' - Logical 0
+ # '1' - Logical 1
+ public method new_state {state} {
+ # Local variables
+ set row_state [list {} {} {} {}] ;# State of rows
+ set col_state [list {} {} {} {}] ;# State of columns
+
+ # Load state of rows and columns from $state
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin $i]
+
+ # Not connected -> Leave it
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ continue
+ }
+
+ # Rows
+ if {$i < 4} {
+ lset row_state $i [lindex $state $pp]
+ # Columns
+ } {
+ lset col_state [expr {$i - 4}] [lindex $state $pp]
+ }
+ }
+
+ ## Determinate new state of rows and columns
+ # Local variables
+ set r_state {} ;# State of current row
+ set c_state {} ;# State of current column
+ set new {} ;# Result from $r_state vs. $c_state clash
+ set changes 1 ;# Number of changes in $r_state or $c_state
+ while {$changes} {
+ # Local variables
+ set k_i 0 ;# Key number (0..15)
+
+ # Iterate over rows
+ for {set r 0} {$r < 4} {incr r} {
+ # Iterate over columns
+ for {set c 0} {$c < 4} {incr c} {
+
+ # Key is pressed -> determinate new state of its row and column
+ if {$keys($k_i)} {
+ # Determinate state of current row and column
+ set r_state [lindex $row_state $r]
+ set c_state [lindex $col_state $c]
+
+ # Determinate new common state for this row and column
+ set new [$project pale_combine_values \
+ $r_state $c_state \
+ ]
+
+ # Detect change
+ if {
+ $new != $r_state
+ ||
+ $new != $c_state
+ } then {
+ incr changes
+ }
+
+ # Set row and column new state
+ lset row_state $r $new
+ lset col_state $c $new
+ }
+
+ # Go to the next key
+ incr k_i
+ }
+ }
+
+ # One change in row/column states was accepted
+ incr changes -1
+ }
+
+ # Adjust input data to the new values
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin $i]
+
+ # Not connected -> Leave it
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ continue
+ }
+
+ # Rows
+ if {$i < 4} {
+ lset state $pp [lindex $row_state $i]
+ # Columns
+ } {
+ lset state $pp [lindex $col_state [expr {$i - 4}]]
+ }
+ }
+
+ ## Adjust wire colors
+ # Rows
+ for {set i 0} {$i < 4} {incr i} {
+ set color [which_color [lindex $row_state $i]]
+ foreach item $row_wire($i) {
+ $canvas_widget itemconfigure $item -fill $color
+ }
+ }
+ # Columns
+ for {set i 0} {$i < 4} {incr i} {
+ set color [which_color [lindex $col_state $i]]
+ foreach item $col_wire($i) {
+ $canvas_widget itemconfigure $item -fill $color
+ }
+ }
+
+ # Return new port states
+ return $state
+ }
+
+ ## Withdraw panel window from the screen
+ # @return void
+ public method withdraw_window {} {
+ wm withdraw $win
+ }
+
+ ## Get panel configuration list (usable with method "set_config")
+ # @return List - configuration list
+ public method get_config {} {
+ return [list \
+ $class_name \
+ [list \
+ [array get connection_port] \
+ [array get connection_pin] \
+ [wm geometry $win] \
+ [$canvas_widget.usr_note get] \
+ [array get keys] \
+ $radio_buttons \
+ ] \
+ ]
+ }
+
+ ## Set panel configuration from list gained from method "get_config"
+ # @parm List state - Configuration list
+ # @return void
+ public method set_config {state} {
+ if {[catch {
+ # Load connections to the MCU
+ array set connection_port [lindex $state 0]
+ array set connection_pin [lindex $state 1]
+
+ # Restore window geometry
+ if {[string length [lindex $state 2]]} {
+ wm geometry $win [lindex $state 2]
+ }
+
+ # Load user note
+ $canvas_widget.usr_note delete 0
+ $canvas_widget.usr_note insert 0 [lindex $state 3]
+
+ # Restore keys configuration and states
+ array set keys [lindex $state 4]
+ set radio_buttons [lindex $state 5]
+
+ # Restore state of ComboBoxes
+ for {set i 0} {$i < 8} {incr i} {
+ ## PIN
+ set pin $connection_pin($i)
+ if {$pin != {-}} {
+ set pin [expr {7 - $pin}]
+ }
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_b$i cget -values] \
+ $pin \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_b$i current $idx
+
+ ## PORT
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_p$i cget -values] \
+ $connection_port($i) \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_p$i current $idx
+ }
+
+ # Adjust key apparences
+ for {set i 0} {$i < 16} {incr i} {
+ key_state_changed $i
+ }
+
+ # Adjust internal logic and the rest of PALE
+ evaluete_enaged_pins
+ $project pale_reevaluate_IO
+ update
+
+ # Fail
+ }]} then {
+ puts "Unable to load config for $class_name"
+ return 0
+
+ # Success
+ } else {
+ clear_modified
+ return 1
+ }
+ }
+
+ ## Simulated MCU has been reseted
+ # @return void
+ public method reset {} {
+ $project pale_reevaluate_IO
+ }
+
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+ # ------------------------------------------------------------------
+
+ ## This method is called before configuration menu invocation
+ # @return void
+ public method config_menu_special {} {
+ set ::MatrixKeyPad::menu_radio_buttons $radio_buttons
+ }
+
+ ## This method is called after configuration menu has beed created
+ # @return void
+ public method create_config_menu_special {} {
+ }
+
+ ## This method is called to fill in the help dialog
+ # @parm Widget text_widget - Target text widget
+ # @return void
+ #
+ # Note: There is defined text tag "tag_bold" in the text widget
+ public method show_help_special {text_widget} {
+ $text_widget insert insert [mc "This tool consists of 16 switches connected in matrix. Connections with the uC are made with ComboBoxes. Panel configuration can be saved to a file (with extension vhc). And can be loaded from that file later. Wire colors are identical to colors used in graph representing IO ports.\n\n"]
+ $text_widget insert insert [mc "Keypad can be configured in two ways:"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc "\n "]
+ $text_widget insert insert [mc "1)"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc " To allow key combinations\n Menu -> Check \"Radio buttons\"\n "]
+ $text_widget insert insert [mc "2)"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc " To do not allow key combinations\n Menu -> Uncheck \"Radio buttons\""]
+ }
+
+ ## This method is called before panel window closure
+ # @return void
+ public method close_window_special {} {
+ }
+
+ ## Commit new on/off state
+ # @return void
+ public method on_off_special {} {
+ new_state [$project pale_get_true_state]
+ }
+}
diff --git a/lib/pale/multiplexedleddisplay.tcl b/lib/pale/multiplexedleddisplay.tcl
new file mode 100755
index 0000000..78976ad
--- /dev/null
+++ b/lib/pale/multiplexedleddisplay.tcl
@@ -0,0 +1,1179 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements PALE VHW component "Multiplexed LED display"
+#
+# Consists of:
+# INTERNAL APPLICATION LOGIC
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM PALE ENGINE
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+# --------------------------------------------------------------------------
+
+class MultiplexedLedDisplay {
+ inherit VirtualHWComponent
+
+ # Font: Font to be used in the panel -- bold
+ common cb_font [font create \
+ -weight bold -size -10 \
+ -family {helvetica} \
+ ]
+ common COMPONENT_NAME "Multiplexed LED display" ;# Name of this component
+ common CLASS_NAME "MultiplexedLedDisplay" ;# Name of this class
+ common COMPONENT_ICON {mleddisplay} ;# Icon for this panel (16x16)
+
+ ## Colors for display segments
+ # There are 6 lists (red orange yellow green blue purple)
+ # and each of them contain 3 colors (semi-dim bright dim)
+ common COLORS {
+ {#AA5555 #FF0000 #FF5555}
+ {#AAAA55 #FF8800 #FFCC55}
+ {#AAAA55 #FFFF00 #FFFF55}
+
+ {#55AA55 #00FF00 #55FF55}
+ {#5555AA #0000FF #5555FF}
+ {#AA55AA #8800FF #CC55FF}
+ }
+
+ # Configuration menu
+ common CONFMENU {
+ {cascade {Common electrode} 7 "diode" .ca false 1 {
+ {radiobutton "Common anode" {}
+ ::MultiplexedLedDisplay::cfg_common_anode 1
+ "common_electrode_chanded" 7 ""}
+ {radiobutton "Common catode" {}
+ ::MultiplexedLedDisplay::cfg_common_anode 0
+ "common_electrode_chanded" 7 ""}
+ }}
+ {cascade {Fade out interval} 5 "player_time" .dim false 1 {
+ {radiobutton "0" {}
+ ::MultiplexedLedDisplay::dim_interval 0
+ "dim_interval_changed" -1
+ "Set LED dim interval to 0 instruction cycles"}
+ {radiobutton "5" {}
+ ::MultiplexedLedDisplay::dim_interval 5
+ "dim_interval_changed" -1
+ "Set LED dim interval to 5 instruction cycles"}
+ {radiobutton "10" {}
+ ::MultiplexedLedDisplay::dim_interval 10
+ "dim_interval_changed" -1
+ "Set LED dim interval to 10 instruction cycles"}
+ {radiobutton "20" {}
+ ::MultiplexedLedDisplay::dim_interval 20
+ "dim_interval_changed" -1
+ "Set LED dim interval to 20 instruction cycles"}
+ {radiobutton "50" {}
+ ::MultiplexedLedDisplay::dim_interval 50
+ "dim_interval_changed" -1
+ "Set LED dim interval to 50 instruction cycles"}
+ {radiobutton "100" {}
+ ::MultiplexedLedDisplay::dim_interval 100
+ "dim_interval_changed" -1
+ "Set LED dim interval to 100 instruction cycles"}
+ {radiobutton "200" {}
+ ::MultiplexedLedDisplay::dim_interval 200
+ "dim_interval_changed" -1
+ "Set LED dim interval to 200 instruction cycles"}
+ {radiobutton "500" {}
+ ::MultiplexedLedDisplay::dim_interval 500
+ "dim_interval_changed" -1
+ "Set LED dim interval to 500 instruction cycles"}
+ {radiobutton "1000" {}
+ ::MultiplexedLedDisplay::dim_interval 1000
+ "dim_interval_changed" -1
+ "Set LED dim interval to 1000 instruction cycles"}
+ }}
+ {cascade {Color} 0 "colorize" .color false 1 {
+ {radiobutton "Red" {}
+ ::MultiplexedLedDisplay::color {red}
+ "color_changed" 0 ""}
+ {radiobutton "Orange" {}
+ ::MultiplexedLedDisplay::color {orange}
+ "color_changed" 0 ""}
+ {radiobutton "Yellow" {}
+ ::MultiplexedLedDisplay::color {yellow}
+ "color_changed" 0 ""}
+ {radiobutton "Green" {}
+ ::MultiplexedLedDisplay::color {green}
+ "color_changed" 0 ""}
+ {radiobutton "Blue" {}
+ ::MultiplexedLedDisplay::color {blue}
+ "color_changed" 0 ""}
+ {radiobutton "Purple" {}
+ ::MultiplexedLedDisplay::color {purple}
+ "color_changed" 0 ""}
+ }}
+ {separator}
+ {command {All fade out} {} 0 "dim_all" {ledgray}
+ "Dim all leds"}
+ {command {Show help} {} 5 "show_help" {help}
+ "Show brief help"}
+ {separator}
+ {command {Save configuration} {} 0 "save_as" {filesave}
+ "Save configuration into a file"}
+ {command {Load configuration} {} 0 "load_from" {fileopen}
+ "Load configuration from a file"}
+ }
+
+ private variable conf_dim_interval 50 ;# Int: Interval to dim LED's in instruction cycles
+ private variable conf_led_color {red} ;# Color: Selected color for display segments
+
+ private variable leds ;# Array of CanvasObject (polygon): leds(display_num,segment_num) --> LED polygon
+ ## Array of CanvasObject (line):
+ # wires(n) --> wire connected to LED's [n e {0..7}]
+ # wires(Tn) --> wire connected transistor [n e {0..3}]
+ private variable wires
+ private variable connection_port ;# Array of Int: Index is key number, value is port number or {-}
+ private variable connection_pin ;# Array of Int: Index is key number, value is bit number or {-}
+ private variable prev_state ;# List: Previous port states
+ private variable common_anode 1 ;# Bool: 1 == common anode; 0 == common catode
+
+ private variable t_state ;# List: Transistor states
+
+
+ # ------------------------------------------------------------------
+ # INTERNAL APPLICATION LOGIC
+ # ------------------------------------------------------------------
+
+ ## Object constructor
+ # @parm Object _project - Project object
+ constructor {_project} {
+ # Set object variables identifing this component (see the base class)
+ set component_name $COMPONENT_NAME
+ set class_name $CLASS_NAME
+ set component_icon $COMPONENT_ICON
+
+ # Set other object variables
+ set project $_project
+ array set connection_port {
+ 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -
+ T0 - T1 - T2 - T3 -
+ }
+ array set connection_pin {
+ 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -
+ T0 - T1 - T2 - T3 -
+ }
+ for {set j 0} {$j < 4} {incr j} {
+ for {set i 0} {$i < 8} {incr i} {
+ set prev_state($j,$i) 0
+ }
+ }
+
+ # Inform PALE
+ $project pale_register_output_device $this
+ $project pale_set_modified
+
+ # Create panel GUI
+ create_gui
+ mcu_changed
+ on_off [$project pale_is_enabled]
+
+ # ComboBoxes to default state
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_b$i current 0
+ $canvas_widget.cb_p$i current 0
+ }
+ for {set i 0} {$i < 4} {incr i} {
+ $canvas_widget.cb_t_p$i current 0
+ $canvas_widget.cb_t_b$i current 0
+ }
+ }
+
+ ## Object destructor
+ destructor {
+ # Inform PALE
+ $project pale_unregister_output_device $this
+
+ # Destroy GUI
+ destroy $win
+ }
+
+ ## Create GUI of this panel
+ # @return void
+ private method create_gui {} {
+ # Create panel window and canvas widget
+ set win [toplevel .multiplexedleddisplay$count -class {Mult. LED Display} -bg {#EEEEEE}]
+ set canvas_widget [canvas $win.canvas \
+ -bg white -width 0 -height 0 \
+ -highlightthickness 0 \
+ ]
+
+ # Draw display and wires
+ set x 90
+ set y 15
+ draw_connections $x $y
+ for {set i 0} {$i < 4} {incr i} {
+ draw_8_segment $x $y [expr {3 - $i}]
+ draw_wires $x $y [lindex {0 1 1 0} $i]
+
+ incr x 80
+ }
+
+ # Create ComboBoxes
+ set tx_p_y 150
+ set cb_p_y 168
+ set cb_b_y 188
+ set x 110
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget create window $x $cb_p_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_p$i \
+ -width 1 \
+ -font $cb_font \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_p$i <<ComboboxSelected>> "$this reconnect S $i"
+
+ $canvas_widget create window $x $cb_b_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_b$i \
+ -width 1 \
+ -font $cb_font \
+ -values {- 0 1 2 3 4 5 6 7} \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_b$i <<ComboboxSelected>> "$this reconnect S $i"
+
+ bindtags $canvas_widget.cb_p$i \
+ [list $canvas_widget.cb_p$i TCombobox all .]
+ bindtags $canvas_widget.cb_b$i \
+ [list $canvas_widget.cb_b$i TCombobox all .]
+
+ lappend wires($i) [$canvas_widget create text \
+ [expr {$x - 3}] $tx_p_y \
+ -text [lindex {A B C D E F G P} $i] \
+ -font $cb_font -fill #000000 -anchor e \
+ ]
+
+ lappend wires($i) [$canvas_widget create line \
+ $x $cb_p_y $x [expr {100 + $y + 4*$i}] \
+ -width 1 -fill #000000 \
+ ]
+
+ if {[lindex {0 0 1 1 1 1 0 1} $i]} {
+ lappend wires($i) [$canvas_widget create oval \
+ [expr {$x - 2}] [expr {100 + $y + 4*$i - 2}] \
+ [expr {$x + 2}] [expr {100 + $y + 4*$i + 2}] \
+ -width 0 -fill #000000 \
+ ]
+ }
+
+ incr x 40
+ }
+
+ # Draw junctions
+ set x 90
+ set y 15
+ foreach coords {
+ {244 122 248 126}
+ {76 98 80 102}
+ {72 102 76 106}
+ } index {
+ 6
+ 0
+ 1
+ } {
+ set coordinates [list]
+ set len [llength $coords]
+
+ for {set m 0; set n 1} {$n < $len} {incr m 2; incr n 2} {
+ lappend coordinates \
+ [expr {[lindex $coords $m] + $x}]
+ lappend coordinates \
+ [expr {[lindex $coords $n] + $y}]
+ }
+
+ lappend wires($index) [$canvas_widget create oval \
+ $coordinates -width 0 -fill #000000 \
+ ]
+ }
+
+ # Draw transistors and their ComboBoxes
+ set cb_x 30
+ set cb_y 55
+ set tr_x 55
+ set tr_y 45
+
+ set txA_x 50
+ set txA_y 33
+ set txB_x 105
+ set txB_y 30
+ for {set i 0} {$i < 4} {incr i} {
+ draw_transistor $tr_x $tr_y $i
+
+ $canvas_widget create window $cb_x $cb_y -anchor e \
+ -window [ttk::combobox $canvas_widget.cb_t_p$i \
+ -width 1 \
+ -font $cb_font \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_t_p$i <<ComboboxSelected>> "$this reconnect T $i"
+
+ $canvas_widget create window $cb_x $cb_y -anchor w \
+ -window [ttk::combobox $canvas_widget.cb_t_b$i \
+ -width 1 \
+ -font $cb_font \
+ -values {- 0 1 2 3 4 5 6 7} \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_t_b$i <<ComboboxSelected>> "$this reconnect T $i"
+
+ bindtags $canvas_widget.cb_t_p$i \
+ [list $canvas_widget.cb_t_p$i TCombobox all .]
+ bindtags $canvas_widget.cb_t_b$i \
+ [list $canvas_widget.cb_t_b$i TCombobox all .]
+
+ set x_foo [expr {$tr_x + 18 + 4 + 4*$i}]
+ set x_bar [expr {135 + (3 - $i)*80}]
+ set wires(T$i) [$canvas_widget create line \
+ [expr {$tr_x + 18}] $tr_y \
+ $x_foo $tr_y \
+ $x_foo [expr {2 + $i*4}] \
+ $x_bar [expr {2 + $i*4}] \
+ $x_bar 19 \
+ -width 1 -fill #000000 \
+ ]
+ lappend wires(T$i) [$canvas_widget create line \
+ [expr {$x_bar - 38}] 30 \
+ [expr {$x_bar - 38}] 19 \
+ [expr {$x_bar + 38}] 19 \
+ [expr {$x_bar + 38}] 30 \
+ -width 2 -fill #000000 \
+ ]
+
+ $canvas_widget create text $txA_x $txA_y \
+ -text $i -font $cb_font
+ $canvas_widget create text $txB_x $txB_y \
+ -text [expr {3 - $i}] -font $cb_font
+
+ incr tr_y 40
+ incr cb_y 40
+ incr txA_y 40
+ incr txB_x 80
+ }
+
+ # Create "ON/OFF" button
+ set start_stop_button [ttk::button $canvas_widget.start_stop_button \
+ -command "$this on_off_button_press" \
+ -style Flat.TButton \
+ -width 3 \
+ ]
+ DynamicHelp::add $canvas_widget.start_stop_button \
+ -text [mc "Turn HW simulation on/off"]
+ setStatusTip -widget $start_stop_button -text [mc "Turn HW simulation on/off"]
+ bind $start_stop_button <Button-3> "$this on_off_button_press; break"
+ $canvas_widget create window 22 2 -window $start_stop_button -anchor nw
+ bindtags $start_stop_button [list $start_stop_button TButton all .]
+
+ # Create configuration menu button
+ set conf_button [ttk::button $canvas_widget.conf_but \
+ -image ::ICONS::16::configure \
+ -style FlatWhite.TButton \
+ -command "$this config_menu" \
+ ]
+ setStatusTip -widget $conf_button -text [mc "Configure"]
+ $canvas_widget create window 20 2 -window $conf_button -anchor ne
+ bindtags $conf_button [list $conf_button TButton all .]
+
+ # Create EntryBox for user note
+ $canvas_widget create text 40 210 \
+ -text {Note} \
+ -font $cb_font \
+ -anchor e
+ $canvas_widget create window 40 210 \
+ -window [ttk::entry $canvas_widget.usr_note \
+ -validate all \
+ -validatecommand "$this set_modified" \
+ ] \
+ -width 380 -anchor w
+ bindtags $canvas_widget.usr_note \
+ [list $canvas_widget.usr_note TEntry $win all .]
+
+ # Pack canvas
+ pack $canvas_widget -fill both -expand 1
+
+ # Set window parameters
+ wm geometry $win =425x225
+ wm iconphoto $win ::ICONS::16::$component_icon
+ wm title $win "[mc $component_name] - [string trim $project {:}] - MCU 8051 IDE"
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "$this close_window"
+ bindtags $win [list $win Toplevel all .]
+ }
+
+ ## LED dim interval changed (meaningfull for multiplexed mode)
+ # @return void
+ public method dim_interval_changed {} {
+ set conf_dim_interval ${::MultiplexedLedDisplay::dim_interval}
+ set_modified
+ }
+
+ ## LED's common electrode chanded
+ # @return void
+ public method common_electrode_chanded {} {
+ set common_anode ${::MultiplexedLedDisplay::cfg_common_anode}
+
+ if {$drawing_on} {
+ dim_all
+ new_state [$project pale_get_true_state] 1
+ }
+ set_modified
+ }
+
+ ## LED color changed
+ # @return void
+ public method color_changed {} {
+ set conf_led_color ${::MultiplexedLedDisplay::color}
+
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state] 1
+ }
+ set_modified
+ }
+
+ ## Dim all LED's and reset their prevoius states
+ # @return void
+ public method dim_all {} {
+ for {set i 0} {$i < 8} {incr i} {
+ for {set j 0} {$j < 4} {incr j} {
+ if {$prev_state($j,$i)} {
+ set prev_state($j,$i) 0
+ $canvas_widget itemconfigure $leds($j,$i) \
+ -fill {#555555} -outline {#FFFFFF}
+ }
+ }
+ }
+ }
+
+ ## Reconnect the specified key to another port pin
+ # @parm Char type - Connection type ('S' => Segment; 'T' => Transistor)
+ # @parm Int i - Connection wire (type == 'S' => {0..3} ^ type == 'T' => {0..7})
+ # @return void
+ public method reconnect {type i} {
+ # Adjust connections
+ if {$type == {S}} {
+ set connection_port($i) [$canvas_widget.cb_p$i get]
+ set connection_pin($i) [$canvas_widget.cb_b$i get]
+ if {$connection_pin($i) != {-}} {
+ set connection_pin($i) [expr {7 - $connection_pin($i)}]
+ }
+ } {
+ set connection_port(T$i) [$canvas_widget.cb_t_p$i get]
+ set connection_pin(T$i) [$canvas_widget.cb_t_b$i get]
+ if {$connection_pin(T$i) != {-}} {
+ set connection_pin(T$i) [expr {7 - $connection_pin(T$i)}]
+ }
+ }
+
+ # Change state of the device
+ if {$drawing_on} {
+ new_state [$project pale_get_true_state] 1
+ }
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## Draw PNP transistor
+ # @parm Int x - X origin coordinate
+ # @parm Int y - Y origin coordinate
+ # @parm Int index - 0..3
+ # @return void
+ private method draw_transistor {x y index} {
+ set coords {
+ 0 9 8 9 8 0 8 18 8 9
+ 9 9 18 0 9 9 18 18 18 24
+ }
+# 11 11 11 15 11 11 15 11 11 11
+
+ # Transform coordinates -- adjust them to the given origin
+ set coordinates [list]
+ set len [llength $coords]
+ for {set m 0; set n 1} {$n < $len} {incr m 2; incr n 2} {
+ lappend coordinates \
+ [expr {[lindex $coords $m] + $x}]
+ lappend coordinates \
+ [expr {[lindex $coords $n] + $y}]
+ }
+
+ # Draw transistor
+ $canvas_widget create line $coordinates \
+ -tags transistor -width 1 -fill #000000
+
+ # Draw supply pin
+ $canvas_widget create oval \
+ [expr {$x + 15}] [expr {$y + 24}] \
+ [expr {$x + 21}] [expr {$y + 30}] \
+ -tags transistor -width 1 -outline #000000
+ }
+
+ ## Draw wires connecting all 4 displays
+ # @parm Int x - X origin coordinate
+ # @parm Int y - Y origin coordinate
+ # @return void
+ private method draw_connections {x y} {
+ set coords {
+ {
+ 20 100 319 100
+ } {
+ 60 104 315 104
+ } {
+ 70 108 311 108
+ } {
+ 35 112 276 112
+ } {
+ 10 116 251 116
+ } {
+ 2 120 243 120
+ } {
+ 6 124 260 124
+ } {
+ 64 128 305 128
+ }
+ }
+
+ # Transform coordinates -- adjust them to the given origin
+ #+ Draw wires
+ for {set i 0} {$i < 8} {incr i} {
+ set coordinates [list]
+ set local_coords [lindex $coords $i]
+ set len [llength $local_coords]
+
+ # Adjust
+ for {set m 0; set n 1} {$n < $len} {incr m 2; incr n 2} {
+ lappend coordinates \
+ [expr {[lindex $local_coords $m] + $x}]
+ lappend coordinates \
+ [expr {[lindex $local_coords $n] + $y}]
+ }
+
+ # Draw
+ set wires($i) [$canvas_widget create line \
+ $coordinates -width 1 -fill #000000 \
+ ]
+ }
+ }
+
+ ## Draw wires from LED's
+ # @parm Int x - X origin coordinate
+ # @parm Int y - Y origin coordinate
+ # @parm Bool junction - Draw juction at the end of the wire
+ # @return void
+ private method draw_wires {x y junction} {
+ set coords {
+ {
+ 46 10 46 8 78 8 78 100
+ } {
+ 70 37 74 37 74 104
+ } {
+ 64 72 70 72 70 108
+ } {
+ 35 95 35 112
+ } {
+ 14 70 10 70 10 116
+ } {
+ 19 33 2 33 2 120
+ } {
+ 25 53 6 53 6 124
+ } {
+ 64 96 64 128
+ }
+ }
+
+ # Transform coordinates -- adjust them to the given origin
+ #+ Draw wires
+ for {set i 0} {$i < 8} {incr i} {
+ set coordinates [list]
+ set local_coords [lindex $coords $i]
+ set len [llength $local_coords]
+
+ # Adjust
+ for {set m 0; set n 1} {$n < $len} {incr m 2; incr n 2} {
+ lappend coordinates \
+ [expr {[lindex $local_coords $m] + $x}]
+ lappend coordinates \
+ [expr {[lindex $local_coords $n] + $y}]
+ }
+
+ # Draw wire
+ lappend wires($i) [$canvas_widget create line \
+ $coordinates -width 1 -fill #000000 \
+ ]
+
+ # Draw junction
+ if {$junction} {
+ set oval [expr {[lindex $coordinates end-1] - 2}]
+ lappend oval [expr {[lindex $coordinates end] - 2}]
+ lappend oval [expr {[lindex $coordinates end-1] + 2}]
+ lappend oval [expr {[lindex $coordinates end] + 2}]
+ lappend wires($i) [$canvas_widget create oval \
+ $oval -width 0 -fill #000000 \
+ ]
+ }
+ }
+ }
+
+ ## Draw one LED display
+ # @parm Int x - X origin coordinate
+ # @parm Int y - Y origin coordinate
+ # @parm Int index - Display index
+ # @return void
+ private method draw_8_segment {x y index} {
+ set coords {
+ {
+ 19 7 25 1 47 1 53 7 53 8
+ 47 14 25 14 19 8
+ } {
+ 55 9 62 16 58 34 50 42 44 36
+ 49 15 55 9
+ } {
+ 50 45 57 52 53 70 46 77 45 77
+ 39 71 44 51 50 45
+ } {
+ 15 73 38 73 44 79 37 86 15 86
+ 9 80 9 79
+ } {
+ 7 78 15 70 19 52 12 45 5 52
+ 1 72
+ } {
+ 12 42 20 34 25 16 17 9 10 16
+ 6 36
+ } {
+ 14 43 20 37 42 37 48 43 48 44
+ 42 50 20 50 14 44
+ }
+ }
+
+ # Transform coordinates -- adjust them to the given origin
+ #+ Draw LED polygons -- for segments A..G
+ for {set i 0} {$i < 7} {incr i} {
+ set coordinates [list]
+ set local_coords [lindex $coords $i]
+ set len [llength $local_coords]
+
+ # Adjust
+ for {set m 0; set n 1} {$n < $len} {incr m 2; incr n 2} {
+ lappend coordinates \
+ [expr {[lindex $local_coords $m] + $x + 10}]
+ lappend coordinates \
+ [expr {[lindex $local_coords $n] + $y + 10}]
+ }
+
+ # Draw
+ set leds($index,$i) [$canvas_widget create polygon \
+ $coordinates -width 0 -fill #555555 \
+ ]
+ }
+
+ # Transform coordinates -- adjust them to the given origin
+ #+ Draw LED oval -- for segment P (point)
+ set leds($index,7) [$canvas_widget create oval \
+ [expr {49 + $x + 10}] [expr {77 + $y + 10}] \
+ [expr {58 + $x + 10}] [expr {86 + $y + 10}] \
+ -width 0 -fill #555555 \
+ ]
+
+ # Print segment labels
+ foreach coords {{35 7} {53 25} {48 62} {26 79} {10 61} {15 25} {31 43}} \
+ text {A B C D E F G} \
+ {
+ $canvas_widget create text \
+ [expr {[lindex $coords 0] + $x + 10}] \
+ [expr {[lindex $coords 1] + $y + 10}] \
+ -text $text -fill {#FFFFFF} \
+ -font $::smallfont
+ }
+ }
+
+ ## Determinate which port pin is connected to the specified wire
+ # @parm Char type - Connection type ('S' => Segment; 'T' => Transistor)
+ # @parm Int i - Connection wire (type == 'S' => {0..3} ^ type == 'T' => {0..7})
+ # @return void
+ private method which_port_pin {type i} {
+ if {$type == {S}} {
+ return [list $connection_port($i) $connection_pin($i)]
+ } {
+ return [list $connection_port(T$i) $connection_pin(T$i)]
+ }
+ }
+
+ ## Handle "ON/OFF" button press
+ # Turn whole PALE system on or off
+ # @return void
+ public method on_off_button_press {} {
+ $project pale_all_on_off
+ }
+
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE
+ # ------------------------------------------------------------------
+
+ ## Simulated MCU has been changed
+ # @return void
+ public method mcu_changed {} {
+ # Refresh lists of possible values in port selection ComboBoxes
+ set avaliable_ports [concat - [$project pale_get_avaliable_ports]]
+
+ # For segments ...
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_p$i configure -values $avaliable_ports
+
+ if {[lsearch -ascii -exact $avaliable_ports $connection_port($i)] == -1} {
+ $canvas_widget.cb_p$i current 0
+ set connection_port($i) {-}
+ }
+ }
+
+ # For transistors ...
+ for {set i 0} {$i < 4} {incr i} {
+ $canvas_widget.cb_t_p$i configure -values $avaliable_ports
+
+ if {[lsearch -ascii -exact $avaliable_ports $connection_port(T$i)] == -1} {
+ $canvas_widget.cb_t_p$i current 0
+ set connection_port(T$i) {-}
+ }
+ }
+ }
+
+ ## Accept new state of ports
+ # @parm List state - Port states ( 5 x {8 x bit} -- {bit0 bit1 bit2 ... bit7} )
+ # @parm Bool preserve_prvious_state = 0 - Preserve previous state of component
+ # @return void
+ #
+ # Possible bit values:
+ # '|' - High frequency
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ # '0' - Logical 0
+ # '1' - Logical 1
+ public method new_state {state {preserve_prvious_state 0}} {
+ # Determinate index of LED color in list COLORS
+ set color_idx [lsearch -ascii -exact \
+ {red orange yellow green blue purple} \
+ $conf_led_color \
+ ]
+
+ # Determinate which displays are online and which are offline
+ for {set i 0} {$i < 4} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin T $i]
+
+ # Not connected
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ set t_state($i) {}
+ # Connected
+ } {
+ set t_state($i) [lindex $state $pp]
+ }
+
+ # Determinate state
+ switch -- $t_state($i) {
+ {0} { ;# Logical 0
+ if {$common_anode} {
+ set t_state($i) 2
+ } {
+ set t_state($i) 0
+ }
+ set wire_color {#FF0000}
+ }
+ {1} { ;# Logical 1
+ if {$common_anode} {
+ set t_state($i) 0
+ } {
+ set t_state($i) 2
+ }
+ set wire_color {#00FF00}
+ }
+ {=} { ;# High forced to low
+ if {$common_anode} {
+ set t_state($i) 2
+ } {
+ set t_state($i) 0
+ }
+ set wire_color {#00FF00}
+ }
+ {?} { ;# No volatge
+ set t_state($i) 0
+ set wire_color {#888888}
+ }
+ {} { ;# Not connected
+ set t_state($i) 0
+ set wire_color {#000000}
+ }
+ default {
+ set t_state($i) 1
+ set wire_color {#FF8800}
+ }
+ }
+
+ # Adjust wire colors
+ foreach item $wires(T$i) {
+ $canvas_widget itemconfigure $item -fill $wire_color
+ }
+ }
+
+ # Adjust displays
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin S $i]
+
+ # Not connected
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-}} {
+ for {set j 0} {$j < 4} {incr j} {
+ $canvas_widget itemconfigure $leds($j,$i) -fill {#555555}
+ }
+ foreach item $wires($i) {
+ $canvas_widget itemconfigure $item -fill {#000000}
+ }
+ continue
+ }
+
+ # Determinate state
+ set state_pp [lindex $state $pp]
+
+ # Adjust wire colors
+ switch -- $state_pp {
+ {0} { ;# Logical 0
+ set wire_color {#00FF00}
+ }
+ {1} { ;# Logical 1
+ set wire_color {#FF0000}
+ }
+ {=} { ;# High forced to low
+ set wire_color {#FF00AA}
+ }
+ {} { ;# Not connected
+ set wire_color {#000000}
+ }
+ {?} { ;# No volatge
+ set wire_color {#888888}
+ }
+ default {
+ set wire_color {#FF8800}
+ }
+ }
+ foreach item $wires($i) {
+ $canvas_widget itemconfigure $item -fill $wire_color
+ }
+
+ # Adjust displays
+ for {set j 0} {$j < 4} {incr j} {
+
+ # Determinate segment color number
+ switch -- $state_pp {
+ {0} { ;# Logical 0
+ if {$common_anode} {
+ switch -- $t_state($j) {
+ {2} {
+ set segment_color {2}
+ }
+ {1} {
+ set segment_color {1}
+ }
+ {0} {
+ set segment_color {0}
+ }
+ }
+ } {
+ set segment_color {0}
+ }
+ }
+ {1} { ;# Logical 1
+ if {$common_anode} {
+ set segment_color {0}
+ } {
+ switch -- $t_state($j) {
+ {2} {
+ set segment_color {2}
+ }
+ {1} {
+ set segment_color {1}
+ }
+ {0} {
+ set segment_color {0}
+ }
+ }
+ }
+ }
+ {=} { ;# High forced to low
+ set segment_color {0}
+ }
+ {} { ;# Not connected
+ set segment_color {0}
+ }
+ {?} { ;# No volatge
+ set segment_color {0}
+ }
+ default {
+ switch -- $t_state($j) {
+ {2} {
+ set segment_color {1}
+ }
+ {1} {
+ set segment_color {0}
+ }
+ {0} {
+ set segment_color {0}
+ }
+ }
+ }
+ }
+
+ ## LED's dims with delay ...
+ set outline {#FFFFFF}
+ # Dim with delay
+ if {$segment_color == {0}} {
+ if {$prev_state($j,$i) == {}} {
+ set prev_state($j,$i) 0
+ }
+ if {$prev_state($j,$i)} {
+ if {!$preserve_prvious_state} {
+ incr prev_state($j,$i) -1
+ }
+ if {$prev_state($j,$i)} {
+ set segment_color {3}
+ }
+ }
+ # Light up now
+ } elseif {$segment_color == {2}} {
+ if {!$preserve_prvious_state} {
+ set prev_state($j,$i) $conf_dim_interval
+ }
+ set outline [lindex $COLORS [list $color_idx $segment_color]]
+ }
+
+ # Determinate segment color (true color, not just number)
+ if {!$segment_color} {
+ set segment_color {#555555}
+ } {
+ incr segment_color -1
+ set segment_color [lindex $COLORS [list $color_idx $segment_color]]
+ }
+
+ # Change segment color
+ $canvas_widget itemconfigure $leds($j,$i) \
+ -fill $segment_color -outline $outline
+ }
+ }
+ }
+
+ ## Withdraw panel window from the screen
+ # @return void
+ public method withdraw_window {} {
+ wm withdraw $win
+ }
+
+ ## Get panel configuration list (usable with method "set_config")
+ # @return List - configuration list
+ public method get_config {} {
+ return [list \
+ $class_name \
+ [list \
+ [array get connection_port] \
+ [array get connection_pin] \
+ [wm geometry $win] \
+ [$canvas_widget.usr_note get] \
+ $conf_led_color \
+ $conf_dim_interval \
+ $common_anode \
+ ] \
+ ]
+ }
+
+ ## Set panel configuration from list gained from method "get_config"
+ # @parm List state - Configuration list
+ # @return void
+ public method set_config {state} {
+ if {[catch {
+ # Load connections to the MCU
+ array set connection_port [lindex $state 0]
+ array set connection_pin [lindex $state 1]
+
+ # Restore window geometry
+ if {[string length [lindex $state 2]]} {
+ wm geometry $win [lindex $state 2]
+ }
+
+ # Load user note
+ $canvas_widget.usr_note delete 0
+ $canvas_widget.usr_note insert 0 [lindex $state 3]
+
+ # Restore LED's configuration
+ set conf_led_color [lindex $state 4]
+ set conf_dim_interval [lindex $state 5]
+ set common_anode [lindex $state 6]
+ if {$common_anode == {}} {
+ set common_anode 1
+ }
+
+ ## Restore state of ComboBoxes
+ # For segments ...
+ for {set i 0} {$i < 8} {incr i} {
+ ## PIN
+ set pin $connection_pin($i)
+ if {$pin != {-}} {
+ set pin [expr {7 - $pin}]
+ }
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_b$i cget -values] \
+ $pin \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_b$i current $idx
+
+ ## PORT
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_p$i cget -values] \
+ $connection_port($i) \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_p$i current $idx
+ }
+ # For transistors ...
+ for {set i 0} {$i < 4} {incr i} {
+ ## PIN
+ set pin $connection_pin(T$i)
+ if {$pin != {-}} {
+ set pin [expr {7 - $pin}]
+ }
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_t_b$i cget -values] \
+ $pin \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_t_b$i current $idx
+
+ ## PORT
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_t_p$i cget -values] \
+ $connection_port(T$i) \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_t_p$i current $idx
+ }
+
+ # Accept new state of ports
+ new_state [$project pale_get_true_state]
+ update
+
+ # Fail
+ }]} then {
+ puts stderr "Unable to load config for $class_name"
+ puts stderr $::errorInfo
+ return 0
+
+ # Success
+ } else {
+ clear_modified
+ return 1
+ }
+ }
+
+ ## Simulated MCU has been reseted
+ # @return void
+ public method reset {} {
+ dim_all
+ new_state [$project pale_get_true_state]
+ }
+
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+ # ------------------------------------------------------------------
+
+ ## This method is called before configuration menu invocation
+ # @return void
+ public method config_menu_special {} {
+ set ::${class_name}::dim_interval $conf_dim_interval
+ set ::${class_name}::color $conf_led_color
+ set ::${class_name}::cfg_common_anode $common_anode
+ }
+
+ ## This method is called after configuration menu has beed created
+ # @return void
+ public method create_config_menu_special {} {
+ foreach item { Red Orange Yellow Green Blue Purple } \
+ color { #DD0000 #DD8800 #DDDD00 #00DD00 #0000DD #8800DD } \
+ {
+ $conf_menu.color entryconfigure [::mc $item] -foreground $color
+ }
+ }
+
+ ## This method is called to fill in the help dialog
+ # @parm Widget text_widget - Target text widget
+ # @return void
+ #
+ # Note: There is defined text tag "tag_bold" in the text widget
+ public method show_help_special {text_widget} {
+ $text_widget insert insert [mc "Virtual multiplexed LED display with common anode (default) or catode. Each segment can be connected to any port pin of the simulated uC. Connections with the uC are made with ComboBoxes. Panel configuration can be saved to a file (with extension vhc). And can be loaded from that file later. LED fade out interval and LED colors are configurable\n\n"]
+
+ set color_idx [lsearch -ascii -exact \
+ {red orange yellow green blue purple} \
+ $conf_led_color \
+ ]
+
+ $text_widget insert insert [mc "LED states:"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc "\n "]
+ $text_widget window create insert -pady 1 -create "frame $text_widget.f0 -bd 1 -width 14 -height 16 -bg #888888"
+ $text_widget insert insert [mc " Off\n "]
+ $text_widget window create insert -pady 1 -create "frame $text_widget.f1 -bd 1 -width 14 -height 16 -bg [lindex $COLORS [list $color_idx 0]]"
+ $text_widget insert insert [mc " Fast blinking\n "]
+ $text_widget window create insert -pady 1 -create "frame $text_widget.f2 -bd 1 -width 14 -height 16 -bg [lindex $COLORS [list $color_idx 1]]"
+ $text_widget insert insert [mc " Shining\n "]
+ $text_widget window create insert -pady 1 -create "frame $text_widget.f3 -bd 1 -width 14 -height 16 -bg [lindex $COLORS [list $color_idx 2]]"
+ $text_widget insert insert [mc " Fading out\n "]
+ }
+
+ ## This method is called before panel window closure
+ # @return void
+ public method close_window_special {} {
+ }
+
+ ## Commit new on/off state
+ # @return void
+ public method on_off_special {} {
+ if {!$drawing_on} {
+ for {set j 0} {$j < 4} {incr j} {
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget itemconfigure $leds($j,$i) -fill {#555555}
+ foreach item $wires($i) {
+ $canvas_widget itemconfigure $item -fill {#000000}
+ }
+ }
+ }
+ } {
+ new_state [$project pale_get_true_state] 1
+ }
+ }
+}
diff --git a/lib/pale/pale.tcl b/lib/pale/pale.tcl
new file mode 100755
index 0000000..3b4b61c
--- /dev/null
+++ b/lib/pale/pale.tcl
@@ -0,0 +1,991 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# PALE (Peripheral Abstraction Layer Engine) - simulates virtual hardware
+# --------------------------------------------------------------------------
+
+# Load base class for Virtual HW components
+source "${::LIB_DIRNAME}/pale/virtual_hw_component.tcl"
+
+# Load Virtual HW components
+source "${::LIB_DIRNAME}/pale/ledpanel.tcl"
+source "${::LIB_DIRNAME}/pale/leddisplay.tcl"
+source "${::LIB_DIRNAME}/pale/ledmatrix.tcl"
+source "${::LIB_DIRNAME}/pale/multiplexedleddisplay.tcl"
+source "${::LIB_DIRNAME}/pale/simplekeypad.tcl"
+source "${::LIB_DIRNAME}/pale/matrixkeypad.tcl"
+
+class Pale {
+ private variable scenario_file {} ;# String: Name of PALE scenario file
+
+ private variable portLatch {} ;# List: Nx{5x{8x{...}}} States of port latches
+ private variable portState {} ;# List: Nx{5x{8x{...}}} True port states
+ private variable portOutput {} ;# List: Nx{5x{8x{...}}} True port outputs
+ private variable portInput {} ;# List: 5x{8x{...}} Port inputs
+ private variable special_func {} ;# List: Values of alternative port functions
+ private variable portConfig ;# Array of Int: Index 0..4, defines port pin functions
+ private variable portConfig_mod 0 ;# Bool: $portConfig contain special configuration
+
+ private variable instruction_cycles 0 ;# Int: Nummber of instruction cycles performed during this simulation cycle
+
+ private variable last_output {} ;# List: 5x{8x{...}} Last port outputs
+ private variable last_input {} ;# List: 5x{8x{...}} Last port inputs
+ private variable last_state {} ;# List: 5x{8x{...}} Last true port states
+
+ private variable input_devices [list] ;# List of Object: Input devices (can affect true state)
+ private variable output_devices [list] ;# List of Object: Output devices (cannot affect true state)
+ private variable engaged_pins ;# Array of Lists of Objects: Output devices which uses pin specified by index (index: (port_num,pin_num))
+
+ private variable is_enabled 0 ;# Bool: PALE sysetem on-line
+ private variable modified 0 ;# Bool: Modified flag
+
+ ## Object constructor
+ # Perform PALE sysetem reset
+ constructor {} {
+ pale_reset
+
+ for {set p 0} {$p < 5} {incr p} {
+ for {set b 0} {$b < 8} {incr b} {
+ set engaged_pins($p,$b) {}
+ }
+ }
+ }
+
+ ## Object destructor
+ # Save PALE scenarion file and destroy all PALE VHW components
+ destructor {
+ pale_save_scenario_file
+
+ foreach dev [concat $output_devices $input_devices] {
+ delete object $dev
+ }
+ }
+
+ ## Save PALE scenario under the specified file name
+ # @parm String filename - Name of the target file
+ # @return Bool - 1 upon success; 0 upon fail
+ public method pale_save_as {filename} {
+ set scenario_file_org $scenario_file
+ set scenario_file [file join [$this cget -ProjectDir] $filename]
+
+ # Adjust file extension
+ if {![regexp {\.vhw$} $scenario_file]} {
+ append scenario_file {.vhw}
+ }
+
+ if {[pale_save_scenario_file]} {
+ return 1
+ }
+
+ set scenario_file $scenario_file_org
+ return 0
+ }
+
+ ## Save PALE scenario to a file
+ # If there is no predefined file name then it will call "::X::__save_as_VHW"
+ # @return Bool - 1 upon success; 0 upon fail
+ public method pale_save {} {
+ if {$scenario_file == {}} {
+ ::X::__save_as_VHW
+ return 0
+ }
+ return [pale_save_scenario_file]
+ }
+
+ ## Save PALE scenario to a file
+ # @return void
+ public method pale_save_scenario_file {} {
+ # Abort on empty file name
+ if {$scenario_file == {}} {
+ return 0
+ }
+
+ # Create a backup file
+ catch {
+ file rename -force $scenario_file "$scenario_file~"
+ }
+
+ # Try to open the file
+ if {[catch {
+ set file [open $scenario_file "w" 420]
+ }]} then {
+ puts stderr "Unable to save to file: \"$scenario_file\""
+ return 0
+ }
+
+ # Save data to the file
+ puts $file "# MCU 8051 IDE: Virtual HW configuration file"
+ puts $file "# Date: [clock format [clock seconds] -format {%D}]"
+ puts $file "# Project: [string trim $this {:}]\n"
+ foreach dev [concat $output_devices $input_devices] {
+ puts $file [$dev get_config]
+ }
+
+ # Finalize
+ catch {
+ close $file
+ }
+ set modified 0
+ return 1
+ }
+
+ ## Get value of flag modified
+ # @return Bool - The modified flag
+ public method pale_modified {} {
+ return $modified
+ }
+
+ ## Set flag modified
+ # @return Bool - Always 1
+ public method pale_set_modified {} {
+ set modified 1
+
+ return 1
+ }
+
+ ## Get name of PALE scenarion file
+ # @return String - Name of the file
+ public method pale_get_scenario_filename {} {
+ # Determinate project root path
+ set prj_path [$this cget -projectPath]
+ append prj_path {/}
+
+ # Return relative directory location
+ if {![string first $prj_path $scenario_file]} {
+ return [string range $scenario_file [string length $prj_path] end]
+ # Return absolute directory location
+ } {
+ return $scenario_file
+ }
+ }
+
+ ## Remove all devices from the current scenarion
+ # @return void
+ public method pale_remove_all_devices {} {
+ foreach dev [concat $output_devices $input_devices] {
+ delete object $dev
+ }
+ }
+
+ ## Reset pale to initial state
+ # @return void
+ public method pale_forget_all {} {
+ pale_remove_all_devices
+ set scenario_file {}
+ set modified 0
+ }
+
+ ## Open the specified PALE scenarion file
+ # @parm String filename - Source file
+ # @return Int - Exit status
+ # 0 - Ok
+ # 1 - Error
+ # 2 - File is not usable
+ public method pale_open_scenario {filename} {
+ set filename [file join [$this cget -ProjectDir] $filename]
+ if {
+ ![file exists $filename] ||
+ ![file isfile $filename] ||
+ (!$::MICROSOFT_WINDOWS && ![file readable $filename])
+ } {
+ return 0
+ }
+
+ pale_remove_all_devices
+
+ set scenario_file $filename
+ set modified 0
+ return [pale_load_scenarion $filename]
+ }
+
+ ## Import the specified PALE scenarion file
+ # @parm String filename - Source file
+ # @return Int - Exit status
+ # 0 - Ok
+ # 1 - Error
+ # 2 - File is not usable
+ public method pale_load_scenarion {filename} {
+ # Check for file usability
+ if {![file exists $filename] || ![file isfile $filename] || (!$::MICROSOFT_WINDOWS && ![file readable $filename])} {
+ return 2
+ }
+
+ # Try to open the specified file
+ if {[catch {
+ set file [open $filename {r}]
+ }]} then {
+ puts stderr "Unable to open file: \"$scenario_file\", that might not be important ..."
+ return 1
+ }
+
+ # Read the file line by line
+ set result 0
+ while {![eof $file]} {
+ set line [gets $file]
+
+ # Skip empty lines and comments
+ if {$line == {} || [regexp {^\s*#} $line]} {continue}
+
+ # Decomposite file records
+ set obj [lindex $line 0] ;# VHW component class name
+ set conf [lindex $line 1] ;# VHW component configuration
+
+ # Create component object and set its configuration
+ if {[catch {
+ set obj [$obj ::#auto $this]
+ $obj set_config $conf
+ # Error detected
+ }]} then {
+ puts stderr "Unable to create PALE object: \"$obj\", maybe you are using old version of MCU 8051 IDE\n"
+ puts stderr $::errorInfo
+
+ catch {
+ delete object $obj
+ }
+
+ set result 1
+ }
+ }
+
+ # Finalize ...
+ catch {
+ close $file
+ }
+ set modified 1
+ return $result
+ }
+
+ ## Reset whole PALE system
+ # @return void
+ public method pale_reset {} {
+ set portConfig_mod 0
+ array set portConfig {
+ 0 {0 0 0 0 0 0 0 0}
+ 1 {0 0 0 0 0 0 0 0}
+ 2 {0 0 0 0 0 0 0 0}
+ 3 {0 0 0 0 0 0 0 0}
+ 4 {0 0 0 0 0 0 0 0}
+ }
+ set last_output [list \
+ [list 1 1 1 1 1 1 1 1] \
+ [list 1 1 1 1 1 1 1 1] \
+ [list 1 1 1 1 1 1 1 1] \
+ [list 1 1 1 1 1 1 1 1] \
+ [list 1 1 1 1 1 1 1 1] \
+ ]
+ set last_input $last_output
+ set last_state $last_output
+ set portState [list $last_output]
+
+ foreach dev [concat $input_devices $output_devices] {
+ $dev reset
+ }
+
+ pale_reevaluate_IO
+ }
+
+ ## Withdraw windows of all PALE components
+ # Usefull to speedup exit program procedure
+ # @return void
+ public method pale_withdraw_all_windows {} {
+ foreach dev [concat $output_devices $input_devices] {
+ $dev withdraw_window
+ }
+ }
+
+ ## Inform pale about interrupt comminted by simulatoe
+ # @parm Int vector - Interrupt vector
+ # @return void
+ public method pale_interrupt {vector} {
+ $this graph_draw_interrupt_line
+ }
+
+ ## Perform one PALE simulation cycle
+ # @parm List - State of 5 port latches
+ # @return void
+ public method pale_simulation_cycle args {
+ if {!$is_enabled} {return}
+
+ set ports [list]
+ foreach byte [lindex $args 0] {
+ set byte [NumSystem::dec2bin $byte]
+ set bin_len [string length $byte]
+ if {$bin_len < 8} {
+ set byte "[string repeat {0} [expr {8 - $bin_len}]]$byte"
+ }
+
+ lappend ports [split $byte {}]
+ }
+ lappend portLatch $ports
+ incr instruction_cycles
+ }
+
+ ## Set Line Special Function (Bypass port latch)
+ # @parm List port_and_bit - {port_number bit_number}
+ # @parm Int type - Function
+ # 0 - Nomal operation -- port latch is outputed
+ # 1 - Special logical IO function (UART, triggers, external memory, etc.)
+ # 2 - High speed digital output (possibly a few pulses per instruction cycle)
+ # 3 - PWM output (it's low speed logical output)
+ # 4 - Analog comparator input (accepts values between 0 and 1)
+ # 5 - External memory
+ # 6 - Not implemented pin
+ # @return void
+ public method pale_SLSF {port_and_bit type} {
+ # Modify ports configuration
+ lset portConfig([lindex $port_and_bit 0]) \
+ [expr {7 - [lindex $port_and_bit 1]}] $type
+
+ # Adjust flag portConfig_mod
+ set portConfig_mod 0
+ for {set i 0} {$i < 5} {incr i} {
+ for {set j 0} {$j < 5} {incr j} {
+ if {[lindex $portConfig($i) $j] != 0} {
+ set portConfig_mod 1
+ return
+ }
+ }
+ }
+ }
+
+ ## Read Real Port Voltage - 8 bit value (0..255)
+ # @parm Int port - Port number
+ # @return Int - Port value
+ public method pale_RRPV {port} {
+ if {!$is_enabled} {return 255}
+
+ set result_tmp [lindex $portState [list end $port]]
+ set result {}
+ foreach bit $result_tmp {
+ switch -- $bit {
+ {?} { ;# No volatge
+ append result [expr {rand() < 0.5}]
+ }
+ {X} { ;# Access to external memory
+ append result [expr {rand() < 0.5}]
+ }
+ {-} { ;# Undeterminable value (some noise)
+ append result [expr {rand() < 0.5}]
+ }
+ {|} { ;# High frequency
+ append result 1
+ }
+ {=} { ;# High forced to low
+ append result 0
+ }
+ default {
+ append result $bit
+ }
+ }
+ }
+ set result [NumSystem::bin2dec $result]
+ return $result
+ }
+
+ ## Read Real Port Pin Voltage - 1 bit value (0 or 1)
+ # @parm List - {port_number bit_number}
+ # @parm Int = 0 - Position in history (positive number)
+ # @return Bool - Boolean value
+ public method pale_RRPPV args {
+ if {!$is_enabled} {return 1}
+
+ # Parse input arguments
+ set port [lindex $args {0 0}]
+ set bit [lindex $args {0 1}]
+ set position [lindex $args 1]
+
+ # Adjust arguments
+ if {![string length $position]} {
+ set position 0
+ } elseif {$position < 0} {
+ set position [expr {[llength $portState] + $position}]
+ }
+ set bit [expr {7 - $bit}]
+
+ # Evaluate result
+ set result [lindex $portState [list $position $port $bit]]
+ switch -- $result {
+ {?} { ;# No volatge
+ return [expr {rand() < 0.5}]
+ }
+ {X} { ;# Access to external memory
+ return [expr {rand() < 0.5}]
+ }
+ {|} { ;# High frequency
+ return 1
+ }
+ {1} { ;# Logical 1
+ return 1
+ }
+ {0} { ;# Logical 0
+ return 0
+ }
+ {=} { ;# High forced to low
+ return 0
+ }
+ default {
+ return 1
+ }
+ }
+ }
+
+ ## Write to port with bypassed latch (takes effect on next simulation cycle)
+ # @parm Int - Port number
+ # @parm List - New value -- list of 8 values {bit0 bit1 bit2 ... bit7}
+ # '0' - Logical 0
+ # '1' - Logical 1
+ # '|' - High frequency pulse
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ # @parm Int = 0 - Position in history (zero or negative number)
+ # @return void
+ public method pale_WPBL args {
+ if {!$is_enabled} {return}
+
+ # Parse input arguments
+ set port [lindex $args 0]
+ set value [lindex $args 1]
+ set position [lindex $args 2]
+
+ # Adjust arguments
+ if {![string length $position]} {
+ set position 0
+ }
+
+ # Set value
+ for {set bit 0} {$bit < 8} {incr bit} {
+ lappend special_func [list $port $bit $value $position]
+ }
+ }
+
+ ## Write to port bit with bypassed latch
+ # @parm List - {port_number bit_number}
+ # @parm Char - New value
+ # '0' - Logical 0
+ # '1' - Logical 1
+ # '|' - High frequency pulse
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ # @parm Int = 0 - Position in history (zero or negative number)
+ # @return void
+ public method pale_WPBBL args {
+ if {!$is_enabled} {return}
+
+ # Parse input arguments
+ set port [lindex $args {0 0}]
+ set bit [lindex $args {0 1}]
+ set value [lindex $args 1]
+ set position [lindex $args 2]
+
+ # Adjust arguments
+ if {![string length $position]} {
+ set position 0
+ }
+ set bit [expr {7 - $bit}]
+
+ # Set value
+ lappend special_func [list $port $bit $value $position]
+ }
+
+ ## Finalize this simulation cycle
+ # @return void
+ public method pale_finish_simulation_cycle {} {
+ if {!$is_enabled} {return}
+
+ # ---------------------------------------------------
+ # DETERMINATE TRUE OUTPUT VALUES
+ # ---------------------------------------------------
+ set portOutput $portLatch
+
+ if {$portConfig_mod} {
+ # Adjust port outputs to contain '#' where are the
+ #+ bits with active alternative function
+ for {set port 0} {$port < 5} {incr port} {
+ for {set bit 0} {$bit < 8} {incr bit} {
+ switch -- [lindex $portConfig($port) $bit] {
+ 0 { ;# Nomal operation -- port latch is outputed
+ }
+ 1 { ;# Special logical IO function (UART, triggers, external memory, etc.)
+ for {set i 0} {$i < $instruction_cycles} {incr i} {
+ lset portOutput [list $i $port $bit] {#}
+ }
+ }
+ 2 { ;# High speed digital output (possibly a few pulses per machine cycle)
+ for {set i 0} {$i < $instruction_cycles} {incr i} {
+ lset portOutput [list $i $port $bit] {#}
+ }
+ }
+ 3 { ;# PWM output (it's low speed logical output)
+ for {set i 0} {$i < $instruction_cycles} {incr i} {
+ lset portOutput [list $i $port $bit] {#}
+ }
+ }
+ 4 { ;# Analog comparator input (accepts values between 0 and 1)
+ for {set i 0} {$i < $instruction_cycles} {incr i} {
+ lset portOutput [list $i $port $bit] {?}
+ }
+ }
+ 5 { ;# Access to external memory
+ for {set i 0} {$i < $instruction_cycles} {incr i} {
+ lset portOutput [list $i $port $bit] {X}
+ }
+ }
+ 6 { ;# Not implemented pin
+ for {set i 0} {$i < $instruction_cycles} {incr i} {
+ lset portOutput [list $i $port $bit] {?}
+ }
+ }
+ }
+ }
+ }
+ # Adjust port outputs to contain values generated by alternaive functions
+ foreach spec $special_func {
+ set port [lindex $spec 0]
+ set bit [lindex $spec 1]
+ set value [lindex $spec 2]
+ set position [lindex $spec 3]
+
+ incr position $instruction_cycles
+ incr position -1
+
+ lset portOutput [list $position $port $bit] $value
+ }
+ # Adjust port outputs to repeat previous values on
+ #+ bits with active alternative function.
+ #+ In other words, eliminate all '#' and replace them with reasonable values
+ for {set i -1; set j 0} {$j < $instruction_cycles} {incr i; incr j} {
+ if {$i < 0} {
+ set previous_output_state $last_output
+ } {
+ set previous_output_state [lindex $portOutput $i]
+ }
+ foreach prev $previous_output_state new [lindex $portOutput $j] port {0 1 2 3 4} {
+ if {[lsearch -ascii -exact $new {#}] != -1} {
+ foreach p $prev n $new bit {0 1 2 3 4 5 6 7} {
+ switch -- $n {
+ {#} { ;# Repeat last value
+ lset portOutput [list $j $port $bit] $p
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ # ---------------------------------------------------
+ # DETERMINATE TRUE STATE
+ # ---------------------------------------------------
+
+ # Call input devices to evaluate input values
+ read_port_input
+
+ # Determinate true port states using function "pale_combine_values"
+ #+ and graw graphs
+ set graw_graph [expr {![$this sim_run_in_progress]}]
+ set portState [list]
+ set state_one_p [list]
+ set state_all_p [list]
+ for {set i 0} {$i < $instruction_cycles} {incr i} {
+ foreach output [lindex $portOutput $i] input [lindex $portInput $i] {
+ foreach out $output in $input {
+ lappend state_one_p [pale_combine_values $in $out]
+ }
+
+ lappend state_all_p $state_one_p
+ set state_one_p [list]
+ }
+
+ if {$graw_graph} {
+ $this graph_new_output_state L [lindex $portLatch $i]
+ $this graph_new_output_state O [lindex $portOutput $i]
+ $this graph_new_output_state S $state_all_p
+ }
+
+ lappend portState $state_all_p
+ set state_all_p [list]
+ }
+
+ # Clean up
+ set instruction_cycles 0
+ set last_output [lindex $portOutput end]
+ set last_input [lindex $portInput end]
+ set last_state [lindex $portState end]
+ set portLatch [list]
+ set portOutput [list]
+ set portInput [list]
+ set special_func [list]
+
+ # Inform output devices about the new port outputs
+ foreach dev $output_devices {
+ $dev new_state $last_state
+ update
+ }
+ }
+
+ ## Determinate resulting value when two values clash on one wire
+ # @parm Char in0 - 1st wire state
+ # @parm Char in1 - The other wire state
+ # @return Char - Resulting state
+ public method pale_combine_values {in0 in1} {
+ if {$in1 == 0} {
+ return {0}
+ } elseif {$in1 == {}} {
+ return $in0
+ }
+ switch -- $in0 {
+ {|} { ;# High frequency
+ if {$in1 == 1 || $in1 == {|} || $in1 == {?}} {
+ return {|}
+ } else {
+ return {-}
+ }
+ }
+ {X} { ;# Access to external memory
+ if {$in1 == 1 || $in1 == {X} || $in1 == {?}} {
+ return {X}
+ } else {
+ return {-}
+ }
+ }
+ {?} { ;# No volatge
+ return $in1
+ }
+ {-} { ;# Undeterminable value (some noise)
+ return {-}
+ }
+ {=} { ;# High forced to low
+ return {=}
+ }
+ {0} { ;# Logical 0
+ return 0
+ }
+ {1} { ;# Logical 1
+ if {$in1 == {?}} {
+ return 1
+ } {
+ return $in1
+ }
+ }
+ {} { ;# Not connected
+ return $in1
+ }
+ default {
+ error "ERROR in function pale_combine_value\npale_combine_values {{$in0} {$in1}}"
+ }
+ }
+ }
+
+ ## Reevaluate inputs & outputs for all PALE devices and the MCU
+ # @return void
+ public method pale_reevaluate_IO {} {
+ # Get last output
+ set input $last_output
+
+ # Call all input devices
+ foreach dev $input_devices {
+ # Call device to change the current state
+ set input [$dev new_state $input]
+ update
+
+ # Inform all other devices interconnected with this one
+ for {set p 0} {$p < 5} {incr p} {
+ for {set b 0} {$b < 8} {incr b} {
+ # Search for connected devices
+ set idx [lsearch -ascii -exact $engaged_pins($p,$b) $dev]
+ if {$idx == -1} {
+ continue
+ }
+ if {[llength $engaged_pins($p,$b)] == 1} {
+ continue
+ }
+
+ # Call all affected devices
+ foreach affected_dev $engaged_pins($p,$b) {
+ if {$affected_dev == $dev} {
+ continue
+ }
+
+ set input [$affected_dev new_state $input]
+ update
+ }
+
+ # Again call the current device
+ set input [$dev new_state $input]
+ update
+ }
+ }
+ }
+ set last_input $input
+
+ # Determinate true port states using function "pale_combine_values"
+ set state_one_p [list]
+ set last_state [list]
+ foreach output $last_output input $last_input {
+ foreach out $output in $input {
+ lappend state_one_p [pale_combine_values $in $out]
+ }
+
+ lappend last_state $state_one_p
+ set state_one_p [list]
+ }
+
+ # Update more complex information about true port states
+ set portState [lreplace $portState end end $last_state]
+
+ # Inform output devices about the new port outputs
+ foreach dev $output_devices {
+ $dev new_state $last_state
+ update
+ }
+ }
+
+ ## Call input devices to evaluate input values
+ # @return void
+ private method read_port_input {} {
+ # Get last output
+ set input [lindex $portOutput end]
+
+ # Call all input devices
+ foreach dev $input_devices {
+ # Call device to change the current state
+ set input [$dev new_state $input]
+ update
+
+ # Inform all other devices interconnected with this one
+ for {set p 0} {$p < 5} {incr p} {
+ for {set b 0} {$b < 8} {incr b} {
+ # Search for connected devices
+ set idx [lsearch -ascii -exact $engaged_pins($p,$b) $dev]
+ if {$idx == -1} {
+ continue
+ }
+ if {[llength $engaged_pins($p,$b)] == 1} {
+ continue
+ }
+
+ # Call all affected devices
+ foreach affected_dev $engaged_pins($p,$b) {
+ if {$affected_dev == $dev} {
+ continue
+ }
+
+ set input [$affected_dev new_state $input]
+ update
+ }
+
+ # Again call the current device
+ set input [$dev new_state $input]
+ update
+ }
+ }
+ }
+
+ # Fill in list of port onputs
+ for {set i 1} {$i < $instruction_cycles} {incr i} {
+ lappend portInput $last_input
+ }
+ lappend portInput $input
+ }
+
+ ## Adjust PALE to new state "ON/OFF"
+ # @parm Bool _is_enabled - 1 == Turn on; 0 == Turn off
+ # @return void
+ public method pale_on_off {_is_enabled} {
+ set is_enabled $_is_enabled
+
+ foreach dev [concat $input_devices $output_devices] {
+ $dev on_off $is_enabled
+ }
+ }
+
+ ## Turn whole PALE system on or off
+ # @return void
+ public method pale_all_on_off {} {
+ $this graph_change_status_on
+ }
+
+ ## Determinate whether PALE is on-line or not
+ # @return Bool - 1 == online; 0 - offline
+ public method pale_is_enabled {} {
+ return $is_enabled
+ }
+
+ ## Inform PALE about new output device (device which CANNOT affect port inputs)
+ # Every output device must be registred in PALE system in
+ #+ this way otherwise it wont work !
+ # @parm Object object - PALE VHW component object reference
+ # @return void
+ #
+ # Note: PALE VHW component must extend class "VirtualHWComponent"
+ public method pale_register_output_device {object} {
+ lappend output_devices $object
+ }
+
+ ## Unregister device prevously registred by "pale_register_output_device"
+ # @parm Object object - PALE VHW component object reference
+ # @return void
+ public method pale_unregister_output_device {object} {
+ set idx [lsearch -ascii -exact $output_devices $object]
+ if {$idx == -1} {
+ return
+ }
+ set output_devices [lreplace $output_devices $idx $idx]
+ }
+
+ ## Inform PALE about new input device (device which CAN affect port inputs)
+ # Every input device must be registred in PALE system in
+ #+ this way otherwise it wont work !
+ # @parm Object object - PALE VHW component object reference
+ # @return void
+ #
+ # Note: PALE VHW component must extend class "VirtualHWComponent"
+ public method pale_register_input_device {object} {
+ lappend input_devices $object
+ }
+
+ ## Unregister device prevously registred by "pale_register_input_device"
+ # @parm Object object - PALE VHW component object reference
+ # @return void
+ public method pale_unregister_input_device {object} {
+ # Find the specified device
+ set idx [lsearch -ascii -exact $input_devices $object]
+ if {$idx == -1} {
+ return
+ }
+
+ # Unregister the device
+ set input_devices [lreplace $input_devices $idx $idx]
+
+ # Disconnect the device from all other devices
+ for {set p 0} {$p < 5} {incr p} {
+ for {set b 0} {$b < 8} {incr b} {
+ pale_disengage_pin_by_input_device $p $b $object
+ }
+ }
+ }
+
+ ## Inform PALE system about that than some input device is
+ #+ connected to the specified port and pin.
+ #
+ # THIS IS VERY IMPORTANT FUNCTION to achieve correct PALE
+ # system functionality !!!
+ #
+ # @parm Int port - Port number (0..4)
+ # @parm Int pin - Port bit number (0..7)
+ # @parm Object dev - Input device (PALE VHW component)
+ # @return void
+ #
+ # Notes:
+ # * PALE VHW component must extend class "VirtualHWComponent"
+ # * Input devices CAN affect port inputs, output cannot
+ public method pale_engage_pin_by_input_device {port pin dev} {
+ lappend engaged_pins($port,$pin) $dev
+ }
+
+ ## Inform PALE system about that than some input device is
+ #+ no longer connected to the specified port and pin.
+ # In other words the right opposite of method
+ # "pale_engage_pin_by_input_device".
+ #
+ # THIS IS VERY IMPORTANT FUNCTION to achieve correct PALE
+ # system functionality !!!
+ #
+ # @parm Int port - Port number (0..4)
+ # @parm Int pin - Port bit number (0..7)
+ # @parm Object dev - Input device (PALE VHW component)
+ # @return void
+ #
+ # Notes:
+ # * PALE VHW component must extend class "VirtualHWComponent"
+ # * Input devices CAN affect port inputs, output cannot
+ public method pale_disengage_pin_by_input_device {port pin dev} {
+ set idx [lsearch -ascii -exact $engaged_pins($port,$pin) $dev]
+ if {$idx == -1} {
+ return
+ }
+
+ set engaged_pins($port,$pin) \
+ [lreplace $engaged_pins($port,$pin) $idx $idx]
+ }
+
+ ## Determinate whether the specified port pin is engaged
+ # by any input device
+ # @parm Int port - Port number (0..4)
+ # @parm Int pin - Port bit number (0..7)
+ # @return void
+ #
+ # Note: Input devices CAN affect port inputs, output cannot
+ public method pale_is_engaged {port pin} {
+ return $engaged_pins($port,$pin)
+ }
+
+ ## Get true port outputs (that means latches plus alternate functions)
+ # @return List of Char - 5 x {8 x $bit_val} -- {bit0 bit1 bit2 ... bit7}
+ # $bit_val can be one of the following values:
+ # '0' - Logical 0
+ # '1' - Logical 1
+ # '|' - High frequency pulse
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ public method pale_get_output_state {} {
+ return $last_output
+ }
+
+ ## Get true port states
+ # @return List of Char - 5 x {8 x $bit_val} -- {bit0 bit1 bit2 ... bit7}
+ # $bit_val can be one of the following values:
+ # '0' - Logical 0
+ # '1' - Logical 1
+ # '|' - High frequency pulse
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ public method pale_get_true_state {} {
+ return $last_state
+ }
+
+ ## Get list of avaliable port number on the current MCU
+ # @return List of Int - e.g. {1 3}
+ public method pale_get_avaliable_ports {} {
+ return [lindex [$this get_ports_info] 1]
+ }
+
+ ## Inform PALE sysetem about MCU change
+ # @return void
+ public method pale_MCU_changed {} {
+ foreach dev [concat $input_devices $output_devices] {
+ $dev mcu_changed
+ }
+ }
+}
diff --git a/lib/pale/simplekeypad.tcl b/lib/pale/simplekeypad.tcl
new file mode 100755
index 0000000..d7baa83
--- /dev/null
+++ b/lib/pale/simplekeypad.tcl
@@ -0,0 +1,670 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements PALE VHW component "Simple Keypad"
+#
+# Consists of:
+# INTERNAL APPLICATION LOGIC
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM PALE ENGINE
+# VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+# --------------------------------------------------------------------------
+
+class SimpleKeyPad {
+ inherit VirtualHWComponent
+
+ # Font: Font to be used in the panel -- bold
+ common cb_font [font create \
+ -weight bold \
+ -size -10 \
+ -family {helvetica} \
+ ]
+ # Font: Font to be used in the panel -- normal weight
+ common cb_font_n [font create \
+ -size -10 \
+ -family {helvetica} \
+ ]
+
+ common COMPONENT_NAME "Simple Keypad" ;# Name of this component
+ common CLASS_NAME "SimpleKeyPad" ;# Name of this class
+ common COMPONENT_ICON {simplekeypad} ;# Icon for this panel (16x16)
+
+ # Configuration menu
+ common CONFMENU {
+ {checkbutton "Radio buttons" {} {::SimpleKeyPad::menu_radio_buttons}
+ 1 0 0 {value_radio_buttons_changed}
+ ""}
+ {command {Show help} {} 5 "show_help" {help}
+ "Show brief help"}
+ {separator}
+ {command {Save configuration} {} 0 "save_as" {filesave}
+ "Save configuration into a file"}
+ {command {Load configuration} {} 0 "load_from" {fileopen}
+ "Load configuration from a file"}
+ }
+
+ private variable radio_buttons ;# Bool: Disallow key combinations
+ private variable keys ;# Array of Bool: Indicates key press
+ private variable wire ;# Array of CanvasObject (line): Wires connected to MCU pins
+ private variable wire_o ;# Array of CanvasObject (oval): Wires connected to MCU pins
+ private variable rect ;# Array of CanvasObject (rectangle): Key rectangles
+ private variable lever ;# Array of CanvasObject (line): Key levers
+ private variable text ;# Array of CanvasObject (text): Key descriptions
+ private variable connection_port ;# Array of Int: Index is key number, value is port number or {-}
+ private variable connection_pin ;# Array of Int: Index is key number, value is bit number or {-}
+ private variable enaged ;# Array of Bool: enaged(port_num,bit_num) --> Is connected to this device ?
+
+
+ # ------------------------------------------------------------------
+ # INTERNAL APPLICATION LOGIC
+ # ------------------------------------------------------------------
+
+ ## Object constructor
+ # @parm Object _project - Project object
+ constructor {_project} {
+ # Set object variables identifing this component (see the base class)
+ set component_name $COMPONENT_NAME
+ set class_name $CLASS_NAME
+ set component_icon $COMPONENT_ICON
+
+ # Set other object variables
+ set project $_project
+ set radio_buttons 1
+ array set connection_port {0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -}
+ array set connection_pin {0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 -}
+ array set keys {0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0}
+ for {set port 0} {$port < 5} {incr port} {
+ for {set bit 0} {$bit < 8} {incr bit} {
+ set enaged($port,$bit) 0
+ }
+ }
+
+ # Inform PALE
+ $project pale_register_input_device $this
+ $project pale_set_modified
+
+ # Create panel GUI
+ create_gui
+ mcu_changed
+ on_off [$project pale_is_enabled]
+
+ # ComboBoxes to default state
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_b$i current 0
+ $canvas_widget.cb_p$i current 0
+ }
+ }
+
+ ## Object destructor
+ destructor {
+ # Inform PALE
+ $project pale_unregister_input_device $this
+
+ # Destroy GUI
+ destroy $win
+ }
+
+ ## Reevaluate array of MCU port pins engaged by this device
+ # @return void
+ private method evaluete_enaged_pins {} {
+ # Mark all as disengaged and infrom PALE
+ for {set port 0} {$port < 5} {incr port} {
+ for {set bit 0} {$bit < 8} {incr bit} {
+ if {$enaged($port,$bit)} {
+ $project pale_disengage_pin_by_input_device $port $bit $this
+ set enaged($port,$bit) 0
+ }
+ }
+ }
+
+ # Find the engaged ones and infrom PALE
+ for {set i 0} {$i < 8} {incr i} {
+ set port $connection_port($i)
+ set bit $connection_pin($i)
+
+ if {$port == {-} || $bit == {-}} {
+ continue
+ }
+
+ set enaged($port,$bit) 1
+ $project pale_engage_pin_by_input_device $port $bit $this
+ }
+ }
+
+ ## Reconnect the specified key to another port pin
+ # @parm Int i - Key number (0..7)
+ # @return void
+ public method reconnect {i} {
+ # Adjust connections
+ set connection_port($i) [$canvas_widget.cb_p$i get]
+ set connection_pin($i) [$canvas_widget.cb_b$i get]
+ if {$connection_pin($i) != {-}} {
+ set connection_pin($i) [expr {7 - $connection_pin($i)}]
+ }
+
+ # Reevaluate array of MCU port pins engaged by this device
+ evaluete_enaged_pins
+
+ # Inform PALE system about the change in order
+ #+ to make immediate change in device states
+ if {$drawing_on} {
+ $project pale_reevaluate_IO
+ }
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## Create GUI of this panel
+ # @return void
+ private method create_gui {} {
+ # Create panel window and canvas widget
+ set win [toplevel .simplekeypad$count -class $component_name -bg {#EEEEEE}]
+ set canvas_widget [canvas $win.canvas -bg white -width 0 -height 0]
+
+ set cb_p_y 65
+ set cb_b_y 85
+ set usr_n_y 105
+ set x 50
+
+ # Create labels
+ $canvas_widget create text 5 $cb_p_y \
+ -text [mc "PORT"] \
+ -font $cb_font \
+ -anchor w
+ $canvas_widget create text 5 $cb_b_y \
+ -text [mc "BIT"] \
+ -font $cb_font \
+ -anchor w
+ $canvas_widget create text 5 $usr_n_y \
+ -text [mc "Note"] \
+ -font $cb_font \
+ -anchor w
+ $canvas_widget create window 37 $usr_n_y \
+ -window [ttk::entry $canvas_widget.usr_note \
+ -validate all \
+ -validatecommand "$this set_modified" \
+ ] \
+ -width 220 -anchor w
+ bindtags $canvas_widget.usr_note \
+ [list $canvas_widget.usr_note TEntry $win all .]
+
+ # Create ComboBoxes
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget create window $x $cb_p_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_p$i \
+ -width 1 \
+ -font $cb_font \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_p$i <<ComboboxSelected>> "$this reconnect $i"
+
+ $canvas_widget create window $x $cb_b_y -anchor center \
+ -window [ttk::combobox $canvas_widget.cb_b$i \
+ -width 1 \
+ -font $cb_font \
+ -values {- 0 1 2 3 4 5 6 7} \
+ -state readonly \
+ ]
+ bind $canvas_widget.cb_b$i <<ComboboxSelected>> "$this reconnect $i"
+
+ bindtags $canvas_widget.cb_p$i \
+ [list $canvas_widget.cb_p$i TCombobox all .]
+ bindtags $canvas_widget.cb_b$i \
+ [list $canvas_widget.cb_b$i TCombobox all .]
+
+ incr x -13
+ draw_key $x 15 $i
+
+ incr x 40
+ }
+
+ # Create "ON/OFF" button
+ set start_stop_button [ttk::button $canvas_widget.start_stop_button \
+ -command "$this on_off_button_press" \
+ -style Flat.TButton \
+ -width 3 \
+ ]
+ DynamicHelp::add $canvas_widget.start_stop_button \
+ -text [mc "Turn HW simulation on/off"]
+ setStatusTip -widget $start_stop_button -text [mc "Turn HW simulation on/off"]
+ bind $start_stop_button <Button-3> "$this on_off_button_press; break"
+ $canvas_widget create window 2 20 -window $start_stop_button -anchor sw
+ bindtags $start_stop_button [list $start_stop_button TButton all .]
+
+ # Create configuration menu button
+ set conf_button [ttk::button $canvas_widget.conf_but \
+ -image ::ICONS::16::configure \
+ -style FlatWhite.TButton \
+ -command "$this config_menu" \
+ ]
+ setStatusTip -widget $conf_button -text [mc "Configure"]
+ $canvas_widget create window 2 20 -window $conf_button -anchor nw
+ bindtags $conf_button [list $conf_button TButton all .]
+
+ # Pack canvas
+ pack $canvas_widget -fill both -expand 1
+
+ # Set window parameters
+ wm geometry $win =260x120
+ wm iconphoto $win ::ICONS::16::$component_icon
+ wm title $win "[mc $component_name] - [string trim $project {:}] - MCU 8051 IDE"
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "$this close_window"
+ bindtags $win [list $win Toplevel all .]
+ }
+
+ ## Handle click on a virtual key
+ # @parm Int i - Key number
+ # @return void
+ public method key_click {i} {
+ # Adjust state of the key
+ set keys($i) [expr {!$keys($i)}]
+ key_state_changed $i
+
+ # Release all other keys if the panel was configured to use radio buttons
+ if {$radio_buttons} {
+ for {set j 0} {$j < 8} {incr j} {
+ if {$j == $i} {
+ continue
+ }
+ if {$keys($j)} {
+ set keys($j) 0
+ key_state_changed $j
+ }
+ }
+ }
+
+ # Inform PALE system about the change in order
+ #+ to make immediate change in device states
+ if {$drawing_on} {
+ $project pale_reevaluate_IO
+ }
+
+ # Set flag modified
+ set_modified
+ }
+
+ ## Adjust GUI to new state of a virtual key
+ # @parm Int i - Key number
+ # @return void
+ private method key_state_changed {i} {
+ # Key pressed
+ if {$keys($i)} {
+ $canvas_widget itemconfigure $lever(0$i) -fill #FFFFFF
+ $canvas_widget itemconfigure $lever(1$i) -fill #00DD00
+ $canvas_widget itemconfigure $text($i) -font $cb_font
+ $canvas_widget itemconfigure $rect($i) -outline #333333 -width 2
+
+ # Key released
+ } {
+ $canvas_widget itemconfigure $lever(0$i) -fill #000000
+ $canvas_widget itemconfigure $lever(1$i) -fill #FFFFFF
+ $canvas_widget itemconfigure $text($i) -font $cb_font_n
+ $canvas_widget itemconfigure $rect($i) -outline #CCCCCC -width 1
+ }
+ }
+
+ ## Handle mouse pointer enter on a virtual key
+ # @parm Int i - Key number
+ # @return void
+ public method key_leave {i} {
+ if {$keys($i)} {
+ set color {#333333}
+ } {
+ set color {#CCCCCC}
+ }
+ $canvas_widget itemconfigure $rect($i) -outline $color
+ }
+
+ ## Handle mouse pointer leave on a virtual key
+ # @parm Int i - Key number
+ # @return void
+ public method key_enter {i} {
+ $canvas_widget itemconfigure $rect($i) -outline {#0000FF}
+ }
+
+ ## Draw virtual key on the panel canvas
+ # @parm Int x - X coordinate of top left corner of the key
+ # @parm Int y - Y coordinate of top left corner of the key
+ # @parm Int i - Key number
+ # @return void
+ private method draw_key {x y i} {
+ # Draw rectangle sorrounding the key
+ set rect($i) [$canvas_widget create rectangle \
+ [expr {$x + 1}] [expr {$y + 1}] \
+ [expr {$x + 25}] [expr {$y + 29}] \
+ -width 1 -outline #CCCCCC -fill #FFFFFF \
+ ]
+
+ # Draw lines connecting the key to MCU port pin
+ set wire($i) [$canvas_widget create line \
+ [expr {$x + 13}] [expr {$y + 26}] \
+ [expr {$x + 13}] [expr {$y + 40}] \
+ -width 1 -fill #000000 \
+ ]
+ set wire_o($i) [$canvas_widget create oval \
+ [expr {$x + 11}] [expr {$y + 21}] \
+ [expr {$x + 15}] [expr {$y + 25}] \
+ -width 1 -outline #000000 \
+ ]
+
+ # Draw lever in the key
+ set lever(1$i) [$canvas_widget create line \
+ [expr {$x + 11}] [expr {$y + 22}] \
+ [expr {$x + 11}] [expr {$y + 6}] \
+ -width 1 -fill #FFFFFF \
+ ]
+ set lever(0$i) [$canvas_widget create line \
+ [expr {$x + 10}] [expr {$y + 22}] \
+ [expr {$x + 5}] [expr {$y + 6}] \
+ -width 1 -fill #000000 \
+ ]
+
+ # Draw lines connecting the key to the electrical ground
+ $canvas_widget create line \
+ [expr {$x + 13}] [expr {$y + 4}] \
+ [expr {$x + 13}] [expr {$y - 10}] \
+ [expr {$x + 8}] [expr {$y - 10}] \
+ [expr {$x + 18}] [expr {$y - 10}] \
+ -width 1 -fill #00DD00
+ set lines [$canvas_widget create oval \
+ [expr {$x + 11}] [expr {$y + 5}] \
+ [expr {$x + 15}] [expr {$y + 9}] \
+ -width 1 -outline #00DD00 \
+ ]
+
+ # Print key label
+ set text($i) [$canvas_widget create text \
+ [expr {$x + 20}] [expr {$y + 15}] \
+ -font $cb_font_n \
+ -text [lindex {A B C D E F G H} $i] \
+ ]
+
+ # Set event bindings for the key
+ foreach items [list \
+ $rect($i) $lines $text($i) \
+ $lever(0$i) $lever(1$i) $wire_o($i) \
+ ] {
+ foreach item $items {
+ $canvas_widget bind $item <Enter> "$this key_enter $i"
+ $canvas_widget bind $item <Leave> "$this key_leave $i"
+ $canvas_widget bind $item <Button-1> "$this key_click $i"
+ }
+ }
+ }
+
+ ## Determinate which port pin is connected to the specified key
+ # @parm Int i - Key number
+ # @return List - {port_number bit_number}
+ private method which_port_pin {i} {
+ return [list $connection_port($i) $connection_pin($i)]
+ }
+
+ ## Handle "ON/OFF" button press
+ # Turn whole PALE system on or off
+ # @return void
+ public method on_off_button_press {} {
+ $project pale_all_on_off
+ }
+
+ ## Value of configuration menu variable "menu_radio_buttons" has been changed
+ # @return void
+ public method value_radio_buttons_changed {} {
+ set radio_buttons $::SimpleKeyPad::menu_radio_buttons
+ }
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE -- CALLED FROM PALE ENGINE
+ # ------------------------------------------------------------------
+
+ ## Simulated MCU has been changed
+ # @return void
+ public method mcu_changed {} {
+ # Refresh lists of possible values in port selection ComboBoxes
+ set avaliable_ports [concat - [$project pale_get_avaliable_ports]]
+
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget.cb_p$i configure -values $avaliable_ports
+
+ if {[lsearch -ascii -exact $avaliable_ports $connection_port($i)] == -1} {
+ $canvas_widget.cb_p$i current 0
+ set connection_port($i) {-}
+ }
+ }
+ }
+
+ ## Evaluate new state of ports
+ # @parm List state - Port states ( 5 x {8 x bit} -- {bit0 bit1 bit2 ... bit7} )
+ # @return state - New port states modified by this device
+ # format is the same as parameter $state
+ #
+ # Possible bit values:
+ # '|' - High frequency
+ # 'X' - Access to external memory
+ # '?' - No volatge
+ # '-' - Undeterminable value (some noise)
+ # '=' - High forced to low
+ # '0' - Logical 0
+ # '1' - Logical 1
+ public method new_state {state} {
+ # Iterate over keys
+ for {set i 0} {$i < 8} {incr i} {
+ # Determinate index in the list of port states
+ set pp [which_port_pin $i]
+
+ # Key is not connected or panel is turned off
+ if {[lindex $pp 0] == {-} || [lindex $pp 1] == {-} || !$drawing_on} {
+ if {$keys($i)} {
+ set wire_color {#00DD00}
+ } {
+ set wire_color {#000000}
+ }
+
+ $canvas_widget itemconfigure $wire($i) -fill $wire_color
+ $canvas_widget itemconfigure $lever($keys(${i})${i}) -fill $wire_color
+ $canvas_widget itemconfigure $wire_o($i) -outline $wire_color
+
+ continue
+ }
+
+ # Pressed key forces port pin state to logical 0
+ if {$keys($i)} {
+ lset state $pp 0
+ }
+
+ # Determinate color for wires connected to the MCU
+ switch -- [lindex $state $pp] {
+ {0} { ;# Logical 0
+ set wire_color {#00FF00}
+ }
+ {1} { ;# Logical 1
+ set wire_color {#FF0000}
+ }
+ {=} { ;# High forced to low
+ set wire_color {#FF00AA}
+ }
+ {} { ;# Not connected
+ set wire_color {#000000}
+ }
+ {?} { ;# No volatge
+ set wire_color {#888888}
+ }
+ default {
+ set wire_color {#FF8800}
+ }
+ }
+
+ # Adjust key apparence
+ $canvas_widget itemconfigure $wire($i) -fill $wire_color
+ $canvas_widget itemconfigure $lever($keys(${i})${i}) -fill $wire_color
+ $canvas_widget itemconfigure $wire_o($i) -outline $wire_color
+ }
+
+ # Return new port states
+ return $state
+ }
+
+ ## Withdraw panel window from the screen
+ # @return void
+ public method withdraw_window {} {
+ wm withdraw $win
+ }
+
+ ## Get panel configuration list (usable with method "set_config")
+ # @return List - configuration list
+ public method get_config {} {
+ return [list \
+ $class_name \
+ [list \
+ [array get connection_port] \
+ [array get connection_pin] \
+ [wm geometry $win] \
+ [$canvas_widget.usr_note get] \
+ [array get keys] \
+ $radio_buttons \
+ ] \
+ ]
+ }
+
+ ## Set panel configuration from list gained from method "get_config"
+ # @parm List state - Configuration list
+ # @return void
+ public method set_config {state} {
+ if {[catch {
+ # Load connections to the MCU
+ array set connection_port [lindex $state 0]
+ array set connection_pin [lindex $state 1]
+
+ # Restore window geometry
+ if {[string length [lindex $state 2]]} {
+ wm geometry $win [lindex $state 2]
+ }
+
+ # Load user note
+ $canvas_widget.usr_note delete 0
+ $canvas_widget.usr_note insert 0 [lindex $state 3]
+
+ # Restore keys configuration and states
+ array set keys [lindex $state 4]
+ set radio_buttons [lindex $state 5]
+
+ # Restore state of ComboBoxes
+ for {set i 0} {$i < 8} {incr i} {
+ ## PIN
+ set pin $connection_pin($i)
+ if {$pin != {-}} {
+ set pin [expr {7 - $pin}]
+ }
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_b$i cget -values] \
+ $pin \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_b$i current $idx
+
+ ## PORT
+ set idx [lsearch -ascii -exact \
+ [$canvas_widget.cb_p$i cget -values] \
+ $connection_port($i) \
+ ]
+ if {$idx == -1} {
+ set idx 0
+ }
+ $canvas_widget.cb_p$i current $idx
+
+ # Adjust key apparence
+ key_state_changed $i
+ }
+
+ # Adjust internal logic and the rest of PALE
+ evaluete_enaged_pins
+ $project pale_reevaluate_IO
+ update
+
+ # Fail
+ }]} then {
+ puts "Unable to load config for $class_name"
+ return 0
+
+ # Success
+ } else {
+ clear_modified
+ return 1
+ }
+ }
+
+ ## Simulated MCU has been reseted
+ # @return void
+ public method reset {} {
+ new_state [$project pale_get_true_state]
+ }
+
+ # ------------------------------------------------------------------
+ # VIRTUAL HW COMMON INTERFACE -- CALLED FROM THE BASE CLASS
+ # ------------------------------------------------------------------
+
+ ## This method is called before configuration menu invocation
+ # @return void
+ public method config_menu_special {} {
+ set ::SimpleKeyPad::menu_radio_buttons $radio_buttons
+ }
+
+ ## This method is called after configuration menu has beed created
+ # @return void
+ public method create_config_menu_special {} {
+ }
+
+ ## This method is called to fill in the help dialog
+ # @parm Widget text_widget - Target text widget
+ # @return void
+ #
+ # Note: There is defined text tag "tag_bold" in the text widget
+ public method show_help_special {text_widget} {
+ $text_widget insert insert [mc "This tool consists of 8 switches. Each of them can connect any port pin of the simulated uC to the ground. Connections with the uC are made with ComboBoxes on the bottom of the panel. Panel configuration can be saved to a file (with extension vhc). And can be loaded from that file later. Wire colors are identical to colors used in graph representing IO ports.\n\n"]
+ $text_widget insert insert [mc "Keypad can be configured in two ways:"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc "\n "]
+ $text_widget insert insert [mc "1)"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc " To allow key combinations\n Menu -> Check \"Radio buttons\"\n "]
+ $text_widget insert insert [mc "2)"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert [mc " To do not allow key combinations\n Menu -> Uncheck \"Radio buttons\""]
+ }
+
+ ## This method is called before panel window closure
+ # @return void
+ public method close_window_special {} {
+ }
+
+ ## Commit new on/off state
+ # @return void
+ public method on_off_special {} {
+ new_state [$project pale_get_true_state]
+ }
+}
diff --git a/lib/pale/virtual_hw_component.tcl b/lib/pale/virtual_hw_component.tcl
new file mode 100755
index 0000000..e0fb00b
--- /dev/null
+++ b/lib/pale/virtual_hw_component.tcl
@@ -0,0 +1,423 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Base class for virtual hardware components
+# --------------------------------------------------------------------------
+
+class VirtualHWComponent {
+ common count 0 ;# Int: Counter of object instances
+ common hlp_dlg_count 0 ;# Int: Counter of help dialog instances
+
+ # Create fonts used in the text
+ common hlp_normal_font [font create \
+ -family {helvetica} \
+ -size -14 -weight {normal} \
+ ]
+ common hlp_bold_font [font create \
+ -family {helvetica} \
+ -size -14 -weight {bold} \
+ ]
+
+ protected variable config_menu_created 0 ;# Bool: COnfiguration menu created
+ protected variable conf_menu {} ;# Widget: Menu - Configuration menu
+
+ protected variable modified 0 ;# Bool: Flag modified
+
+ protected variable project ;# Object: Project object
+ protected variable win ;# Widget: Dialog window
+ protected variable drawing_on 1 ;# Bool: Flag panel enabled
+ protected variable canvas_widget ;# Widget: Canvas widget - crucial part of the window
+ protected variable start_stop_button ;# Widget: Button "ON/OFF"
+ protected variable conf_button ;# Widget: Button to invoke configuration menu
+
+ protected variable component_name {} ;# String: Name of this VHW component
+ protected variable class_name {} ;# String: Name of class of this VHW component
+ protected variable component_icon {} ;# String: Name of icon of this VHW component
+ protected variable current_filename {} ;# String: Full name of file the current configuration
+
+ ## Object constructor
+ # Increments counter of class instances
+ constructor {} {
+ incr count
+ }
+
+ ## Object destructor
+ destructor {
+ }
+
+ ## Close dialog window
+ # Ask user for save, call "close_window_special" and destroy the object
+ # @return void
+ public method close_window {} {
+ if {$modified} {
+ switch -- [tk_messageBox \
+ -type yesnocancel \
+ -icon question \
+ -parent $win \
+ -title [mc "Component modified"] \
+ -message [mc "Do you want to save configuration of this panel before closing ?"] \
+ ] {
+ {yes} {
+ save_as
+
+ if {$modified} {
+ return
+ }
+ }
+ {no} {
+ }
+ default {
+ return
+ }
+ }
+ }
+
+ $this close_window_special
+ delete object $this
+ }
+
+ ## Set modified flag to 1, here and in whole PALE system
+ # @return void
+ public method set_modified {} {
+ set modified 1
+ $project pale_set_modified
+
+ return 1
+ }
+
+ ## Set modified flag to 0
+ # @return void
+ public method clear_modified {} {
+ set modified 0
+ }
+
+ ## Invoke configuration menu
+ # Call "config_menu_special" before popup
+ # @return void
+ public method config_menu {} {
+ if {!$config_menu_created} {
+ create_config_menu
+ }
+
+ set x [winfo rootx $conf_button]
+ set y [winfo rooty $conf_button]
+ incr y [winfo height $conf_button]
+
+ $this config_menu_special
+
+ tk_popup $conf_menu $x $y
+ }
+
+ ## Create configuration menu widgets
+ # Call create_config_menu_special after widgets were created
+ # @return void
+ protected method create_config_menu {} {
+ set config_menu_created 1
+ set conf_menu $canvas_widget.conf_menu
+ menuFactory [subst "\${${class_name}::CONFMENU}"] \
+ $conf_menu 0 "$this " 0 {}
+
+ $this create_config_menu_special
+ }
+
+ ## Action "Save as"
+ # @return void
+ public method save_as {} {
+ # Create file selection dialog
+ catch {delete object ::fsd}
+ KIFSD::FSD ::fsd \
+ -title "[mc {Save configuration}] - [mc $component_name] - [string trim $project {:}] - MCU 8051 IDE" \
+ -master $win \
+ -directory [$project cget -projectPath] \
+ -initialfile [file tail $current_filename] \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{VH component} {*.vhc} }
+ {{All files} {*} }
+ }
+
+ # Open file after press of OK button
+ ::fsd setokcmd "$this save_config_to_file \[::fsd get\]"
+
+ # activate the dialog
+ ::fsd activate
+ }
+
+ ## Action "Open file"
+ # @return void
+ public method load_from {} {
+ # Create file selection dialog
+ catch {delete object ::fsd}
+ KIFSD::FSD ::fsd \
+ -title "[mc {Load configuration}] - [mc $component_name] - [string trim $project {:}] - MCU 8051 IDE" \
+ -master $win \
+ -directory [$project cget -projectPath] \
+ -initialfile [file tail $current_filename] \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{VH component} {*.vhc} }
+ {{All files} {*} }
+ }
+
+ # Open file after press of OK button
+ ::fsd setokcmd "$this load_config_from_file \[::fsd get\]"
+
+ # activate the dialog
+ ::fsd activate
+ }
+
+ ## Save configuration to the specified file
+ # @parm String filename - Name of target file
+ # @return Bool - 1 upon success; 0 upon fail
+ public method save_config_to_file {filename} {
+ # Adjust file name
+ if {![string length $filename]} {
+ return 0
+ }
+ set filename [file join [$project cget -ProjectDir] $filename]
+
+ # Adjust file extension
+ if {![regexp {\.vhc$} $filename]} {
+ append filename {.vhc}
+ }
+
+ if {[file exists $filename]} {
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent $win \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file with name '%s' already exists. Do you want to overwrite it ?" [file tail $filename]]
+ ] != {yes}
+ } {
+ return 0
+ }
+ }
+
+ # Create backup file
+ if {[file isfile $filename]} {
+ catch {
+ file rename -force $filename "$filename~"
+ }
+ }
+
+ # Try to open the file
+ if {[catch {
+ set file [open $filename {w} 420]
+ }]} then {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -parent $win \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to write to file:\n\"%s\"" $filename]
+ return 0
+ }
+
+ # Gain configuration list
+ set config [$this get_config]
+ lset config {1 2} {} ;# Remove geometry information
+
+ # Save configuration to the file
+ puts $file "# MCU 8051 IDE: Virtual HW component configuration file"
+ puts $file "# Date: [clock format [clock seconds] -format {%D}]"
+ puts $file "# Project: [string trim $project {:}]"
+ puts $file "# Component: $component_name\n"
+ puts $file $config
+
+ # Finalize
+ set current_filename $filename
+ close $file
+ set modified 0
+ return 1
+ }
+
+ ## Load configuration from the specified file
+ # @parm String filename - Name of source file
+ # @return void
+ public method load_config_from_file {filename} {
+ # Try to open the file
+ if {[catch {
+ set file [open $filename {r}]
+ }]} then {
+ tk_messageBox \
+ -type ok \
+ -icon error \
+ -parent $win \
+ -title [mc "IO Error"] \
+ -message [mc "Unable to read file:\n\"%s\"" $filename]
+ return 0
+ }
+
+ # Read file line by line
+ while {![eof $file]} {
+ set line [gets $file]
+
+ # Skip empty lines and comments
+ if {$line == {} || [regexp {^\s*#} $line]} {continue}
+
+ # Decomposite file records
+ set obj [lindex $line 0] ;# VHW Object
+ set conf [lindex $line 1] ;# Configuration
+
+ # Detect wrong object name
+ if {$obj != $class_name} {
+ tk_messageBox \
+ -type ok \
+ -parent $win \
+ -icon error \
+ -title [mc "File corrupted"] \
+ -message [mc "Unable to read configuration from file:\n\"%s\"" $filename]
+ return 0
+ }
+
+ # Set configuration for this component
+ if {![$this set_config $conf]} {
+ tk_messageBox \
+ -type ok \
+ -parent $win \
+ -icon error \
+ -title [mc "File corrupted"] \
+ -message [mc "Unable to read configuration from file:\n\"%s\"" $filename]
+ return 0
+ }
+
+ # Only first configuration record is accepted
+ break
+ }
+
+ # Finalize ...
+ set current_filename $filename
+ close $file
+ set modified 0
+ return 1
+ }
+
+ ## Show help dialog
+ # @return void
+ public method show_help {} {
+ # Increment counter of help dialog instances
+ incr hlp_dlg_count
+
+ # Create toplevel window
+ set dialog [toplevel .help_dialog_${class_name}_${hlp_dlg_count} -class {Help} -bg {#EEEEEE}]
+
+ ## Create top frame (header and icon)
+ set top_frame [frame $dialog.top_frame]
+ # Icon
+ pack [label $top_frame.header_image \
+ -image ::ICONS::22::$component_icon \
+ ] -side left -padx 10
+ # Header text
+ pack [label $top_frame.header_label \
+ -anchor w -justify left \
+ -text $component_name \
+ ] -side left
+ pack $top_frame -anchor n -pady 2
+
+ ## Create main frame (text and scrollbar)
+ set main_frame [frame $dialog.main_frame]
+ # Text widget
+ set text_widget [text $main_frame.text \
+ -width 0 -height 0 -font $hlp_normal_font \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ -wrap word -padx 5 -pady 5 \
+ ]
+ pack $text_widget -side left -fill both -expand 1
+ # Scrollbar
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$text_widget yview" \
+ ] -side right -fill y
+ # Finalize ...
+ pack $main_frame -fill both -expand 1
+
+ ## Create bottom frame (button close)
+ # Separator
+ pack [ttk::separator $dialog.sep \
+ -orient horizontal \
+ ] -fill x
+ # Button "Close"
+ pack [ttk::button $dialog.close_button \
+ -text [mc "Close"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "destroy $dialog" \
+ ] -ipady 0
+
+
+ # Create text tags in the text widget
+ $text_widget tag configure tag_bold -font $hlp_bold_font
+
+ # Fill in the text widget with the help message
+ $this show_help_special $text_widget
+
+ ## Display section "Wire colors"
+ $text_widget insert insert "\n\n"
+ $text_widget insert insert [mc "Wire colors:"]
+ $text_widget tag add tag_bold {insert linestart} {insert lineend}
+ $text_widget insert insert "\n"
+ # Create canvas widget
+ set cw [canvas $text_widget.canvas\
+ -bg {#FFFFFF} \
+ -takefocus 0 \
+ -cursor left_ptr \
+ -bd 0 -relief flat \
+ -width 170 -height 110 \
+ ]
+ bind $cw <Button-5> "$text_widget yview scroll +5 units; break"
+ bind $cw <Button-4> "$text_widget yview scroll -5 units; break"
+ # Fill in the canvas widget
+ $project Graph_create_legend $cw 1
+ # Show the canvas widget
+ $text_widget window create insert -window $cw
+
+ # Finalize ...
+ $text_widget configure -state disabled
+ wm minsize $dialog 300 300
+ wm title $dialog $component_name
+ wm iconphoto $dialog ::ICONS::16::help
+ focus -force $dialog.close_button
+ }
+
+ ## Commit new on/off state
+ # @parm Bool state - 1 == ON; 0 == OFF
+ # @return void
+ public method on_off {state} {
+ # Adjust flag panel enabled
+ set drawing_on $state
+
+ ## Adjust apparence of "ON/OFF" button
+ # Turn ON
+ if {$state} {
+ $start_stop_button configure -style GreenBg.TButton -text "ON"
+ # Turn OFF
+ } else {
+ $start_stop_button configure -style RedBg.TButton -text "OFF"
+ }
+
+ # Call component specific procedure
+ $this on_off_special
+ }
+}
diff --git a/lib/project.tcl b/lib/project.tcl
new file mode 100755
index 0000000..3c4571b
--- /dev/null
+++ b/lib/project.tcl
@@ -0,0 +1,868 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements project files management
+# --------------------------------------------------------------------------
+
+namespace eval Project {
+
+ variable xml_data_tk_mcuide_project {} ;# Attributes of <tk_mcuide_project>
+ variable xml_data_authors {} ;# Content of <authors>
+ variable xml_data_copyright {} ;# Content of <copyright>
+ variable xml_data_licence {} ;# Content of <licence>
+ variable xml_data_processor {} ;# Attributes of <processor>
+ variable xml_data_options {} ;# Attributes of <options>
+ variable xml_data_graph {} ;# Attributes of <graph>
+ variable xml_data_description {} ;# Content of <description>
+ variable xml_data_todo {} ;# Content of <todo>
+ variable xml_data_calculator {} ;# Attributes of <calculator>
+ variable xml_data_other_options {} ;# Content of <other_options>
+ variable xml_data_compiler_options {} ;# Content of <compiler_options>
+ variable xml_data_files {} ;# Contents of <file>
+ variable xml_data_file_notes {} ;# Contents of <notes>
+ variable xml_data_files_count {} ;# Number of files
+
+ variable xml_data_file {} ;# Auxiliary variable for xml_data_files
+ variable xml_attlist ;# Auxiliary variable - List of current tag attributes
+ variable xml_expect {} ;# XML tag expected to be the next
+ variable xml_curTag {} ;# Currenly parsed XML tag
+ variable xml_start {} ;# Bool: True at start of parsing
+ variable expect_data_part 1 ;# Bool: True if on the next comes data
+ variable xml_warning 0 ;# Bool: True if an error occured during parsing process
+
+
+ ## Create string which can be saved as a project definition file (format: XML)
+ # @parm List inputData - requested format: {
+ # {version date creator_ver} # tag: tk_mcuide_project
+ # {authors copyright licence} # tag: authors copyright licence
+ # {type clock xdata xcode} # tag: processor
+ # {watches_file scheme main_file auto_sw_enabled} # tag: options
+ # {grid_mode magnification drawing_on mark_flags} # tag: graph
+ # {description todo} # tag: descriptin todo
+ # {radix angle_unit # tag: calculator
+ # display0 display1 display2
+ # memory0 memory1 memory2
+ # frequency time mode}
+ # {other_options} # tag: other_options
+ # {compiler_options}
+ # {files_count {current_file # tag: files
+ # current_file2 pwin_sash pwin_orient}
+ # { # tag: file actual_line md5_hash path bookmarks breakpoints
+ # name active o_bookmark p_bookmark
+ # file_index read_only actual_line md5_hash
+ # path bookmarks breakpoints eol
+ # enc highlight notes
+ # }
+ # ...
+ # }
+ # }
+ # @return String - outpud data (formated as XML)
+ proc create_project_file_as_string {inputData} {
+
+ # Initialize variables related to content of the file
+ if {$inputData != {}} {
+
+ # Definition of file structure (except of <files>)
+ set dataPartStructure {
+ {version date creator_ver}
+ {authors copyright licence}
+ {mcu_type clock xdata xcode}
+ {watches_file scheme main_file auto_sw_enabled}
+ {graph_grid_mode graph_magnification graph_drawing_on graph_mark_flags_s graph_mark_flags_l graph_mark_flags_o active_page}
+ {description todo}
+ {calc_radix angle_unit display0 display1 display2 memory0 memory1 memory2 freq time mode}
+ {other_options}
+ {compiler_options}
+ }
+
+ # Parse part of input list
+ set i 0
+ foreach record $dataPartStructure {
+ set data [lindex $inputData $i]
+ incr i
+ foreach value $data var $record {
+ set $var $value
+ }
+ }
+
+ # Parse remain of input list
+ set files [lindex $inputData 9]
+ set files_count [lindex $files 0]
+ set current_file [lindex $files {1 0}]
+ set current_file2 [lindex $files {1 1}]
+ set pwin_sash [lindex $files {1 2}]
+ set pwin_orient [lindex $files {1 3}]
+ set selected_view [lindex $files {1 4}]
+ set files [lreplace $files 0 1]
+
+ # Set all variables to defaults
+ } else {
+ foreach var {
+ version date creator_ver authors copyright
+ licence other_options files_count mcu_type xdata
+ watches_file files description todo calc_radix
+ angle_unit display0 display1 display2 memory0
+ memory1 memory2 clock freq time
+ mode graph_grid_mode graph_magnification graph_drawing_on
+ graph_mark_flags_s graph_mark_flags_l graph_mark_flags_o active_page
+ xcode scheme graph_mark_flags current_file2
+ pwin_sash main_file compiler_options
+ } {
+ set $var {}
+ }
+ }
+
+ # Discard input data
+ unset inputData
+
+ # Initialize resulting string
+ set result {}
+
+ ## Create XML string
+ append result "<?xml version='1.0' encoding='utf-8'?>\n"
+ if {[file exists "${::LIB_DIRNAME}/../data/project.dtd"]} {
+ if {[catch {
+ set dtd [open "${::LIB_DIRNAME}/../data/project.dtd" r]
+ }]} then {
+ puts stderr "Unable to open project DTD, please check your installation."
+ } else {
+ append result "<!DOCTYPE tk_mcuide_project \[\n\n"
+ while 1 {
+ if {[eof $dtd]} {
+ close $dtd
+ break
+ }
+ set line [gets $dtd]
+ if {[string length $line]} {
+ append result "\t" $line
+ }
+ append result "\n"
+ }
+ append result "\]>\n"
+ }
+ }
+ append result "<tk_mcuide_project version=\"[adjust_to_xml $version]\""
+ append result " date=\"[adjust_to_xml $date]\" creator_ver=\"${::VERSION}\">\n"
+ append result "\t<general>\n"
+ append result "\t\t<authors><!\[CDATA\[[adjust_to_xml $authors]\]\]></authors>\n"
+ append result "\t\t<copyright><!\[CDATA\["
+ append result "[adjust_to_xml $copyright]\]\]></copyright>\n"
+ append result "\t\t<licence><!\[CDATA\[[adjust_to_xml $licence]\]\]></licence>\n"
+ append result "\t\t<processor type=\"[adjust_to_xml $mcu_type]\" clock=\"[adjust_to_xml $clock]\""
+ append result " xdata=\"[adjust_to_xml $xdata]\" xcode=\"[adjust_to_xml $xcode]\"/>\n"
+ append result "\t\t<options\n"
+ append result "\t\t\twatches_file=\"[adjust_to_xml $watches_file]\"\n"
+ append result "\t\t\tscheme=\"[adjust_to_xml $scheme]\"\n"
+ append result "\t\t\tmain_file=\"[adjust_to_xml $main_file]\"\n"
+ append result "\t\t\tauto_sw_enabled=\"[adjust_to_xml $auto_sw_enabled]\"\n"
+ append result "\t\t\t/>\n"
+ append result "\t\t<graph\n"
+ append result "\t\t\tgrid=\"$graph_grid_mode\"\n"
+ append result "\t\t\tmagnification=\"$graph_magnification\"\n"
+ append result "\t\t\tenabled=\"$graph_drawing_on\"\n"
+ append result "\t\t\tmarks_s=\"$graph_mark_flags_s\"\n"
+ append result "\t\t\tmarks_l=\"$graph_mark_flags_l\"\n"
+ append result "\t\t\tmarks_o=\"$graph_mark_flags_o\"\n"
+ append result "\t\t\tactive_page=\"$active_page\"\n"
+ append result "\t\t/>\n"
+ append result "\t\t<description><!\[CDATA\[[adjust_to_xml $description]\]\]></description>\n"
+ append result "\t\t<todo><!\[CDATA\[[unescape_curlies $todo]\]\]></todo>\n"
+ append result "\t\t<calculator\n"
+ append result "\t\t\tradix=\"[adjust_to_xml $calc_radix]\"\n"
+ append result "\t\t\tangle_unit=\"[adjust_to_xml $angle_unit]\"\n"
+ append result "\t\t\tdisplay0=\"[adjust_to_xml $display0]\"\n"
+ append result "\t\t\tdisplay1=\"[adjust_to_xml $display1]\"\n"
+ append result "\t\t\tdisplay2=\"[adjust_to_xml $display2]\"\n"
+ append result "\t\t\tmemory0=\"[adjust_to_xml $memory0]\"\n"
+ append result "\t\t\tmemory1=\"[adjust_to_xml $memory1]\"\n"
+ append result "\t\t\tmemory2=\"[adjust_to_xml $memory2]\"\n"
+ append result "\t\t\tfreq=\"[adjust_to_xml $freq]\"\n"
+ append result "\t\t\ttime=\"[adjust_to_xml $time]\"\n"
+ append result "\t\t\tmode=\"[adjust_to_xml $mode]\"\n"
+ append result "\t\t/>\n"
+ append result "\t</general>\n"
+ append result "\t<other_options><!\[CDATA\[[adjust_to_xml $other_options]\]\]></other_options>\n"
+ append result "\t<compiler_options><!\[CDATA\[[adjust_to_xml $compiler_options]\]\]></compiler_options>\n"
+ append result "\t<files\n"
+ append result "\t\tcount=\"[adjust_to_xml $files_count]\"\n"
+ append result "\t\tcurrent_file=\"[adjust_to_xml $current_file]\"\n"
+ append result "\t\tcurrent_file2=\"[adjust_to_xml $current_file2]\"\n"
+ append result "\t\tpwin_sash=\"[adjust_to_xml $pwin_sash]\"\n"
+ append result "\t\tselected_view=\"[adjust_to_xml $selected_view]\"\n"
+ append result "\t\tpwin_orient=\"[adjust_to_xml $pwin_orient]\">\n\n"
+ foreach file $files {
+ foreach value $file \
+ var {
+ name active o_bookmark p_bookmark
+ file_index read_only actual_line md5_hash
+ path bookmarks breakpoints eol
+ enc highlight notes
+ } {
+ set $var $value
+ }
+ append result "\t\t<file name=\"[adjust_to_xml $name]\" active=\"[adjust_to_xml $active]\" "
+ append result "o_bookmark=\"$o_bookmark\" p_bookmark=\"$p_bookmark\" "
+ append result "file_index=\"$file_index\" read_only=\"$read_only\" highlight=\"$highlight\">\n"
+ append result "\t\t\t<actual_line value=\"[adjust_to_xml $actual_line]\"/>\n"
+ append result "\t\t\t<md5_hash value=\"[adjust_to_xml $md5_hash]\"/>\n"
+ append result "\t\t\t<path><!\[CDATA\[[adjust_to_xml $path]\]\]></path>\n"
+ append result "\t\t\t<bookmarks>\n\t\t\t\t[adjust_to_xml $bookmarks]\n"
+ append result "\t\t\t</bookmarks>\n"
+ append result "\t\t\t<breakpoints>\n\t\t\t\t[adjust_to_xml $breakpoints]\n"
+ append result "\t\t\t</breakpoints>\n"
+ append result "\t\t\t<eol value=\"$eol\"/>\n"
+ append result "\t\t\t<encoding value=\"$enc\"/>\n"
+ append result "\t\t\t<notes><!\[CDATA\[[adjust_to_xml $notes]\]\]></notes>\n"
+ append result "\t\t</file>\n\n"
+ }
+ append result "\t</files>\n"
+ append result "</tk_mcuide_project>"
+
+ # Return resulting XML String
+ return $result
+ }
+
+ ## Open project (open project file, parse it and Initialize new instance of MainTab class)
+ # @parm String filename
+ # @return Bool - result
+ proc open_project_file {filename} {
+ set filename [file normalize $filename]
+
+ # Check for file existance
+ if {![file exists $filename]} {return 0}
+
+ # Retreive project data list from the file
+ if {[catch {
+ set projectFile [open $filename r]
+ set dataList [create_list_from_project_string [read $projectFile]]
+ close $projectFile
+ }]} {
+ return 0
+ }
+
+ # Check for project data list validity
+ if {$dataList == {}} {return 0}
+
+ # Local variables
+ regexp {^.*[\\\/]} $filename projectPath ;# Path to project file
+ regsub {[\\\/]$} $projectPath {} projectPath
+ regexp {[^\\\/]*$} $filename projectFileName ;# Name of project definition file
+ regexp {[^\\\/]+$} $filename project_new_name ;# Name of the project
+ regsub {\.[^\.]+$} $project_new_name {} project_new_name
+ set projectDescriptor [regsub -all -- {\s} $project_new_name {-}]
+ regsub -all {[\\\/\.\,`\!@#\$%\^&:\;\|\*\"\(\)\[\]\{\}]} \
+ $projectDescriptor {_} projectDescriptor
+
+ # Take care of opening multiple instances of the same project
+ if {[lsearch ${X::openedProjects} $projectDescriptor] != -1} {
+ append project_new_name "(0)"
+ append projectDescriptor "_0"
+
+ while 1 {
+ if {[lsearch ${X::openedProjects} $projectDescriptor] == -1} {break}
+
+ regexp {\d+$} $projectDescriptor index
+ regsub {_\d+$} $projectDescriptor {} projectDescriptor
+
+ regexp {\d+\)$} $project_new_name index
+ set index [string trimright $index {\)}]
+ regsub {\(\d+\)$} $project_new_name {} project_new_name
+
+ incr index
+ append project_new_name "($index)"
+ append projectDescriptor "_$index"
+ }
+ }
+
+ # Show project notebook
+ if {${X::project_menu_locked}} {
+ pack .mainFrame.mainNB -expand 1 -fill both
+ }
+
+ # Adjust project related variables in NS ::X::
+ lappend ::X::openedProjects $projectDescriptor
+ lappend ::X::simulator_enabled 0
+ # Initialize project object
+ MainTab ::$projectDescriptor $project_new_name $projectPath $projectFileName $dataList
+
+ # Unlock all menu items
+ if {${X::project_menu_locked}} {
+ ::X::Unlock_project_menu
+ }
+ ::X::disaena_menu_toolbar_for_current_project
+
+ # Done ...
+ return 1
+ }
+
+ ## Parse given project definition (XML) and return resulting data-list
+ # @parm String inputData - content of the project file
+ # @return List - result or {}
+ proc create_list_from_project_string {inputData} {
+ variable xml_data_tk_mcuide_project ;# Attributes of <tk_mcuide_project>
+ variable xml_data_authors ;# Content of <authors>
+ variable xml_data_copyright ;# Content of <copyright>
+ variable xml_data_licence ;# Content of <licence>
+ variable xml_data_processor ;# Attributes of <processor>
+ variable xml_data_options ;# Attributes of <options>
+ variable xml_data_graph ;# Attributes of <graph>
+ variable xml_data_description ;# Content of <description>
+ variable xml_data_todo ;# Content of <todo>
+ variable xml_data_calculator ;# Attributes of <calculator>
+ variable xml_data_other_options ;# Content of <other_options>
+ variable xml_data_compiler_options ;# Content of <compiler_options>
+ variable xml_data_files ;# Contents of <file>
+ variable xml_data_files_count ;# Number of files
+
+ variable xml_expect ;# XML tag expected to be the next
+ variable xml_curTag ;# Currenly parsed XML tag
+ variable xml_data_file ;# Auxiliary variable for xml_data_files
+ variable xml_warning ;# Bool: True if an error occured during parsing process
+ variable xml_start ;# Bool: True at start of parsing
+
+ # Setup XML parser
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand Project::project_xml_parser_handler_element \
+ -elementendcommand Project::project_xml_parser_handler_element_end \
+ -characterdatacommand Project::project_xml_parser_handler_data \
+ ]
+
+
+ set xml_warning 0 ;# No error so far
+ set xml_start 1 ;# Parsing just begun
+
+ # Start XML parser
+ if {[catch {
+ $parser parse $inputData
+ } result]} {
+ puts stderr "XML parse error: $result"
+ report_project_loading_error
+ return {}
+ }
+
+ # Unload XML parser
+ $parser free
+ if {$xml_warning} {
+ free_resources
+ return {}
+ }
+
+ # Composite resulting string
+ set result {}
+ lappend result [unescape_tags $xml_data_tk_mcuide_project]
+ lappend result [list \
+ [unescape_tags $xml_data_authors ] \
+ [unescape_tags $xml_data_copyright ] \
+ [unescape_tags $xml_data_licence ] \
+ ]
+ lappend result $xml_data_processor
+ lappend result [unescape_tags $xml_data_options]
+ lappend result $xml_data_graph
+ lappend result [list \
+ [unescape_tags $xml_data_description ] \
+ [unescape_tags $xml_data_todo ] \
+ ]
+ lappend result [unescape_tags $xml_data_calculator ]
+ lappend result [unescape_tags $xml_data_other_options ]
+ lappend result [unescape_curlies [unescape_tags $xml_data_compiler_options]]
+
+ lappend__xml_data_files__xml_data_file ;# Note that this is important function
+ lappend result [concat \
+ $xml_data_files_count \
+ [unescape_tags $xml_data_files] \
+ ]
+
+ # Free used memory
+ free_resources
+
+ # Return resulting List
+ return $result
+
+ }
+
+ ## Free memory used during parsing
+ # @return void
+ proc free_resources {} {
+ variable xml_data_tk_mcuide_project ;# Attributes of <tk_mcuide_project>
+ variable xml_data_authors ;# Content of <authors>
+ variable xml_data_copyright ;# Content of <copyright>
+ variable xml_data_licence ;# Content of <licence>
+ variable xml_data_processor ;# Attributes of <processor>
+ variable xml_data_options ;# Attributes of <options>
+ variable xml_data_graph ;# Attributes of <graph>
+ variable xml_data_description ;# Content of <description>
+ variable xml_data_todo ;# Content of <todo>
+ variable xml_data_calculator ;# Attributes of <calculator>
+ variable xml_data_other_options ;# Content of <other_options>
+ variable xml_data_compiler_options ;# Content of <compiler_options>
+ variable xml_data_files ;# Contents of <file>
+ variable xml_data_file_notes ;# Contents of <notes>
+ variable xml_data_files_count ;# Number of files
+
+ variable xml_expect ;# XML tag expected to be the next
+ variable xml_curTag ;# Currenly parsed XML tag
+ variable xml_data_file ;# Auxiliary variable for xml_data_files
+ variable xml_start ;# Bool: True at start of parsing
+
+ # Set all listed variables to empty string
+ foreach var {
+ xml_data_tk_mcuide_project xml_data_authors xml_data_copyright
+ xml_data_licence xml_curTag xml_data_processor
+ xml_data_options xml_data_description xml_data_todo
+ xml_data_files xml_data_calculator xml_data_other_options
+ xml_data_files_count xml_data_current_file xml_data_file
+ xml_expect xml_data_graph xml_data_compiler_options
+ xml_data_file_notes
+ } {
+ set $var {}
+ }
+ }
+
+ ## Invoke dialog to report error occcured while parsing data
+ # @return void
+ proc report_project_loading_error {} {
+ variable xml_warning ;# Bool: True if an error occured during parsing process
+
+ # Ensure than there is only one error message dialog
+ if {$xml_warning} {return}
+
+ # Invoke dialog
+ tk_messageBox -icon error -type ok -title [mc "Project loading error"] \
+ -message [mc "ERROR:\nThe project file cannot be loaded correctly due to a xml parsing error. The file is eighter corrupted or it is not a project file acceptable by this environment."]
+
+ set xml_warning 1
+ }
+
+ ## Escape curly brackets and convert '<' and '>' to HTML entities
+ # @parm String data - input
+ # @return String - output
+ proc adjust_to_xml {data} {
+ set data [unescape_curlies $data]
+ return [escape_tags $data]
+ }
+
+ ## Unescape curly brackets
+ # @parm String data - input
+ # @return String - output
+ proc unescape_curlies {data} {
+ regsub -all {\\\{} $data "{" data
+ regsub -all {\\\}} $data "}" data
+ return $data
+ }
+
+ ## Escape curly brackets
+ # @parm String data - input
+ # @return String - output
+ proc escape_curlies {data} {
+ regsub -all {\{} $data "\\{" data
+ regsub -all {\}} $data "\\}" data
+ return $data
+ }
+
+ ## Convert '&lt;' -> '<' and '&gt;' -> '>'
+ # @parm String data - input
+ # @return String - output
+ proc unescape_tags {data} {
+ regsub -all {&amp;} $data "\\&" data
+ regsub -all {&lt;} $data "<" data
+ regsub -all {&gt;} $data ">" data
+ regsub -all {&quot;} $data "\"" data
+ regsub -all {\\\"} $data "\"" data
+ regsub -all {\\\\} $data "\\" data
+ return $data
+ }
+
+ ## Convert '<' -> '&lt;' and '>' -> '&gt;'
+ # @parm String data - input
+ # @return String - output
+ proc escape_tags {data} {
+ regsub -all {&} $data "\\&amp;" data
+ regsub -all {<} $data "\\&lt;" data
+ regsub -all {>} $data "\\&gt;" data
+ regsub -all {\"} $data "\\&quot;" data
+ regsub -all {\\\"} $data "\"" data
+ return $data
+ }
+
+ ## Parse attributes of current tab
+ # @parm String nextTag - name of XML tag which is expected to be the next
+ # @parm List Attrlist - list of attributes to process
+ # @return List - result
+ proc project_xml_attr_parser {nextTag Attrlist} {
+ variable xml_attlist ;# Auxiliary variable - List of attributes of current tag
+
+ # Set expected tag
+ project_xml_expect $nextTag
+
+ # Create array of attributes
+ for {set i 0} {$i <= [llength $xml_attlist]} {incr i} {
+ set name [lindex $xml_attlist $i]
+ incr i
+ set value [lindex $xml_attlist $i]
+ set attr($name) [escape_curlies $value]
+ }
+
+ # Parse attributes and composite result
+ set result {}
+ foreach attrName $Attrlist {
+ if {![info exists attr($attrName)]} {set attr($attrName) {}}
+ lappend result $attr($attrName)
+ }
+
+ # Return result
+ return $result
+ }
+
+ ## Set name of XML tag which must follow the cuurent one
+ # @parm String nextTag - XML tag
+ # @return Bool - result
+ proc project_xml_expect {nextTag} {
+ variable xml_expect ;# XML tag expected to be the next
+ variable xml_curTag ;# Currenly parsed XML tag
+
+ # Check if the current tag was expected
+ if {$xml_expect != $xml_curTag && [lsearch $xml_expect $xml_curTag] == -1} {
+ puts stderr "Expected XML tag was: \"$xml_expect\", but \"$xml_curTag\" was given"
+ set xml_expect $nextTag
+ report_project_loading_error
+ return 0
+ }
+
+ # Set expected tag
+ set xml_expect $nextTag
+ return 1
+ }
+
+ ## XML parser handler - Handles XML tag end
+ # @return void
+ proc project_xml_parser_handler_element_end args {
+ variable expect_data_part ;# Bool: True if on the next comes data
+
+ set expect_data_part 0
+ }
+
+ ## XML parser handler - handles XML data
+ # @parm String arg1 - content of the element
+ # @return void
+ proc project_xml_parser_handler_data {data} {
+ variable expect_data_part ;# Bool: True if on the next comes data
+ variable xml_expect ;# XML tag expected to be the next
+ variable xml_curTag ;# Currenly parsed XML tag
+ variable xml_start ;# Bool: True at start of parsing
+ variable xml_attlist ;# Auxiliary variable - List of current tag attributes
+ variable xml_warning ;# Bool: True if an error occured during parsing process
+
+ variable xml_data_tk_mcuide_project ;# Attributes of <tk_mcuide_project>
+ variable xml_data_authors ;# Content of <authors>
+ variable xml_data_copyright ;# Content of <copyright>
+ variable xml_data_licence ;# Content of <licence>
+ variable xml_data_processor ;# Attributes of <processor>
+ variable xml_data_options ;# Attributes of <options>
+ variable xml_data_graph ;# Attributes of <graph>
+ variable xml_data_description ;# Content of <description>
+ variable xml_data_todo ;# Content of <todo>
+ variable xml_data_calculator ;# Attributes of <calculator>
+ variable xml_data_other_options ;# Content of <other_options>
+ variable xml_data_compiler_options ;# Content of <compiler_options>
+ variable xml_data_files ;# Contents of <file>
+ variable xml_data_files_count ;# Number of files
+ variable xml_data_file ;# Contents of <file>
+ variable xml_data_file_notes ;# Contents of <notes>
+
+ # Abort on error
+ if {$xml_warning} {return}
+
+ # Inicalize on parser start up
+ if {$xml_start} {
+ set xml_start 0
+ set xml_expect "xml_data_tk_mcuide_project"
+ }
+ # Check if data part is expected
+ if {!$expect_data_part} {
+ return
+ }
+
+ # Adjust given data
+ if {$xml_curTag != {todo}} {
+ regsub -all {^\s+} $data {} data
+ }
+ regsub -all {\s+$} $data {} data
+ set data [escape_curlies $data]
+
+ # Parse given data
+ switch -- $xml_curTag {
+ {authors} {
+ append xml_data_authors $data "\n"
+ }
+ {copyright} {
+ set xml_data_copyright $data
+ }
+ {licence} {
+ set xml_data_licence $data
+ }
+ {description} {
+ append xml_data_description $data "\n"
+ }
+ {todo} {
+ append xml_data_todo $data "\n"
+ }
+ {other_options} {
+ append xml_data_other_options $data "\n"
+ }
+ {compiler_options} {
+ append xml_data_compiler_options $data "\n"
+ }
+ {bookmarks} {
+ # Append an empty file path if the path was empty
+ if {[llength $xml_data_file] == 9} {
+ lappend xml_data_file {}
+ }
+ regsub -all {[ \t\n\r]+} $data {} data
+ lappend xml_data_file $data
+ }
+ {breakpoints} {
+ regsub -all {[ \t\n\r]+} $data {} data
+ lappend xml_data_file $data
+ }
+ {path} {
+ lappend xml_data_file $data
+ }
+ {notes} {
+ append xml_data_file_notes $data "\n"
+ }
+ }
+ }
+
+ ## XML parser handler - handles XML tags
+ # @parm String arg1 - name of the element
+ # @parm List arg2 - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ proc project_xml_parser_handler_element args {
+ variable expect_data_part ;# Bool: True if on the next comes data
+ variable xml_expect ;# XML tag expected to be the next
+ variable xml_curTag ;# Currenly parsed XML tag
+ variable xml_start ;# Bool: True at start of parsing
+ variable xml_attlist ;# Auxiliary variable - List of current tag attributes
+ variable xml_warning ;# Bool: True if an error occured during parsing process
+
+ variable xml_data_tk_mcuide_project ;# Attributes of <tk_mcuide_project>
+ variable xml_data_authors ;# Content of <authors>
+ variable xml_data_copyright ;# Content of <copyright>
+ variable xml_data_licence ;# Content of <licence>
+ variable xml_data_processor ;# Attributes of <processor>
+ variable xml_data_options ;# Attributes of <options>
+ variable xml_data_graph ;# Attributes of <graph>
+ variable xml_data_description ;# Content of <description>
+ variable xml_data_todo ;# Content of <todo>
+ variable xml_data_calculator ;# Attributes of <calculator>
+ variable xml_data_other_options ;# Content of <other_options>
+ variable xml_data_compiler_options ;# Content of <compiler_options>
+ variable xml_data_files ;# Contents of <file>
+ variable xml_data_files_count ;# Number of files
+ variable xml_data_file ;# Contents of <file>
+ variable xml_data_file_notes ;# Contents of <notes>
+
+ # Abort on error
+ if {$xml_warning} {return}
+
+ # Inicalize on parser start up
+ if {$xml_start} {
+ set xml_start 0
+ set xml_expect "xml_data_tk_mcuide_project"
+ }
+
+ # At next expect data part
+ set expect_data_part 1
+
+ # Local variables
+ set tag [lindex $args 0] ;# Element name
+ set xml_attlist [lindex $args 1] ;# List of attributes
+
+ # Parse attributes
+ switch $tag {
+ {tk_mcuide_project} {
+ set xml_curTag "xml_data_tk_mcuide_project"
+ set xml_data_tk_mcuide_project [project_xml_attr_parser \
+ "general" {version date creator_ver} \
+ ]
+ }
+ {general} {
+ set xml_curTag "general"
+ project_xml_expect "authors"
+ }
+ {authors} {
+ set xml_curTag "authors"
+ project_xml_expect "copyright"
+ }
+ {copyright} {
+ set xml_curTag "copyright"
+ project_xml_expect "licence"
+ }
+ {licence} {
+ set xml_curTag "licence"
+ project_xml_expect "processor"
+ }
+ {processor} {
+ set xml_curTag "processor"
+ set xml_data_processor [project_xml_attr_parser \
+ "options" {type clock xdata xcode} \
+ ]
+ }
+ {options} {
+ set xml_curTag "options"
+ set xml_data_options [project_xml_attr_parser \
+ "graph description" {
+ watches_file scheme main_file auto_sw_enabled
+ } \
+ ]
+ }
+ {graph} {
+ set xml_curTag "graph"
+ set xml_data_graph [project_xml_attr_parser \
+ "description" {grid magnification enabled marks_s marks_l marks_o active_page} \
+ ]
+ }
+ {description} {
+ set xml_curTag "description"
+ project_xml_expect "todo"
+ }
+ {todo} {
+ set xml_curTag "todo"
+ project_xml_expect "calculator"
+ }
+ {calculator} {
+ set xml_curTag "calculator"
+ set xml_data_calculator [project_xml_attr_parser \
+ "other_options" {
+ radix angle_unit display0 display1
+ display2 memory0 memory1 memory2
+ freq time mode
+ } \
+ ]
+ }
+ {other_options} {
+ set xml_curTag "other_options"
+ project_xml_expect "compiler_options files"
+ }
+ {compiler_options} {
+ set xml_curTag "compiler_options"
+ project_xml_expect "files"
+ }
+ {files} {
+ set xml_curTag "files"
+ set files_attrs [project_xml_attr_parser \
+ "file" {count current_file current_file2 pwin_sash
+ pwin_orient selected_view} \
+ ]
+ set xml_data_files_count [list \
+ [lindex $files_attrs 0] \
+ [lrange $files_attrs 1 end] \
+ ]
+ }
+ {file} {
+ lappend__xml_data_files__xml_data_file ;# Note that this is important function
+
+ set xml_curTag "file"
+ set xml_data_file [project_xml_attr_parser \
+ "actual_line" {name active o_bookmark p_bookmark
+ file_index read_only highlight} \
+ ]
+ }
+ {actual_line} {
+ set xml_curTag "actual_line"
+ lappend xml_data_file [project_xml_attr_parser \
+ "md5_hash" {value} \
+ ]
+ }
+ {md5_hash} {
+ set xml_curTag "md5_hash"
+ lappend xml_data_file [project_xml_attr_parser \
+ "path" {value} \
+ ]
+ }
+ {path} {
+ set xml_curTag "path"
+ project_xml_expect "bookmarks"
+ }
+ {bookmarks} {
+ set xml_curTag "bookmarks"
+ project_xml_expect "breakpoints"
+ }
+ {breakpoints} {
+ set xml_curTag "breakpoints"
+ project_xml_expect "eol file"
+ }
+ {eol} {
+ set xml_curTag "eol"
+ lappend xml_data_file [project_xml_attr_parser \
+ "encoding" {value} \
+ ]
+ }
+ {encoding} {
+ set xml_curTag "encoding"
+ lappend xml_data_file [project_xml_attr_parser \
+ "file notes" {value} \
+ ]
+ }
+ {notes} {
+ set xml_curTag "notes"
+ project_xml_expect "file"
+ }
+ }
+ }
+
+ ## This procedure is a product of bad software design
+ # Variable xml_data_file must be modified by this function when xml_data_file is complete.
+ # It's because of some changes in the project file format in recent versions of the IDE
+ #
+ # THIS MUST BE ALWAYS CALLED INSTEAD OF DOING THIS: "lappend xml_data_files $xml_data_file" !
+ proc lappend__xml_data_files__xml_data_file {} {
+ variable xml_data_files ;# Contents of <files>
+ variable xml_data_file ;# Contents of <file>
+ variable xml_data_file_notes ;# Contents of <notes>
+
+ if {$xml_data_file == {}} {
+ return
+ }
+
+ if {[llength $xml_data_file] == 12} {
+ puts stderr [mc "Conveting old project file to new version"]
+
+ # eol enc
+ lappend xml_data_file {} {}
+ }
+
+ # Move attribute "highlight" from index 6 to 13
+ set xml_data_file [linsert $xml_data_file 14 [lindex $xml_data_file 6]]
+ set xml_data_file [lreplace $xml_data_file 6 6]
+
+ # Append file notes
+ lappend xml_data_file [unescape_tags $xml_data_file_notes]
+ set xml_data_file_notes {}
+
+
+ lappend xml_data_files $xml_data_file
+ }
+}
diff --git a/lib/rightpanel/hwmanager.tcl b/lib/rightpanel/hwmanager.tcl
new file mode 100755
index 0000000..0e27941
--- /dev/null
+++ b/lib/rightpanel/hwmanager.tcl
@@ -0,0 +1,419 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides panel for managing hardware plugins (e.g. Programmer, ICD, etc.)
+# --------------------------------------------------------------------------
+
+class HwManager {
+ ## COMMON
+ common PLUGIN_SEARCH_PATHS {
+ ../hwplugins
+ /usr/share/mcu8051ide/hwplugins
+ /usr/local/share/mcu8051ide/hwplugins
+ }
+ common inst_plg_count 0 ;# Int: Number of installed plugins
+
+ ## PRIVATE
+ private variable parent ;# Widget: parent widget
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+
+ private variable main_frame ;# Widget: Main frame
+ private variable pagesmanager ;# Widget: Pages manager for plugins GUI
+ private variable plg_combobox ;# Widget: Plugin selection combobox
+ private variable plg_refresh_but ;# Widget: Button "Refresh avaliable plugins"
+ private variable ins_plugin_namespaces {} ;# List of Strings: Namespaces of installed (initialized) plugins
+ private variable ins_plugin_names {} ;# List of Strings: Names of installed (initialized) plugins
+ private variable avl_plugin_files {} ;# List of Strings: Full filenames of avaliable plugins
+ private variable avl_plugin_names {} ;# List of Strings: Names of avaliable plugins
+
+ # List: Configuraion list of this panel (for session management)
+ private variable local_config [lindex $::CONFIG(HW_MANAGER_CONFIG) 0]
+ # List: Names of plugins with saved configuration (for session management)
+ private variable plugin_config_0 [lindex $::CONFIG(HW_MANAGER_CONFIG) 1]
+ # List: Configuration lists for plugins with saved configuration (for session management)
+ private variable plugin_config_1 [lindex $::CONFIG(HW_MANAGER_CONFIG) 2]
+
+
+ constructor {} {
+ }
+
+ destructor {
+ # Order all plugins to free their resources
+ hw_man_kill_childern
+ }
+
+ ## Kill all child processes
+ # @return void
+ public method hw_man_kill_childern {} {
+ foreach ns $ins_plugin_namespaces name $ins_plugin_names {
+
+ if {[catch {
+ ${ns}::dispose
+ }]} {
+ plugin_error $name $ns
+ }
+ }
+ }
+
+ ## Prepare this panel for initialization of its GUI
+ # MUST BE called before "CreateHwManagerGUI"
+ # @parm Widget _parent - Frame where this panel would be created
+ # @return void
+ public method PrepareHwManager {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Finalize initialization of this panel
+ # @return void
+ public method CreateHwManagerGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Create main GUI parts
+ set main_frame [frame $parent.main_frame]
+ set top_frame [frame $main_frame.top]
+ set pagesmanager [PagesManager $main_frame.pagesmanager -background {#eeeeee}]
+
+ ## Create parts of top panel
+ # Label "HW"
+ pack [label $top_frame.plg_label \
+ -text [mc "HW:"] \
+ ] -side left
+ # Combobox of avaliable/installed plugins
+ set plg_combobox [ttk::combobox $top_frame.plg_cbbox \
+ -exportselection 1 \
+ -width 0 \
+ -state readonly \
+ ]
+ DynamicHelp::add $plg_combobox -text [mc "List avaliable or installed HW plugins"]
+ bind $plg_combobox <<ComboboxSelected>> "$this hw_manager_plg_cbs"
+ pack $plg_combobox -fill x -expand 1 -side left
+ setStatusTip -widget $plg_combobox -text [mc "Avaliable/installed plugins"]
+ # Button "Refresh"
+ set plg_refresh_but [ttk::button $top_frame.plg_refresh_but \
+ -image ::ICONS::16::reload \
+ -command "$this hw_manager_refresh_plugins" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $top_frame.plg_refresh_but \
+ -text [mc "Refresh list avaliable or installed HW plugins"]
+ pack $plg_refresh_but -side left
+ setStatusTip -widget $plg_refresh_but -text [mc "Refresh"]
+ # Fill in the combobox
+ hw_manager_refresh_plugins
+
+ # Show GUI of the plugin from the last session
+ set idx [lsearch -ascii -exact [$plg_combobox cget -values] [lindex $local_config 0]]
+ if {$idx != -1} {
+ $plg_combobox current $idx
+ hw_manager_plg_cbs
+ }
+
+ # Pack top frame, create separator and pack the pages manager
+ pack $top_frame -fill x
+ pack [ttk::separator $main_frame.sep \
+ -orient horizontal \
+ ] -fill x -pady 5
+ pack $pagesmanager -fill both -expand 1
+ pack $main_frame -fill both -expand 1
+ }
+
+ ## Refresh list avaliable or installed HW plugins
+ # @return void
+ public method hw_manager_refresh_plugins {} {
+ if {!$gui_initialized} {CreateHwManagerGUI}
+ if {${::CLI_OPTION(no-plugins)}} {return}
+
+ set avl_plugin_files [list]
+ set avl_plugin_names [list]
+
+ # Search for avaliable plugins
+ foreach dir $PLUGIN_SEARCH_PATHS {
+ set dir [file join ${::LIB_DIRNAME} $dir]
+ catch { ;# For Microsoft Windows it has to be enclosed by catch
+ foreach file [glob -directory $dir -nocomplain -types f *.tcl] {
+ if {[lsearch -ascii -exact $avl_plugin_names [file tail [file rootname $file]]] != -1} {
+ continue
+ }
+ lappend avl_plugin_files $file
+ lappend avl_plugin_names [regsub -all {_} [file tail [file rootname $file]] { }]
+ }
+ }
+ }
+
+ # Adjust the combobox
+ $plg_combobox configure -values $avl_plugin_names
+ }
+
+ ## Switch plugin
+ # @parm String plugin_name - Plugin to switch to
+ # @return void
+ public method hw_manager_switch_plugin {plugin_name} {
+ if {!$gui_initialized} {CreateHwManagerGUI}
+ if {${::CLI_OPTION(no-plugins)}} {return}
+
+ # Install the plugin if it wasn't installed yet
+ if {[lsearch -ascii -exact $ins_plugin_names $plugin_name] == -1} {
+ # Check if the selected plugin is really avaliable
+ if {[lsearch -ascii -exact $avl_plugin_names $plugin_name] == -1} {
+ return
+ }
+
+ # Install the plugin (means initialize)
+ lappend ins_plugin_names $plugin_name
+ lappend ins_plugin_namespaces [ \
+ hw_manager_install_plugin $plugin_name [lindex \
+ $avl_plugin_files \
+ [lsearch -ascii -exact $avl_plugin_names $plugin_name] \
+ ]
+ ]
+ }
+
+ # Adjust the combobox of avaliable/installed plugins
+ $pagesmanager raise [regsub -all {\s} $plugin_name {_}]
+ }
+
+ ## "Change command" for the combobox of avaliable/installed plugins
+ # Switches the selected plugin
+ # @return void
+ public method hw_manager_plg_cbs {} {
+ if {!$gui_initialized} {CreateHwManagerGUI}
+ hw_manager_switch_plugin [$plg_combobox get]
+ }
+
+ ## Install plugin (means initialize)
+ # @parm String plugin_name - Plugin name
+ # @parm String file_path - Full path to the plugin main file
+ # @return String - Plugin namespace
+ public method hw_manager_install_plugin {plugin_name file_path} {
+ if {!$gui_initialized} {CreateHwManagerGUI}
+ if {${::CLI_OPTION(no-plugins)}} {return}
+ set plg_ns {}
+
+ if {[catch {
+ set frame [$pagesmanager add [regsub -all {\s} $plugin_name {_}]]
+ set plg_ns "::HwManager::plugin_ns::$inst_plg_count"
+ incr inst_plg_count
+
+ namespace eval $plg_ns "source {$file_path}"
+
+ set min_ide_ver [subst "\$${plg_ns}::MIN_IDE_VER"]
+ if {[package vcompare $min_ide_ver $::VERSION] == 1} {
+ tk_messageBox \
+ -title [mc "Too old version"] \
+ -type ok -icon warning \
+ -message [mc "Plugin %s requires MCU 8051 IDE version %s and above, please upgrade your MCU 8051 IDE" $plugin_name $min_ide_ver]
+ }
+
+ ${plg_ns}::init $frame $this $plg_ns [file dirname $file_path]
+
+ set idx [lsearch $plugin_config_0 $plugin_name]
+ if {$idx != -1} {
+ ${plg_ns}::restore_session [lindex $plugin_config_1 $idx]
+ }
+ }]} {
+ plugin_error $plugin_name $plg_ns
+ }
+
+ return $plg_ns
+ }
+
+ ## Handle plugin error and display error message
+ # @parm String plugin_name - Name of the plugin
+ # @parm String plugin_ns - Namespace of the plugin
+ # @return void
+ private method plugin_error {plugin_name plugin_ns} {
+
+ # Try to gain some informations about the crashed plugin
+ set plugin_ver {not defined}
+ set plugin_author {not defined}
+ set authors_email {not defined}
+ set err_info $::errorInfo
+ catch {set plugin_ver [subst "\$${plugin_ns}::P_VERSION"]}
+ catch {set plugin_author [subst "\$${plugin_ns}::AUTHOR"]}
+ catch {set authors_email [subst "\$${plugin_ns}::EMAIL"]}
+
+ # Print error message to stadrad error output
+ puts stderr "\n\n"
+ puts stderr [string repeat {=} 64]
+ puts stderr "PLUGIN ERROR:"
+ puts stderr [string repeat {-} 64]
+ puts stderr "Plugin name:\t$plugin_name"
+ puts stderr "Plugin version:\t$plugin_ver"
+ puts stderr "Author:\t\t$plugin_author <$authors_email>"
+ puts stderr [string repeat {-} 64]
+ puts stderr $err_info
+ puts stderr [string repeat {=} 64]
+ puts stderr "\n\n"
+
+ # Save log file
+ if {![catch {set log_file [open [file join ${::X::defaultDirectory} mcu8051ide_plugin_errors.log] a]}]} {
+ puts $log_file "\n\n"
+ puts $log_file [string repeat {=} 64]
+ puts $log_file "PLUGIN ERROR:"
+ puts $log_file [string repeat {-} 64]
+ puts $log_file "Plugin name:\t$plugin_name"
+ puts $log_file "Plugin version:\t$plugin_ver"
+ puts $log_file "Author:\t\t$plugin_author <$authors_email>"
+ puts $log_file [string repeat {-} 64]
+ puts $log_file $err_info
+ puts $log_file [string repeat {=} 64]
+ puts $log_file "\n\n"
+ close $log_file
+ }
+
+ # Display GUI error message
+ set dialog [toplevel .plugin_error -bg {#EEEEEE}]
+
+ # Create window frames
+ set main_dlg_frame [frame $dialog.main_frame]
+ set top_frame [frame $main_dlg_frame.top_frame -bg {#EE0000}]
+ set middle_frame [frame $main_dlg_frame.middle_frame]
+ set bottom_frame [frame $main_dlg_frame.bottom_frame]
+
+ # Create window header
+ pack [label $top_frame.header_lbl \
+ -text [mc "PLUGIN ERROR"] \
+ -bg {#EE0000} -fg {#FFFFFF} \
+ -font [font create \
+ -family helvetica \
+ -size -24 \
+ -weight bold \
+ ] \
+ ] -side left -fill x -expand 1
+
+ # Create error message text and scrollbar
+ pack [text $middle_frame.text \
+ -bg {white} -bd 0 \
+ -yscrollcommand "$middle_frame.scrollbar set" \
+ -width 0 -height 0 -relief flat -wrap word \
+ ] -side left -fill both -expand 1 -padx 5 -pady 5
+ bind $middle_frame.text <Button-1> {focus %W}
+ pack [ttk::scrollbar $middle_frame.scrollbar \
+ -orient vertical \
+ -command "$middle_frame.text yview" \
+ ] -fill y -side right
+
+ # Create button "Close"
+ pack [ttk::button $bottom_frame.ok \
+ -text [mc "Close"] \
+ -style GreenBg.TButton \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side right
+ focus -force $bottom_frame.ok
+
+ # Display error message
+ $middle_frame.text insert insert [mc "Plugin name:\t%s\n" $plugin_name]
+ $middle_frame.text insert insert [mc "Plugin version:\t%s\n" $plugin_ver]
+ $middle_frame.text insert insert [mc "Author:\t\t%s <%s>\n" $plugin_author $authors_email]
+ $middle_frame.text insert insert "\n"
+ $middle_frame.text insert insert $err_info
+ $middle_frame.text insert insert "\n"
+ $middle_frame.text configure -state disabled
+
+ # Pack window frames
+ pack $top_frame -fill x -anchor n
+ pack $middle_frame -fill both -expand 1
+ pack $bottom_frame -fill x
+ pack $main_dlg_frame -fill both -expand 1 -padx 5 -pady 5
+
+ # Configure dialog window
+ set x [expr {[winfo screenwidth $dialog] / 2 - 225}]
+ set y [expr {[winfo screenheight $dialog] / 2 - 125}]
+ wm iconphoto $dialog ::ICONS::16::bug
+ wm title $dialog [mc "PLUGIN ERROR - MCU 8051 IDE"]
+ wm minsize $dialog 450 250
+ wm geometry $dialog =550x250+$x+$y
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog"
+ update
+ raise $dialog
+ grab $dialog
+ wm transient $dialog .
+ tkwait window $dialog
+ }
+
+ ## Ask all plugins wheather they are ready for exit
+ # @return Bool - 1 == Exit allowed; 0 == Exit DENIED
+ public method hw_manager_comfirm_exit {} {
+ if {!$gui_initialized} {return 1}
+
+ foreach plg_name $ins_plugin_names plg_ns $ins_plugin_namespaces {
+ set busy_flag 0
+ catch {
+ set busy_flag [${plg_ns}::is_busy]
+ }
+ if {$busy_flag} {
+ if {[tk_messageBox \
+ -parent . \
+ -type yesno \
+ -icon question \
+ -title [mc "Hardware is busy"] \
+ -message [mc "Plugin \"%s\" is busy.\nDo you really want to close the program ?" $plg_name]
+ ] != {yes}} {
+ return 0
+ }
+ }
+ }
+
+ return 1
+ }
+
+ ## Get configuration list for this panel (intented for sessions management)
+ # @return void
+ public method hw_manager_get_cfg {} {
+ if {!$gui_initialized} {
+ return [list $local_config $plugin_config_0 $plugin_config_1]
+ }
+
+ set local_config {}
+ set plugin_config_0 {}
+ set plugin_config_1 {}
+
+ # Get panel configuration
+ lappend local_config [$plg_combobox get]
+
+ # Get plugins configuration
+ foreach plg_name $ins_plugin_names plg_ns $ins_plugin_namespaces {
+ set idx [lsearch -ascii -exact $plugin_config_0 $plg_name]
+
+ set config [${plg_ns}::save_session]
+
+ if {$idx == -1} {
+ lappend plugin_config_0 $plg_name
+ lappend plugin_config_1 $config
+ } {
+ lset plugin_config_1 $idx $config
+ }
+ }
+
+ return [list $local_config $plugin_config_0 $plugin_config_1]
+ }
+}
diff --git a/lib/rightpanel/instructiondetails.tcl b/lib/rightpanel/instructiondetails.tcl
new file mode 100755
index 0000000..0c7efaf
--- /dev/null
+++ b/lib/rightpanel/instructiondetails.tcl
@@ -0,0 +1,1755 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements tab "Instruction details" on the Right Panel
+# --------------------------------------------------------------------------
+
+class InstructionDetails {
+
+ ## COMMON
+ # Conter of instances
+ common count 0
+ # Font for instruction details
+ common instruction_font [font create -size -12 -family $::DEFAULT_FIXED_FONT]
+ ## Highlighting tags for instruction details
+ # {
+ # {tag_name foreground_color ?bold_or_italic?}
+ # ...
+ # }
+ common instruction_tags {
+ {tag_code8 #00AA00 0}
+ {tag_code11 #00AA33 0}
+ {tag_code16 #00AA55 0}
+ {tag_imm8 #FF0000 0}
+ {tag_imm16 #FF0055 0}
+ {tag_data #88DD00 0}
+ {tag_bit #555588 0}
+ {tag_DPTR #0000FF 1}
+ {tag_A #3300DD 1}
+ {tag_AB #8800FF 1}
+ {tag_SFR #0000FF 1}
+ {tag_indr #FF0000 1}
+ {tag_1 #00DD00}
+ {tag_2 #AAAA00}
+ {tag_3 #FF0000}
+ {tag_4 #8800FF}
+ {tag_5 #0000FF}
+ }
+
+ ## Detail description of each directive
+ # Format: {
+ # {directive} {description}
+ # {directive} {description}
+ # {directive} {description}
+ # . .
+ # . .
+ # . .
+ # }
+ common HELP_FOR_DIRECTIVES {}
+ common HELP_FOR_DIRECTIVES_RAW {
+ elseif {Conditional assembly\n\nSyntax:\n ELSEIF <expr>\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSEIF SOMETHING_ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only}
+ ifn {IF Not, conditional assembly\n\nSyntax:\n IFN <expr>\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n}
+ elseifn {ELSE IF Not\n\nSyntax:\n ELSEIFN <expr>\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSEIFN SOMETHING_ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only}
+ ifdef {IF DEFined\n\nSyntax:\n IFDEF <symbol>\n\nExample:\n IFDEF CND\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n}
+ elseifdef {ELSE IF DEFined\n\nSyntax:\n ELSEIFDEF <symbol>\n\nExample:\n IFDEF(2 * 4 - CND)\n MOV A, #20h\n ELSEIFDEF SOMETHING_ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only}
+ ifndef {IF Not DEFined\n\nSyntax:\n IFNDEF <symbol>\n\nExample:\n IFNDEF CND\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n}
+ elseifndef {ELSE IF Not DEFined\n\nSyntax:\n ELSEIFNDEF <symbol>\n\nExample:\n IFDEF CND\n MOV A, #20h\n ELSEIFNDEF SOMETHING_ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only}
+ ifb {IF Black\n\nSyntax:\n IFB <literal>\n\nExample:\n IFB <CND>\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only}
+ elseifb {ELSE IF Black\n\nSyntax:\n ELSEIFB <literal>\n\nExample:\n IFB <CND>\n MOV A, #20h\n ELSEIFB <SOMETHING_ELSE>\n MOV A, #40h\n ENDIF\n\literal:\n Supported by ASEM-51 only}
+ ifnb {IF Not Black\n\nSyntax:\n IFNB <literal>\n\nExample:\n IFNB <CND>\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only}
+ elseifnb {ELSE IF Not Black\n\nSyntax:\n ELSEIFNB <literal>\n\nExample:\n IFB <CND>\n MOV A, #20h\n ELSEIFNB <SOMETHING_ELSE>\n MOV A, #40h\n ENDIF\n\nNote:\n Supported by ASEM-51 only}
+ rept {REPeaT Macro\n\nSyntax:\n REPT <expr>\n\nExample:\n REPT 5\n NOP\n ENDM\n\n}
+ times {REPeaT Macro\n\nSyntax:\n TIMES <expr>\n\nExample:\n TIMES 5\n NOP\n ENDM\n\nNote:\n Supported by native assembler only}
+ name {define module NAME\n\nSyntax:\n NAME <name>\n\nExample:\n NAME my_2nd_program\n\nNote:\n Supported by ASEM-51 only}
+ if {Conditional assembly\n\nSyntax:\n IF <expr>\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n}
+ else {Conditional assembly\n\nSyntax:\n ELSE\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n}
+ endif {Conditional assembly\n\nSyntax:\n ENDIF\n\nExample:\n IF(2 * 4 - CND)\n MOV A, #20h\n ELSE\n MOV A, #40h\n ENDIF\n\n}
+ endm {END of Macro definition\n\nSyntax:\n ENDM\n\nExample:\n ABC MACRO\n MOV B, #12d\n ENDM\n\n}
+ end {END of the program\n\nSyntax:\n END\n\nExample:\n END\n\n}
+ exitm {premature end of macro expansion\n\nSyntax:\n EXITM\n\nExample:\n ABC MACRO\n MOV B, #12d\n EXITM\n NOP\n ENDM\n\n}
+ list {enable code LISTing\n\nSyntax:\n LIST\n\nExample:\n NOP\n NOLIST\n NOP\n NOP\n LIST\n NOP\n\n}
+ nolist {disabled code listing\n\nSyntax:\n NOLIST\n\nExample:\n NOP\n NOLIST\n NOP\n NOP\n LIST\n NOP\n\n}
+ dseg {switch to DATA segment \[at address\]\n\nSyntax:\n DSEG \[AT <expr>\]\n\nExample:\n DSEG at 20d\n\n}
+ iseg {switch to IDATA segment \[at address\]\n\nSyntax:\n ISEG \[AT <expr>\]\n\nExample:\n ISEG at 10d\n\n}
+ bseg {switch to BIT segment \[at address\]\n\nSyntax:\n BSEG \[AT <expr>\]\n\nExample:\n BSEG at 5d\n\n}
+ xseg {switch to XDATA segment \[at address\]\n\nSyntax:\n XSEG \[AT <expr>\]\n\nExample:\n XSEG at 30d\n\n}
+ cseg {switch to CODE segment \[at address\]\n\nSyntax:\n CSEG \[AT <expr>\]\n\nExample:\n CSEG at 40d\n\n}
+ flag {define a FLAG bit\n\nSyntax:\n <symbol> FLAG <expr>\n\nExample:\n F4 FLAG 16h\n\nNote:\n Deprecated directive. Consider directive BIT instead.}
+ skip {SKIP bytes in the code memory\n\nSyntax:\n SKIP <expr>\n\nExample:\n SKIP 5\n\n}
+ equ {EQUivalent\n\nSyntax:\n <symbol> EQU <expr>\n\nExample:\n ABC EQU R0\n XYZ EQU 4Eh+12\n\n}
+ bit {define BIT address\n\nSyntax:\n <symbol> BIT <expr>\n\nExample:\n ABC BIT P4.5\n\n}
+ set {SET numeric variable or variable register\n\nSyntax:\n <symbol> SET <expr>\n <symbol> SET <register>\n\nExample:\n ALPHA SET R0\N ALPHA SET 42*BETA\n\n}
+ code {define address in the CODE memory\n\nSyntax:\n <symbol> CODE <expr>\n\nExample:\n TBL CODE 600h\n\n}
+ data {define address in the DATA memory\n\nSyntax:\n <symbol> DATA <expr>\n\nExample:\n UIV DATA 20h\n\n}
+ idata {define address in the Internal DATA memory\n\nSyntax:\n <symbol> IDATA <expr>\n\nExample:\n UIV IDATA 20h\n\n}
+ xdata {define address in the External DATA memory\n\nSyntax:\n <symbol> XDATA <expr>\n\nExample:\n UIV XDATA 400h\n\n}
+ macro {MACRO definition\n\nSyntax:\n <macro> MACRO \[<arg0> \[,<arg1> ... \]\n\n\nExample:\n ABC MACRO X\n MOV X, #12d\n ENDM\n\n}
+ ds {Define Space\n\nSyntax:\n DS <expr>\n\nExample:\n DS 2+4\n\n}
+ dw {Define Words\n\nSyntax:\n DW <expr1> \[,<expr2> ... \]\n\nExample:\n DW 0,02009H,2009,4171\n\n}
+ db {Define Bytes\n\nSyntax:\n DB <expr1> \[,<expr2> ... \]\n\nExample:\n DB 24,'August',09,(2*8+24)/8\n\n}
+ dbit {Define BITs\n\nSyntax:\n DBIT <expr>\n\nExample:\n DBIT 4+2\n\n}
+ include {INCLUDE an external source code\n\nSyntax:\n INCLUDE <filename>\n\nExample:\n INCLUDE 'my file.asm'\n\n}
+ org {ORiGin of segment location\n\nSyntax:\n ORG <expr>\n\nExample:\n ORG 0Bh\n\n}
+ using {USING register banks\n\nSyntax:\n USING <expr>\n\nExample:\n USING 2\n\n}
+ byte {define BYTE address in the data memory\n\nSyntax:\n <symbol> BYTE <expr>\n\nExample:\n UIV BYTE 20h\n\nNote:\n Deprecated directive. Consider directive DATA instead.}
+
+ {$cond} {List full IFxx .. ENDIF\n\nSyntax:\n \$COND\n\nExample:\n \$COND\n\nNote:\n Supported by ASEM-51 only}
+ {$nocond} {Don't list lines in false branches\n\nSyntax:\n \$NOCOND\n\nExample:\n \$NOCOND\n\nNote:\n Supported by ASEM-51 only}
+ {$condonly} {List assembled lines only\n\nSyntax:\n \$CONDONLY\n\nExample:\n \$CONDONLY\n\nNote:\n Supported by ASEM-51 only}
+ {$date} {Inserts date string into page header\n\nSyntax:\n \$DATE(string)\n\nExample:\n \$DATE(1965-12-31)\n\n}
+ {$da} {Inserts date string into page header\n\nSyntax:\n \$DATE(string)\n\nExample:\n \$DATE(1965-12-31)\n\n}
+ {$debug} {Include debug information\n\nSyntax:\n \$DEBUG\n\nExample:\n \$DEBUG\n\nNote:\n Supported by ASEM-51 only}
+ {$db} {Include debug information\n\nSyntax:\n \$DB\n\nExample:\n \$DB\n\nNote:\n Supported by ASEM-51 only}
+ {$nodebug} {Don't include debug information\n\nSyntax:\n \$NODEBUG\n\nExample:\n \$NODEBUG\n\nNote:\n Supported by ASEM-51 only}
+ {$nodb} {Don't include debug information\n\nSyntax:\n \$NODB\n\nExample:\n \$NODB\n\nNote:\n Supported by ASEM-51 only}
+ {$eject} {Start a new page in list file\n\nSyntax:\n \$EJECT\n\nExample:\n \$EJECT\n\n}
+ {$ej} {Start a new page in list file\n\nSyntax:\n \$EJ\n\nExample:\n \$EJ\n\n}
+ {$error} {Force a user-defined error\n\nSyntax:\n \$ERROR(string)\n\nExample:\n \$ERROR(Impossible combination ...)\n\nNote:\n Supported by ASEM-51 only}
+ {$warning} {Force a user-defined warning\n\nSyntax:\n \$WARNING(string)\n\nExample:\n \$WARNING(Testing only !)\n\nNote:\n Supported by ASEM-51 only}
+ {$ge} {List macro calls and expansion lines\n\nSyntax:\n \$GE\n\nExample:\n \$GE\n\nNote:\n Supported by ASEM-51 only}
+ {$gen} {List macro calls and expansion lines\n\nSyntax:\n \$GEN\n\nExample:\n \$GEN\n\nNote:\n Supported by ASEM-51 only}
+ {$noge} {List macro calls only\n\nSyntax:\n \$NOGE\n\nExample:\n \$NOGE\n\nNote:\n Supported by ASEM-51 only}
+ {$nogen} {List macro calls only\n\nSyntax:\n \$NOGEN\n\nExample:\n \$NOGEN\n\nNote:\n Supported by ASEM-51 only}
+ {$go} {List expansion lines only\n\nSyntax:\n \$GO\n\nExample:\n \$GO\n\nNote:\n Supported by ASEM-51 only}
+ {$genonly} {List expansion lines only\n\nSyntax:\n \$GENONLY\n\nExample:\n \$GENONLY\n\nNote:\n Supported by ASEM-51 only}
+ {$include} {Include a source file\n\nSyntax:\n \$INCLUDE(string)\n\nExample:\n \$INCLUDE(somefile.asm)\n\n}
+ {$inc} {Include a source file\n\nSyntax:\n \$INC(string)\n\nExample:\n \$INC(somefile.asm)\n\n}
+ {$list} {List subsequent source lines\n\nSyntax:\n \$LIST\n\nExample:\n \$LIST\n\n}
+ {$li} {List subsequent source lines\n\nSyntax:\n \$LI\n\nExample:\n \$LI\n\n}
+ {$noli} {Don't list subsequent source lines\n\nSyntax:\n \$NOLI\n\nExample:\n \$NOLI\n\n}
+ {$nolist} {Don't list subsequent source lines\n\nSyntax:\n \$NOLIST\n\nExample:\n \$NOLIST\n\n}
+ {$macro} {Reserve n % of free memory for macros\n\nSyntax:\n \$MACRO(int)\n\nExample:\n \$MACRO(50)\n\nNote:\n Supported by ASEM-51 only}
+ {$mr} {Reserve n % of free memory for macros\n\nSyntax:\n \$MR(int)\n\nExample:\n \$MR(50)\n\nNote:\n Supported by ASEM-51 only}
+ {$nomr} {Reserve all for the symbol table\n\nSyntax:\n \$NOMR\n\nExample:\n \$NOMR\n\nNote:\n Supported by ASEM-51 only}
+ {$nomacro} {Reserve all for the symbol table\n\nSyntax:\n \$NOMACRO\n\nExample:\n \$NOMACRO\n\nNote:\n Supported by ASEM-51 only}
+ {$mod51} {Enable predefined SFR symbols\n\nSyntax:\n \$MOD51\n\nExample:\n \$MOD51\n\nNote:\n Supported by ASEM-51 only}
+ {$mo} {Enable predefined SFR symbols\n\nSyntax:\n \$MO\n\nExample:\n \$MO\n\nNote:\n Supported by ASEM-51 only}
+ {$nomod} {Disable predefined SFR symbols\n\nSyntax:\n \$NOMOD\n\nExample:\n \$NOMOD\n\n}
+ {$nomo} {Disable predefined SFR symbols\n\nSyntax:\n \$NOMO\n\nExample:\n \$NOMO\n\n}
+ {$nomod51} {Disable predefined SFR symbols\n\nSyntax:\n \$NOMOD51\n\nExample:\n \$NOMOD51\n\n}
+ {$nobuiltin} {Don't list predefined symbols\n\nSyntax:\n \$NOBUILTIN\n\nExample:\n \$NOBUILTIN\n\nNote:\n Supported by ASEM-51 only}
+ {$notabs} {Don't use tabs in list file\n\nSyntax:\n \$NOTABS\n\nExample:\n \$NOTABS\n\nNote:\n Supported by ASEM-51 only}
+ {$paging} {Enable listing page formatting\n\nSyntax:\n \$LIST\n\nExample:\n \$PAGING\n\n}
+ {$pi} {Enable listing page formatting\n\nSyntax:\n \$PI\n\nExample:\n \$PI\n\n}
+ {$nopi} {Disable listing page formatting\n\nSyntax:\n \$NOPI\n\nExample:\n \$NOPI\n\n}
+ {$nopaging} {Disable listing page formatting\n\nSyntax:\n \$NOPAGING\n\nExample:\n \$NOPAGING\n\n}
+ {$pagelength} {Set lines per page for listing\n\nSyntax:\n \$PAGELENGTH(int)\n\nExample:\n \$PAGELENGTH(64)\n\n}
+ {$pl} {Set lines per page for listing\n\nSyntax:\n \$PL(int)\n\nExample:\n \$PL(64)\n\n}
+ {$pagewidth} {Set columns per line for listing\n\nSyntax:\n \$PAGEWIDTH(int)\n\nExample:\n \$PAGEWIDTH(132)\n\n}
+ {$pw} {Set columns per line for listing\n\nSyntax:\n \$PW(int)\n\nExample:\n \$PW(132)\n\n}
+ {$philips} {Switch on 83C75x family support\n\nSyntax:\n \$PHILIPS\n\nExample:\n \$PHILIPS\n\nNote:\n Supported by ASEM-51 only}
+ {$save} {Save current \$LIST/\$GEN/\$COND\n\nSyntax:\n \$SAVE\n\nExample:\n \$SAVE\n\nNote:\n Supported by ASEM-51 only}
+ {$sa} {Save current \$LIST/\$GEN/\$COND\n\nSyntax:\n \$SA\n\nExample:\n \$SA\n\nNote:\n Supported by ASEM-51 only}
+ {$restore} {Restore old \$LIST/\$GEN/\$COND\n\nSyntax:\n \$RESTORE\n\nExample:\n \$RESTORE\n\nNote:\n Supported by ASEM-51 only}
+ {$rs} {Restore old \$LIST/\$GEN/\$COND\n\nSyntax:\n \$RS\n\nExample:\n \$RS\n\nNote:\n Supported by ASEM-51 only}
+ {$symbols} {Create symbol table\n\nSyntax:\n \$SYMBOLS\n\nExample:\n \$SYMBOLS\n\n}
+ {$sb} {Create symbol table\n\nSyntax:\n \$SB\n\nExample:\n \$SB\n\n}
+ {$nosymbols} {Don't create symbol table\n\nSyntax:\n \$NOSYMBOLS\n\nExample:\n \$NOSYMBOLS\n\n}
+ {$nosb} {Don't create symbol table\n\nSyntax:\n \$NOSB\n\nExample:\n \$NOSB\n\n}
+ {$title} {Inserts title string into page header\n\nSyntax:\n \$TITLE(string)\n\nExample:\n \$TITLE(My firts code)\n\n}
+ {$tt} {Inserts title string into page header\n\nSyntax:\n \$TT(string)\n\nExample:\n \$TT(My firts code)\n\n}
+ {$xref} {Create cross reference\n\nSyntax:\n \$XREF\n\nExample:\n \$XREF\n\nNote:\n Supported by ASEM-51 only}
+ {$xr} {Create cross reference\n\nSyntax:\n \$XR\n\nExample:\n \$XR\n\nNote:\n Supported by ASEM-51 only}
+ {$noxref} {Don't create cross reference\n\nSyntax:\n \$NOXREF\n\nExample:\n \$NOXREF\n\nNote:\n Supported by ASEM-51 only}
+ {$noxr} {Don't create cross reference\n\nSyntax:\n \$NOXR\n\nExample:\n \$NOXR\n\nNote:\n Supported by ASEM-51 only}
+ {$noobject} {Do not create Intel HEX file\n\nSyntax:\n \$NOOBJECT\n\nExample:\n \$NOOBJECT\n\nNote:\n Supported by native assembler only}
+ {$object} {Specify file name for Intel HEX\n\nSyntax:\n \$OBJECT(string)\n\nExample:\n \$OBJECT(my_hex.hex)\n\nNote:\n Supported by native assembler only}
+ {$print} {Specify file name for list file\n\nSyntax:\n \$PRINT(string)\n\nExample:\n \$PRINT(my_list.lst)\n\nNote:\n Supported by native assembler only}
+ {$noprint} {Do not create list file at all\n\nSyntax:\n \$NOPRINT\n\nExample:\n \$NOPRINT\n\nNote:\n Supported by native assembler only}
+ {$nomacrosfirst} {Define and expand macro instruction after! conditional assembly and definitions of constants\n\nSyntax:\n \$NOMACROSFIRTS\n\nExample:\n \$NOMACROSFIRTS\n\nNote:\n Supported by native assembler only}
+ }
+
+ ## Detail description of each instruction
+ # Format: {
+ # {INSTRUCTION OPR0, OPR1 ...} {
+ # {description}
+ # {class}
+ # {note}
+ # {affected flags in order: C OV AC, for instance "{0 X 1}"}
+ # }
+ # }
+ common INSTRUCTION_DESCRIPTION {
+ {ADD A, Rn} {
+ {Add register to Accumulator}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {ADD A, direct} {
+ {Add direct byte to Accumulator}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {ADD A, @Ri} {
+ {Add indirect RAM to Accumulator}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {ADD A, #data} {
+ {Add immediate data to Accumulator}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {ADDC A, Rn} {
+ {Add register to Accumulator with Carry}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {ADDC A, direct} {
+ {Add direct byte to Accumulator with Carry}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {ADDC A, @Ri} {
+ {Add indirect RAM to Accumulator with Carry}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {ADDC A, #data} {
+ {Add immediate data to Acc with Carry}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {SUBB A, Rn} {
+ {Subtract Register from Acc with borrow}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {SUBB A, direct} {
+ {Subtract direct byte from Acc with borrow}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {SUBB A, @Ri} {
+ {Subtract indirect RAM from ACC with borrow}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {SUBB A, #data} {
+ {Subtract immediate data from Acc with borrow}
+ {Arithmetic Operations}
+ {}
+ {X X X}
+ }
+ {INC A} {
+ {Increment Accumulator}
+ {Arithmetic Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {INC Rn} {
+ {Increment register}
+ {Arithmetic Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {INC direct} {
+ {Increment direct byte}
+ {Arithmetic Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {INC @Ri} {
+ {Increment direct RAM}
+ {Arithmetic Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {DEC A} {
+ {Decrement Accumulator}
+ {Arithmetic Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {DEC Rn} {
+ {Decrement Register}
+ {Arithmetic Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {DEC direct} {
+ {Decrement direct byte}
+ {Arithmetic Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {DEC @Ri} {
+ {Decrement indirect RAM}
+ {Arithmetic Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {INC DPTR} {
+ {Increment Data Pointer}
+ {Arithmetic Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {MUL AB} {
+ {Multiply A & B}
+ {Arithmetic Operations}
+ {}
+ {0 X {}}
+ }
+ {DIV AB} {
+ {Divide A by B}
+ {Arithmetic Operations}
+ {}
+ {0 X {}}
+ }
+ {DA A} {
+ {Decimal Adjust Accumulator}
+ {Arithmetic Operations}
+ {}
+ {X {} {}}
+ }
+
+
+ {ANL A, Rn} {
+ {AND Register to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ANL A, direct} {
+ {AND direct byte to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ANL A, @Ri} {
+ {AND indirect RAM to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ANL A, #data} {
+ {AND immediate data to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ANL direct, A} {
+ {AND Accumulator to direct byte}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ANL direct, #data} {
+ {AND immediate data to direct byte}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ORL A, Rn} {
+ {OR register to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ORL A, direct} {
+ {OR direct byte to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ORL A, @Ri} {
+ {OR indirect RAM to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ORL A, #data} {
+ {OR immediate data to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ORL direct, A} {
+ {OR Accumulator to direct byte}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {ORL direct, #data} {
+ {OR immediate data to direct byte}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {XRL A, Rn} {
+ {Exclusive-OR register to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {XRL A, direct} {
+ {Exclusive-OR direct byte to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {XRL A, @Ri} {
+ {Exclusive-OR indirect RAM to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {XRL A, #data} {
+ {Exclusive-OR immediate data to Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {XRL direct, A} {
+ {Exclusive-OR Accumulator to direct byte}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {XRL direct, #data} {
+ {Exclusive-OR immediate data to direct byte}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {CLR A} {
+ {Clear Accumulator}
+ {Logical Operations}
+ {}
+ {}
+ }
+ {CPL A} {
+ {Complement Accumulator}
+ {Logical Operations}
+ {Read-Modify-Write}
+ {}
+ }
+ {RL A} {
+ {Rotate Accumulator Left}
+ {Logical Operations}
+ {}
+ {}
+ }
+ {RLC A} {
+ {Rotate Accumulator Left through the Carry}
+ {Logical Operations}
+ {}
+ {X {} {}}
+ }
+ {RR A} {
+ {Rotate Accumulator Right}
+ {Logical Operations}
+ {}
+ {}
+ }
+ {RRC A} {
+ {Rotate Accumulator Right through the Carry}
+ {Logical Operations}
+ {}
+ {X {} {}}
+ }
+ {SWAP A} {
+ {Swap nibbles within the Accumulator}
+ {Logical Operations}
+ {}
+ {}
+ }
+
+
+
+ {MOV A, Rn} {
+ {Move register to Accumulator}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV A, direct} {
+ {Move direct byte to Accumulator}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV A, @Ri} {
+ {Move indirect RAM to Accumulator}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV A, #data} {
+ {Move immediate data to Accumulator}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV Rn, A} {
+ {Move Accumulator to register}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV Rn, direct} {
+ {Move direct byte to register}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV Rn, #data} {
+ {Move immediate data to register}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV direct, A} {
+ {Move Accumulator to direct byte}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV direct, Rn} {
+ {Move register to direct byte}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV direct, direct} {
+ {Move direct byte to direct}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV direct, @Ri} {
+ {Move indirect RAM to direct byte}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV direct, #data} {
+ {Move immediate data to direct byte}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV @Ri, A} {
+ {Move Accumulator to indirect RAM}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV @Ri, direct} {
+ {Move direct byte to indirect RAM}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV @Ri, #data} {
+ {Move immediate data to indirect RAM}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOV DPTR, #data16} {
+ {Load Data Pointer with a 16-bit constant}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOVC A, @A+DPTR} {
+ {Move Code byte relative to DPTR to Acc}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOVC A, @A+PC} {
+ {Move Code byte relative to PC to Acc}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOVX A, @Ri} {
+ {Move External RAM (8-bit addr) to Acc}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOVX A, @DPTR} {
+ {Move Exernal RAM (16-bit addr) to Acc}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOVX @Ri, A} {
+ {Move Acc to External RAM (8-bit addr)}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {MOVX @DPTR, A} {
+ {Move Acc to External RAM (16-bit addr)}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {PUSH direct} {
+ {Push direct byte onto stack}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {POP direct} {
+ {Pop direct byte from stack}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {XCH A, Rn} {
+ {Exchange register with Accumulator}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {XCH A, direct} {
+ {Exchange direct byte with Accumulator}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {XCH A, @Ri} {
+ {Exchange indirect RAM with Accumulator}
+ {Data Transfer}
+ {}
+ {}
+ }
+ {XCHD A, @Ri} {
+ {Exchange low-order Digit indirect RAM with Acc}
+ {Data Transfer}
+ {}
+ {}
+ }
+
+
+ {CLR C} {
+ {Clear Carry}
+ {Boolean Variable Manipulation}
+ {}
+ {0 {} {}}
+ }
+ {CLR bit} {
+ {Clear direct bit}
+ {Boolean Variable Manipulation}
+ {Read-Modify-Write}
+ {}
+ }
+ {SETB C} {
+ {Set Carry}
+ {Boolean Variable Manipulation}
+ {}
+ {1 {} {}}
+ }
+ {SETB bit} {
+ {Set direct bit}
+ {Boolean Variable Manipulation}
+ {Read-Modify-Write}
+ {}
+ }
+ {CPL C} {
+ {Complement Carry}
+ {Boolean Variable Manipulation}
+ {Read-Modify-Write}
+ {X {} {}}
+ }
+ {CPL bit} {
+ {Complement direct bit}
+ {Boolean Variable Manipulation}
+ {Read-Modify-Write}
+ {}
+ }
+ {ANL C, bit} {
+ {AND direct bit to CARRY}
+ {Boolean Variable Manipulation}
+ {Read-Modify-Write}
+ {X {} {}}
+ }
+ {ANL C, /bit} {
+ {AND complement of direct bit to Carry}
+ {Boolean Variable Manipulation}
+ {Read-Modify-Write}
+ {X {} {}}
+ }
+ {ORL C, bit} {
+ {OR direct bit to Carry}
+ {Boolean Variable Manipulation}
+ {}
+ {X {} {}}
+ }
+ {ORL C, /bit} {
+ {OR complement of direct bit to Carry}
+ {Boolean Variable Manipulation}
+ {}
+ {X {} {}}
+ }
+ {MOV C, bit} {
+ {Move direct bit to Carry}
+ {Boolean Variable Manipulation}
+ {}
+ {X {} {}}
+ }
+ {MOV bit, C} {
+ {Move Carry to direct bit}
+ {Boolean Variable Manipulation}
+ {Read-Modify-Write}
+ {}
+ }
+ {JC rel} {
+ {Jump if Carry is set}
+ {Boolean Variable Manipulation}
+ {}
+ {}
+ }
+ {JNC rel} {
+ {Jump if Carry not set}
+ {Boolean Variable Manipulation}
+ {}
+ {}
+ }
+ {JB bit, rel} {
+ {Jump if direct Bit is set}
+ {Boolean Variable Manipulation}
+ {}
+ {}
+ }
+ {JNB bit, rel} {
+ {Jump if direct Bit is Not set}
+ {Boolean Variable Manipulation}
+ {}
+ {}
+ }
+ {JBC bit, rel} {
+ {Jump if direct Bit is set & clear bit}
+ {Boolean Variable Manipulation}
+ {Read-Modify-Write}
+ {}
+ }
+
+
+ {ACALL addr11} {
+ {Absolute Subroutine Call}
+ {Program Branching}
+ {}
+ {}
+ }
+ {LCALL addr16} {
+ {Long Subroutine Call}
+ {Program Branching}
+ {}
+ {}
+ }
+ {RET } {
+ {Return from Subroutine}
+ {Program Branching}
+ {}
+ {}
+ }
+ {RETI } {
+ {Return from interrupt}
+ {Program Branching}
+ {}
+ {}
+ }
+ {AJMP addr11} {
+ {Absolute Jump}
+ {Program Branching}
+ {}
+ {}
+ }
+ {LJMP addr16} {
+ {Long Jump}
+ {Program Branching}
+ {}
+ {}
+ }
+ {SJMP rel} {
+ {Short Jump (relative addr)}
+ {Program Branching}
+ {}
+ {}
+ }
+ {JMP @A+DPTR} {
+ {Jump indirect relative to the DPTR}
+ {Program Branching}
+ {}
+ {}
+ }
+ {JZ rel} {
+ {Jump if Accumulator is Zero}
+ {Program Branching}
+ {}
+ {}
+ }
+ {JNZ rel} {
+ {Jump if Accumulator is Not Zero}
+ {Program Branching}
+ {}
+ {}
+ }
+ {CJNE A, direct, rel} {
+ {Compare direct byte to Acc and Jump if Not Equal}
+ {Program Branching}
+ {}
+ {X {} {}}
+ }
+ {CJNE A, #data, rel} {
+ {Compare immediate to Acc and Jump if Not Equal}
+ {Program Branching}
+ {}
+ {X {} {}}
+ }
+ {CJNE Rn, #data, rel} {
+ {Compare immediate to register and Jump if Not Equal}
+ {Program Branching}
+ {}
+ {X {} {}}
+ }
+ {CJNE @Ri, #data, rel} {
+ {Compare immediate to indirect and Jump if Not Equal}
+ {Program Branching}
+ {}
+ {X {} {}}
+ }
+ {DJNZ Rn, rel} {
+ {Decrement register and Jump if Not Zero}
+ {Program Branching}
+ {Read-Modify-Write}
+ {}
+ }
+ {DJNZ direct, rel} {
+ {Decrement direct byte and Jump if Not Zero}
+ {Program Branching}
+ {Read-Modify-Write}
+ {}
+ }
+ {NOP } {
+ {No Operation}
+ {Program Branching}
+ {}
+ {}
+ }
+ }
+
+ ## PRIVATE
+ private variable instruction_text {} ;# Widget: ID of text widget of tab "Instruction details"
+ private variable instruction_menu ;# Widget: Popup menu for the text widget
+ private variable instruction_label ;# Widget: ID of label above instruction details
+ private variable header_text ;# Widget: Text header
+ private variable instruction_last {} ;# String: Last instruction shown in details window
+ private variable parent {} ;# Widget: GUI parent
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+ private variable gui_preparing 0 ;# Bool: Prearing panel GUI
+ private variable enabled 0 ;# Bool: enable procedures which are needless while loading project
+
+ private variable help_win_index 0 ;# Int: Index of help window object (just some number)
+ private variable ins_help_win_enabled 1 ;# Bool: Enable instruction help window
+ private variable ins_help_win_created 0 ;# Bool: Help window widgets are ready to be mapped by geometry manager
+ private variable ins_help_win_visible 0 ;# Bool: Flag help window visible
+ private variable ins_help_window {} ;# Widget: Help window itself
+ private variable help_win_title ;# Widget: Title label (should contain instruction name and operands)
+ ## Array of Widgets: Labels containing certain information
+ # Avaliable keys are: description, length, execution_time, opcode, note and class
+ private variable help_win_labels
+
+ constructor {} {
+ incr count
+ }
+
+ destructor {
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - GUI parent widget
+ # @return void
+ public method PrepareInstructionDetails {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Create GUI of tab "Instruction details"
+ # @return void
+ public method CreateInstructionDetailsGUI {} {
+ if {$gui_initialized || $gui_preparing || ${::Editor::editor_to_use}} {return}
+ set gui_preparing 1
+
+ # Create frames
+ set body_frame [frame $parent.frm_rightPanel_instruction_body]
+ set text_frame [frame $body_frame.frm_rightPanel_instruction_txt -bd 1 -relief sunken]
+ set header_frame [frame $parent.frm_rightPanel_instruction_header]
+
+ # Button "Show legend"
+ set button [ttk::button \
+ $header_frame.but_rightPanel_instruction_legend \
+ -image ::ICONS::16::help \
+ -style Flat.TButton \
+ -command "$this rightPanel_ins_legend" \
+ ]
+ DynamicHelp::add $header_frame.but_rightPanel_instruction_legend \
+ -text [mc "Show legend"]
+ pack $button -side right -fill none -expand 0
+ setStatusTip -widget $button -text [mc "Show legend"]
+
+ # Tab header (instruction name)
+ set instruction_label [label $header_frame.lbl_rightPanel_instruction_header \
+ -fg {#0000FF} \
+ -anchor w \
+ -padx {20px} \
+ -font [font create -weight {bold} -size -17 -family $::DEFAULT_FIXED_FONT] \
+ ]
+ pack $instruction_label -side left -fill x -expand 1
+ setStatusTip -widget $instruction_label -text [mc "Instruction name"]
+
+ # Create popup menu for instruction text and its header
+ set instruction_menu [menu $text_frame.popup_menu -tearoff 0]
+ $instruction_menu add command -label "Configure" -compound left \
+ -command {::configDialogs::rightPanel::mkDialog 1} \
+ -underline 0 -image ::ICONS::16::configure
+
+ # Text header
+ set header_text [text $text_frame.txt_rightPanel_instruction_hdr \
+ -cursor left_ptr \
+ -font $instruction_font \
+ -bg {#DDDDDD} \
+ -height 1 \
+ -bd 0 \
+ -exportselection 0 \
+ ]
+ bind $header_text <ButtonRelease-3> "tk_popup $instruction_menu %X %Y; break"
+ bind $header_text <Key-Menu> "tk_popup $instruction_menu %X %Y; break"
+ bindtags $header_text $header_text
+
+ # Instruction details text
+ set instruction_text [text $text_frame.txt_rightPanel_instruction \
+ -yscrollcommand "$body_frame.src_rightPanel_instruction set" \
+ -cursor left_ptr -state disabled -wrap word \
+ -font $instruction_font -bd 0 -exportselection 0 \
+ ]
+ # Create scrollbar
+ pack [ttk::scrollbar $body_frame.src_rightPanel_instruction \
+ -orient vertical -command "$instruction_text yview" \
+ ] -side right -fill y
+
+ setStatusTip -widget $instruction_text -text [mc "Instruction operands"]
+ bind $instruction_text <ButtonRelease-3> "tk_popup $instruction_menu %X %Y; break"
+ bind $instruction_text <Key-Menu> "tk_popup $instruction_menu %X %Y; break"
+ bind $instruction_text <<Selection>> {false_selection %W}
+ bind $instruction_text <Motion> "$this rightPanel_ins_text_motion %x %y %X %Y"
+ bind $instruction_text <Leave> "+$this rightPanel_ins_hide_ins_help_window"
+
+ $instruction_text delete 1.0 end
+ $instruction_text tag configure tag_sel -background #CCCCFF
+ $instruction_text tag configure tag_sel0 -background #E0FFE0
+ rightPanel_refresh_instruction_highlighting
+ $instruction_text tag configure tag_bold -font [font create \
+ -size -12 -family $::DEFAULT_FIXED_FONT -weight {bold}]
+
+ # Pack parts of text frame (Instruction details text, Text header)
+ pack $header_text -side top -fill x
+ pack $instruction_text -side bottom -fill both -expand 1
+ pack $text_frame -side left -fill both -expand 1
+
+ # Pack all remaining frames
+ pack $header_frame -side top -fill x
+ pack $body_frame -side bottom -fill both -expand 1
+
+ set gui_initialized 1
+ }
+
+ ## Invoke legend window for "Instruction details"
+ # @return void
+ public method rightPanel_ins_legend {} {
+ # Destroy legend window
+ if {[winfo exists .rightPanel_legend]} {
+ grab release .rightPanel_legend
+ destroy .rightPanel_legend
+ return
+ }
+ set x [expr {[winfo pointerx .] - 380}]
+ set y [winfo pointery .]
+
+ # Create legend window
+ set win [toplevel .rightPanel_legend -class {Help} -bg {#EEEEEE}]
+ set frame [frame $win.f -bg {#555555} -bd 0 -padx 1 -pady 1]
+ wm overrideredirect $win 1
+
+ # Click to close
+ bind $win <Button-1> "grab release $win; destroy $win"
+
+ # Create header "-- click to close --"
+ pack [label $frame.lbl_header \
+ -text [mc "-- click to close --"] \
+ -bg {#FFFF55} -font $::smallfont\
+ -fg {#000000} -anchor c \
+ ] -side top -anchor c -fill x
+
+ # Create text widget
+ set text [text $frame.text \
+ -bg {#FFFFCC} \
+ -exportselection 0 \
+ -takefocus 0 \
+ -cursor left_ptr \
+ -bd 0 -relief flat \
+ ]
+
+ pack $frame -fill both -expand 1
+
+ # Create text tags
+ $this right_panel_create_highlighting_tags $text $instruction_tags 0
+ $text tag configure tag_sel \
+ -relief raised \
+ -borderwidth 1 \
+ -background #F8F8F8
+ $text tag configure tag_desc
+
+ ## Fill text widget
+ # "code8"
+ set idx [$text index insert]
+ $text insert end [mc "code8"]
+ $text tag add tag_code8 $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\t8 bit offset for relative jump\n"]
+ $text tag add tag_desc $idx insert
+ # "code11"
+ set idx [$text index insert]
+ $text insert end [mc "code11"]
+ $text tag add tag_code11 $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\t11 bit program memory address\n"]
+ $text tag add tag_desc $idx insert
+ # "code16"
+ set idx [$text index insert]
+ $text insert end [mc "code16"]
+ $text tag add tag_code16 $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\t16 bit program memory address\n"]
+ $text tag add tag_desc $idx insert
+ # "imm8"
+ set idx [$text index insert]
+ $text insert end [mc "imm8"]
+ $text tag add tag_imm8 $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\t8 bit constant data\n"]
+ $text tag add tag_desc $idx insert
+ # "imm16"
+ set idx [$text index insert]
+ $text insert end [mc "imm16"]
+ $text tag add tag_imm16 $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\t16 bit constant data\n"]
+ $text tag add tag_desc $idx insert
+ # "data"
+ set idx [$text index insert]
+ $text insert end [mc "data"]
+ $text tag add tag_data $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\tinternal data memory or SFR direct address\n"]
+ $text tag add tag_desc $idx insert
+ # "bit"
+ set idx [$text index insert]
+ $text insert end [mc "bit"]
+ $text tag add tag_bit $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\tbit memory direct address\n"]
+ $text tag add tag_desc $idx insert
+
+ $text insert end "\n"
+ # "DPTR"
+ set idx [$text index insert]
+ $text insert end "DPTR"
+ $text tag add tag_DPTR $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\tData PoinTeR register (16 bit)\n"]
+ $text tag add tag_desc $idx insert
+ # "A"
+ set idx [$text index insert]
+ $text insert end "A"
+ $text tag add tag_A $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\tPrimary work register\n"]
+ $text tag add tag_desc $idx insert
+ # "AB"
+ set idx [$text index insert]
+ $text insert end "AB"
+ $text tag add tag_AB $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\tAccumulator\n"]
+ $text tag add tag_desc $idx insert
+
+ $text insert end "\n"
+ # "R0..R7"
+ set idx [$text index insert]
+ $text insert end "R0..R7"
+ $text tag add tag_SFR $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\tRegisters of active bank\n"]
+ $text tag add tag_desc $idx insert
+ # "C"
+ set idx [$text index insert]
+ $text insert end "C"
+ $text tag add tag_SFR $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\tCarry flag\n"]
+ $text tag add tag_desc $idx insert
+ # "@R0 ..."
+ set idx [$text index insert]
+ $text insert end "@R0 ..."
+ $text tag add tag_indr $idx insert
+ set idx [$text index insert]
+ $text insert end [mc "\tIndirect address"]
+ $text tag add tag_desc $idx insert
+
+ # Show the text
+ $text configure -state disabled
+ pack $text -side bottom -fill both -expand 1
+
+ # Show the window
+ wm geometry $win "=380x280+$x+$y"
+ update
+ catch {
+ grab -global $win
+ }
+ }
+
+ ## Clear instruction details window
+ # @return void
+ public method rightPanel_ins_clear {} {
+ if {!$enabled || ${::Editor::editor_to_use}} {return}
+ if {!$gui_initialized} {CreateInstructionDetailsGUI}
+ $instruction_text configure -state normal
+ $instruction_text delete 1.0 end
+ $instruction_text configure -state disabled
+ $instruction_label configure -text {}
+
+ set instruction_last {}
+ rightPanel_ins_hide_ins_help_window
+ set help_win_index 0
+ }
+
+ ## Refresh highlighting tags in "Instruction details"
+ # @return void
+ public method rightPanel_refresh_instruction_highlighting {} {
+ if {${::Editor::editor_to_use}} {return}
+ if {!$gui_initialized && !$gui_preparing} {return}
+ $this right_panel_create_highlighting_tags \
+ $instruction_text $instruction_tags 0
+ }
+
+ ## Unset current selection in "Instruction details" window
+ # @return void
+ public method rightPanel_ins_unselect {} {
+ if {!$enabled || ${::Editor::editor_to_use}} {return}
+ if {!$gui_initialized} {return}
+
+ $instruction_text tag remove tag_sel 1.0 end
+ if {$::CONFIG(VALIDATION_LEVEL) == 2} {
+ $instruction_label configure -fg {#FF0000}
+ } {
+ $instruction_label configure -fg {#0000FF}
+ }
+ }
+
+ ## Change current selection in "Instruction details" window
+ # @parm Bool perfect_match - Operand matches exactly
+ # @parm List list_of_indexes - Lines to select (benining from zero) (eg. '0 4 9')
+ # @return void
+ public method rightPanel_ins_select {perfect_match list_of_indexes} {
+ if {!$enabled || ${::Editor::editor_to_use}} {return}
+ if {!$gui_initialized} {return}
+ if {[$instruction_label cget -text] == {}} {return}
+ $instruction_label configure -fg {#0000FF}
+ if {$perfect_match} {
+ set tag tag_sel
+ } {
+ set tag tag_sel0
+ }
+ foreach line $list_of_indexes {
+ incr line
+ $instruction_text tag add $tag $line.0 "$line.0+1l"
+ }
+ $instruction_text see $line.0
+ }
+
+ ## Change current directive in "Instruction details" window
+ # @parm Char type - 'C' == Control; 'D' == Directive
+ # @parm String directive - directive name
+ # @return void
+ public method rightPanel_dir_change {type directive} {
+ if {!$enabled || ${::Editor::editor_to_use}} {return}
+ if {!$gui_initialized} {return}
+
+ regsub {^\.} $directive {} directive
+ set directive [string tolower $directive]
+ if {$instruction_last == $directive} {return}
+ set instruction_last $directive
+
+ set ins_help_win_enabled 0
+
+ # Change content of tab header
+ if {$type == {D}} {
+ set clr {#00AADD}
+ } {
+ set clr {#00AADD}
+ }
+ set dir_up [string toupper $directive]
+ $instruction_label configure -text $dir_up -fg $clr
+ $header_text delete 1.0 end
+
+ # Enable and clear the text widget
+ $instruction_text configure -state normal
+ $instruction_text delete 1.0 end
+
+ set idx [lsearch -ascii -exact $HELP_FOR_DIRECTIVES $directive]
+ if {$idx == -1} {
+ $instruction_text insert end [mc "no help available for this directive"]
+ } {
+ incr idx
+ $instruction_text insert end [lindex $HELP_FOR_DIRECTIVES $idx]
+ }
+
+ # Create highlight tags
+ $instruction_text tag add tag_DPTR 1.0 {1.0 lineend}
+ $instruction_text tag add tag_AB 3.0 {3.0 lineend}
+ $instruction_text tag add tag_AB 6.0 {6.0 lineend}
+ $instruction_text tag add tag_indr {end-2l linestart} {end-2l lineend}
+
+ # Disable the widget
+ $instruction_text configure -state disabled
+ }
+
+ ## Change current instruction in "Instruction details" window
+ # @parm String instruction - instruction name
+ # @return void
+ public method rightPanel_ins_change {instruction} {
+ if {!$enabled || ${::Editor::editor_to_use}} {return}
+ if {!$gui_initialized} {return}
+
+ set instruction [string tolower $instruction]
+ if {$instruction_last == $instruction} {return}
+ set instruction_last $instruction
+
+ set ins_help_win_enabled 0
+
+ # Change content of tab header
+ $instruction_label configure -text [string toupper $instruction] -fg {#0000FF}
+ $header_text delete 1.0 end
+ $header_text insert 1.0 "Opr 0\tOpr 1\tOpr 2\tLen Code Time"
+
+ # Find given instruction in compilers instruction set definition
+ if {[lsearch -ascii -exact ${::CompilerConsts::AllInstructions} $instruction] == -1} {return}
+
+ # Enable and clear the text widget
+ $instruction_text configure -state normal
+ $instruction_text delete 1.0 end
+
+ # Display instruction details
+ set data {}
+ foreach line [lindex $::CompilerConsts::InstructionDefinition($instruction) 1] {
+ # Write operands
+ for {set i 0} {$i < 3} {incr i} {
+ set startIndex [$instruction_text index insert]
+ set opr [lindex $line [list 0 $i]]
+
+ # Adjust operand
+ if {[lsearch -ascii -exact {code8 code11 code16 imm8 imm16 data bit} $opr] == -1} {
+ set opr [string toupper $opr]
+ }
+
+ # Insert operand
+ $instruction_text insert insert $opr
+ $instruction_text insert insert "\t"
+
+ # Highlight operand
+ switch -- $opr {
+ {code8} { ;# 8 bit offset for relative jump
+ $instruction_text tag add tag_code8 $startIndex insert-1c
+ }
+ {code11} { ;# 11 bit program memory address
+ $instruction_text tag add tag_code11 $startIndex insert-1c
+ }
+ {code16} { ;# 16 bit program memory address
+ $instruction_text tag add tag_code16 $startIndex insert-1c
+ }
+ {imm8} { ;# 8 bit constant data
+ $instruction_text tag add tag_imm8 $startIndex insert-1c
+ }
+ {imm16} { ;# 16 bit constant data
+ $instruction_text tag add tag_imm16 $startIndex insert-1c
+ }
+ {data} { ;# internal data memory or SFR direct address
+ $instruction_text tag add tag_data $startIndex insert-1c
+ }
+ {bit} { ;# bit memory direct address
+ $instruction_text tag add tag_bit $startIndex insert-1c
+ }
+ {DPTR} { ;# Data PoinTeR register (16 bit)
+ $instruction_text tag add tag_DPTR $startIndex insert-1c
+ }
+ {A} { ;# Primary work register (Accumulator)
+ $instruction_text tag add tag_A $startIndex insert-1c
+ }
+ {AB} { ;# Accumulator
+ $instruction_text tag add tag_AB $startIndex insert-1c
+ }
+ default { ;# SFR or indirect address
+ # Indirect address
+ if {[string index $opr 0] == {@}} {
+ $instruction_text tag add tag_indr $startIndex insert-1c
+ # SFR
+ } {
+ $instruction_text tag add tag_SFR $startIndex insert-1c
+ }
+ }
+ }
+ }
+
+ # Write length
+ $instruction_text insert insert " "
+ set startIndex [$instruction_text index insert]
+ set num [lindex $line 1]
+ $instruction_text insert insert $num
+ if {$num > 0 && $num < 6} {
+ $instruction_text tag add "tag_$num" $startIndex insert
+ }
+
+ # Write OP code
+ $instruction_text insert insert " "
+ $instruction_text insert insert [string toupper [lindex $line 2]]
+
+ # Write time
+ $instruction_text insert insert " "
+ set startIndex [$instruction_text index insert]
+ set num [lindex $line 4]
+ $instruction_text insert insert $num
+ if {$num > 0 && $num < 6} {
+ $instruction_text tag add "tag_$num" $startIndex insert
+ }
+
+ # Set last 9 characters to bold font
+ $instruction_text tag add tag_bold {insert-9c} insert
+ $instruction_text insert insert "\n"
+ }
+
+ # Disable the widget
+ $instruction_text configure -state disabled
+
+ # Update help window
+ if {$ins_help_win_visible} {
+ set idx $help_win_index
+ set help_win_index 0
+ show_ins_help_window $idx
+ }
+
+ set ins_help_win_enabled 1
+ }
+
+ ## Set flag enabled
+ # @parm Bool bool - New value
+ # @return void
+ public method right_panel_instruction_details_set_enabled {bool} {
+ set enabled $bool
+ }
+
+ ## Handles Motion event on the text widget
+ # @param Int x - Relative mouse pointer position
+ # @param Int y - Relative mouse pointer position
+ # @param Int X - Absolute mouse pointer position
+ # @param Int Y - Absolute mouse pointer position
+ # @return void
+ public method rightPanel_ins_text_motion {x y X Y} {
+ if {!$ins_help_win_enabled} {return}
+ set index [$instruction_text index @$x,$y]
+ set index [expr {int($index)}]
+ if {$help_win_index == $index} {
+ move_ins_help_window $X $Y
+ return
+ }
+ set help_win_index $index
+
+ show_ins_help_window $index
+ }
+
+ ## Move instruction help window
+ # @param Int X - Absolute mouse pointer position
+ # @param Int Y - Absolute mouse pointer position
+ # @return void
+ private method move_ins_help_window {X Y} {
+ if {!$ins_help_win_visible} {
+ return
+ }
+
+ # Determinate main window geometry
+ set geometry [split [wm geometry .] {+}]
+ set limits [split [lindex $geometry 0] {x}]
+
+ # Adjust X and Y
+ set x_coord [expr {$X - 5 - [lindex $geometry 1]}]
+ set y_coord [expr {$Y - 20 - [lindex $geometry 2]}]
+
+ if {$y_coord > ([lindex $limits 1] - 220)} {incr y_coord -240}
+
+ # Show the window
+ catch {
+ place $ins_help_window -anchor ne -x $x_coord -y $y_coord -width 300
+ raise $ins_help_window
+ }
+ }
+
+ ## Show instruction help window
+ # @param Int index - Line number
+ # @return void
+ private method show_ins_help_window {index} {
+ # Create help window widget
+ if {!$ins_help_win_created} {
+ create_ins_help_window
+ }
+ # Hide window if there is nothing to show
+ if {[$instruction_text compare $index.0 == end]} {
+ rightPanel_ins_hide_ins_help_window
+ return
+ }
+
+ # Set help window visibility flag
+ set ins_help_win_visible 1
+
+ # Determinate instruction name (and possibly abort the process)
+ incr index -1
+ set instruction [string tolower [$instruction_label cget -text]]
+ if {![string length $instruction]} {
+ rightPanel_ins_hide_ins_help_window
+ return
+ }
+ # Check if the instruction is really an instruction
+ if {[lsearch -ascii -exact ${::CompilerConsts::AllInstructions} $instruction] == -1} {return}
+
+ # Modify instruction name if nessesary
+ switch -- $instruction {
+ {jmp} {
+ switch -- $index {
+ 1 {set instruction {ljmp}}
+ 2 {set instruction {ajmp}}
+ 3 {set instruction {sjmp}}
+ }
+ set index 0
+ }
+ }
+
+ # Obtain detailed informations about the instruction
+ set operands_tmp [list]
+ set instruction_def [lindex $::CompilerConsts::InstructionDefinition($instruction) [list 1 $index]]
+ set operands [lindex $instruction_def 0]
+ foreach operand $operands {
+ switch -glob -- $operand {
+ a -
+ c -
+ ab -
+ @dptr -
+ @a+dptr -
+ @a+pc -
+ dptr {
+ set operand [string toupper $operand]
+ }
+ r? {
+ set operand {Rn}
+ }
+ @r? {
+ set operand {@Ri}
+ }
+ imm8 {
+ set operand {#data}
+ }
+ imm16 {
+ set operand {#data16}
+ }
+ code8 {
+ set operand {rel}
+ }
+ code11 {
+ set operand {addr11}
+ }
+ code16 {
+ set operand {addr16}
+ }
+ bit {
+ set operand {bit}
+ }
+ /bit {
+ set operand {/bit}
+ }
+ data {
+ set operand {direct}
+ }
+ }
+ lappend operands_tmp $operand
+ }
+ set operands [join $operands_tmp {, }]
+ set instruction [string toupper $instruction]
+
+ # Modify detailed informations
+ set title "$instruction\t$operands"
+
+ set ins_length [lindex $instruction_def 1]
+ set opcode [string toupper [lindex $instruction_def 2]]
+ if {[string length $ins_length]} {
+ append opcode [string repeat {-} [expr {($ins_length - 1) * 2}]]
+ }
+
+ set ins_description [lsearch -ascii -exact $INSTRUCTION_DESCRIPTION $title]
+ if {$ins_description == -1} {
+ rightPanel_ins_hide_ins_help_window
+ return
+ }
+ incr ins_description
+ set ins_description [lindex $INSTRUCTION_DESCRIPTION $ins_description]
+
+ # Fill in the help window
+ $help_win_title configure -text $title
+ $help_win_labels(description) configure -text [mc [lindex $ins_description 0]]
+ $help_win_labels(length) configure -text $ins_length
+ $help_win_labels(execution_time) configure -text [lindex $instruction_def 4]
+ $help_win_labels(opcode) configure -text "0x$opcode"
+ $help_win_labels(note) configure -text [mc [lindex $ins_description 2]]
+ $help_win_labels(class) configure -text [mc [lindex $ins_description 1]]
+ foreach i_0 {0 1 2 } \
+ i_1 {C OV AC } \
+ i_2 {C_l OV_l AC_l } \
+ {
+ set txt [lindex $ins_description [list 3 $i_0]]
+ switch -- $txt {
+ X {set clr {#00AAFF}}
+ 0 {set clr {#DD0000}}
+ 1 {set clr {#00CC00}}
+ default {set clr {#888888}}
+ }
+ $help_win_labels($i_1) configure -text $txt -fg $clr
+ $help_win_labels($i_2) configure -fg $clr
+ }
+ }
+
+ ## Hide instruction help window
+ # @return void
+ public method rightPanel_ins_hide_ins_help_window {} {
+ if {!$ins_help_win_visible} {
+ return
+ }
+
+ set help_win_index 0
+ set ins_help_win_visible 0
+ catch {
+ place forget $ins_help_window
+ }
+ }
+
+ ## Create instruciton help window
+ # @return void
+ private method create_ins_help_window {} {
+ set ins_help_win_created 1
+
+ # Create main parts of the window
+ set ins_help_window [frame .ins_help_window${count} -bd 0 -bg {#BBBBFF} -padx 2 -pady 2]
+ pack [frame $ins_help_window.top -bg {#BBBBFF}] -fill x -expand 1
+ pack [label $ins_help_window.top.img -bg {#BBBBFF} -image ::ICONS::16::info] -side left
+ pack [label $ins_help_window.top.tit -bg {#BBBBFF} -justify left -anchor w] -side left -fill x -expand 1
+ pack [frame $ins_help_window.msg -bg {#FFFFFF} -padx 10 -pady 5] -fill both -expand 1
+ set help_win_title "$ins_help_window.top.tit"
+
+ ## Create other parts of the window
+ # Descripton
+ set i 0
+ set help_win_labels(description) [ \
+ label $ins_help_window.msg.r_$i \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ -wraplength 260 -justify left \
+ ]
+ grid $help_win_labels(description) -row $i -column 0 -columnspan 2 -sticky w
+ incr i
+ # - (separator)
+ grid [ttk::separator $ins_help_window.msg.sep \
+ -orient horizontal \
+ ] -row $i -column 0 -columnspan 2 -sticky we
+ # Class
+ incr i
+ grid [label $ins_help_window.msg.l_$i \
+ -pady 0 -fg {#0000AA} \
+ -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ -text [mc "Class:"] \
+ ] -row $i -column 0 -sticky w
+ set help_win_labels(class) [ \
+ label $ins_help_window.msg.r_$i \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ]
+ grid $help_win_labels(class) -row $i -column 1 -sticky w
+ incr i
+ # Flags
+ grid [label $ins_help_window.msg.l_$i \
+ -pady 0 -fg {#0000AA} \
+ -highlightthickness 0 \
+ -text [mc "Flags:"] \
+ -bg {#FFFFFF} \
+ ] -row $i -column 0 -sticky nw
+
+ set flags_frm [frame $ins_help_window.msg.flags_frm \
+ -bg {#888888} \
+ ]
+ grid $flags_frm -row $i -column 1 -sticky w
+ incr i
+ # Length
+ grid [label $ins_help_window.msg.l_$i \
+ -pady 0 -fg {#0000AA} \
+ -highlightthickness 0 \
+ -text [mc "Length:"] \
+ -bg {#FFFFFF} \
+ ] -row $i -column 0 -sticky w
+ set help_win_labels(length) [ \
+ label $ins_help_window.msg.r_$i \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ]
+ grid $help_win_labels(length) -row $i -column 1 -sticky w
+ incr i
+ # Time
+ grid [label $ins_help_window.msg.l_$i \
+ -pady 0 -fg {#0000AA} \
+ -highlightthickness 0 \
+ -text [mc "Time:"] \
+ -bg {#FFFFFF} \
+ ] -row $i -column 0 -sticky w
+ set help_win_labels(execution_time) [ \
+ label $ins_help_window.msg.r_$i \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ]
+ grid $help_win_labels(execution_time) -row $i -column 1 -sticky w
+ incr i
+ # OPCODE
+ grid [label $ins_help_window.msg.l_$i \
+ -pady 0 -fg {#0000AA} \
+ -highlightthickness 0 \
+ -text [mc "OPCODE:"] \
+ -bg {#FFFFFF} \
+ ] -row $i -column 0 -sticky w
+ set help_win_labels(opcode) [ \
+ label $ins_help_window.msg.r_$i \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ]
+ grid $help_win_labels(opcode) -row $i -column 1 -sticky w
+ incr i
+ # Note
+ grid [label $ins_help_window.msg.l_$i \
+ -pady 0 -fg {#0000AA} \
+ -highlightthickness 0 \
+ -text [mc "Note:"] \
+ -bg {#FFFFFF} \
+ ] -row $i -column 0 -sticky w
+ set help_win_labels(note) [ \
+ label $ins_help_window.msg.r_$i \
+ -pady 0 -bg {#FFFFFF} \
+ -highlightthickness 0 \
+ ]
+ grid $help_win_labels(note) -row $i -column 1 -sticky w
+ ## Table of flags
+ # Flag C
+ set help_win_labels(C_l) [ \
+ label $flags_frm.ll_C \
+ -bg {#FFFFFF} \
+ -pady 0 \
+ -highlightthickness 0 \
+ -text "C" \
+ ]
+ grid $help_win_labels(C_l) -row 0 -column 0 -sticky nswe -padx 1 -pady 1
+ set help_win_labels(C) [ \
+ label $flags_frm.lr_C \
+ -bg {#FFFFFF} \
+ -pady 0 \
+ -highlightthickness 0 \
+ ]
+ grid $help_win_labels(C) -row 1 -column 0 -sticky nswe -padx 1 -pady 1
+ # Flag OV
+ set help_win_labels(OV_l) [ \
+ label $flags_frm.ll_OV \
+ -bg {#FFFFFF} \
+ -pady 0 \
+ -highlightthickness 0 \
+ -text "OV" \
+ ]
+ grid $help_win_labels(OV_l) -row 0 -column 1 -sticky nswe -padx 1 -pady 1
+ set help_win_labels(OV) [ \
+ label $flags_frm.lr_OV \
+ -bg {#FFFFFF} \
+ -pady 0 \
+ -highlightthickness 0 \
+ ]
+ grid $help_win_labels(OV) -row 1 -column 1 -sticky nswe -padx 1 -pady 1
+ # Flag AC
+ set help_win_labels(AC_l) [ \
+ label $flags_frm.ll_AC \
+ -bg {#FFFFFF} \
+ -pady 0 \
+ -highlightthickness 0 \
+ -text "AC" \
+ ]
+ grid $help_win_labels(AC_l) -row 0 -column 2 -sticky nswe -padx 1 -pady 1
+ set help_win_labels(AC) [ \
+ label $flags_frm.lr_AC \
+ -bg {#FFFFFF} -bd 1 \
+ -pady 0 \
+ -highlightthickness 0 \
+ ]
+ grid $help_win_labels(AC) -row 1 -column 2 -sticky nswe -padx 1 -pady 1
+ # (finalize creation of table of flags)
+ grid columnconfigure $ins_help_window.msg 0 -minsize 80
+ grid columnconfigure $ins_help_window.msg 1 -weight 1
+ }
+
+ proc initialize {} {
+ set l [llength $HELP_FOR_DIRECTIVES_RAW]
+ for {set i 0; set j 1} {$i < $l} {incr i 2; incr j 2} {
+ lappend HELP_FOR_DIRECTIVES [lindex $HELP_FOR_DIRECTIVES_RAW $i]
+ lappend HELP_FOR_DIRECTIVES [mc [subst [lindex $HELP_FOR_DIRECTIVES_RAW $j]]]
+ }
+ }
+}
+
+# Initialize
+::InstructionDetails::initialize
diff --git a/lib/rightpanel/regwatches.tcl b/lib/rightpanel/regwatches.tcl
new file mode 100755
index 0000000..ad5e433
--- /dev/null
+++ b/lib/rightpanel/regwatches.tcl
@@ -0,0 +1,2120 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements register watches (part of Right Panel)
+# --------------------------------------------------------------------------
+
+class RegWatches {
+
+ ## COMMON
+ common watches_set_shortcuts {} ;# Currently set shortcuts for register watches
+ common watches_shortcuts_cat {watches} ;# Key shortcut categories related to register watches
+ # Counter of embedded entry widgets in register watches
+ common watch_entry_count 0
+ # Conter of instances
+ common count 0
+ ## Highlighting tags for register watches
+ # {
+ # {tag_name foreground_color ?bold_or_italic?}
+ # ...
+ # }
+ common watch_text_tags {
+ {tag_Baddr #DD0000 1}
+ {tag_Xaddr #AA00FF 1}
+ {tag_Eaddr #00AAFF 1}
+ {tag_addr #0000DD 1}
+ {tag_name #8888DD {}}
+ }
+ common regfont [font create -family $::DEFAULT_FIXED_FONT -size -14]
+ # Popup menu for register watches
+ common WATCHMENU {
+ {command {Move top} {$watches:top} 0 "rightPanel_watch_move_top"
+ {top} "Move this register watch to the top of list"}
+ {command {Move up} {$watches:up} 0 "rightPanel_watch_move_up"
+ {1uparrow} "Move this register watch up"}
+ {command {Move down} {$watches:down} 1 "rightPanel_watch_move_down"
+ {1downarrow} "Move this register watch down"}
+ {command {Move bottom} {$watches:bottom} 2 "rightPanel_watch_move_bottom"
+ {bottom} "Move this register watch to the bottom of list"}
+ {separator}
+ {command {Remove} {$watches:remove} 2 "rightPanel_watch_remove"
+ {button_cancel} "Remove this register watch from the list"}
+ {separator}
+ {command {Remove all} {$watches:remove_all} 0 "rightPanel_watch_clear"
+ {editdelete} "Clear the list of register watches"}
+ {separator}
+ {command {Save} {} 0 "rightPanel_watch_save {} 1" {filesave}
+ "Save this list to a file"}
+ {command {Configure} {} 0 "rightPanel_configure 0" {configure}
+ "Configure this panel"}
+ }
+ # Configuration menu
+ common CONFMENU {
+ {cascade {Sort by} 0 "" .sort false 1 {
+ {command {Name} {} 0 "rightPanel_watch_sort_by N" {}
+ ""}
+ {command {Address} {} 0 "rightPanel_watch_sort_by A" {}
+ ""}
+ {command {Type} {} 0 "rightPanel_watch_sort_by T" {}
+ ""}
+ {separator}
+ {radiobutton "Incremental" {} ::RegWatches::sorting_order 1
+ {} 0 ""}
+ {radiobutton "Decremental" {} ::RegWatches::sorting_order 0
+ {} 0 ""}
+ }}
+ {command {Remove all} {} 0 "rightPanel_watch_clear" {editdelete}
+ ""}
+ {separator}
+ {checkbutton {Autoload from code listing} {} {::RegWatches::menu_autoload} 1 0 0
+ {rightPanel_watch_toggle_autoload_flag}}
+ }
+
+ ## PRIVATE
+ private variable enabled 0 ;# Bool: enable procedures which are needless while loading project
+ private variable obj_idx ;# Number of this object
+ private variable parent ;# Widget: parent widget
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+
+ private variable conf_button ;# Widget: Configuration button
+ private variable conf_menu {} ;# Configuration menu
+ private variable watch_menu ;# ID of popup menu for "Register watches"
+ private variable watch_text ;# ID of text widget representing list of register watches
+ private variable watch_remove_button ;# ID of button "Remove watch" - Register watches
+ private variable watch_new_button ;# ID of button "New watch" - Register watches
+ private variable watch_add_button ;# ID of button "Add watch" - Register watches
+ private variable watch_addr_entry ;# ID of entry "Address" - Register watches
+ private variable watch_search_entry ;# ID of entry "Search" - Register watches
+ private variable watch_search_clear ;# ID of button "Clear search entry" - Register watches
+
+ # Bool: Autoload from LST file
+ private variable autoload_flag [lindex $::CONFIG(REGWATCHES_CONFIG) 0]
+ private variable watches_modified 0 ;# Bool: Register watches definition modified
+ private variable search_val_in_progress 0 ;# Bool: Search entry validation in porgress
+ private variable watch_file_name {} ;# Name of file currently loaded in register watches
+ private variable watch_curLine 0 ;# Current line in list of register watches
+ private variable watch_AN_valid_ena 1 ;# Bool: Enable validation of address entry in register watches
+ private variable validator_engaged 0 ;# Bool: Address entry validation in progress
+ private variable watches_enabled 0 ;# Bool: Entry widgets in register watches enabled
+
+ private variable watch_addrs {} ;# List - {hex_addr hex_addr ...}
+ ## Array of Lists - info about particular watch
+ # format: $watch_data($hex_addr) -> {regName textVariable}
+ # note: embedded entry path == $watch_text.$textVariable
+ private variable watch_data
+
+
+ ## Object constructor
+ constructor {} {
+ incr count
+ set obj_idx $count
+ }
+
+ ## Object destructor
+ destructor {
+ if {$gui_initialized} {
+ # Remove status bar tips for popup menus
+ menu_Sbar_remove $watch_menu
+
+ # Unallocate GUI related variables
+ unset RightPanel::watch_addr$obj_idx
+ unset RightPanel::watch_name$obj_idx
+ }
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - GUI parent widget
+ # @parm String watches_file - Definition file for register watches
+ # @return void
+ public method PrepareRegWatches {_parent filename} {
+ set parent $_parent
+ set watch_file_name $filename
+ set gui_initialized 0
+ }
+
+ ## Create GUI of register watches
+ # @return void
+ public method CreateRegWatchesGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Top frame
+ set icon_bar [frame $parent.frm_rightPanel_watch_iconBar]
+ # Bottom frame
+ set text_frame [frame $parent.frm_rightPanel_watch_txt]
+ # Toolbar
+ set tool_bar [frame $parent.frm_rightPanel_watch_toolBar]
+
+ # Button "Configure"
+ set button [ttk::button $icon_bar.conf_but \
+ -image ::ICONS::16::configure \
+ -command "$this rightPanel_watch_cfg_menu" \
+ -style Flat.TButton \
+ ]
+ set conf_button $button
+ pack $button -side left -padx 3
+ # Separator
+ pack [ttk::separator $icon_bar.sep_rightPanel_watch_ib_sepm0 \
+ -orient vertical \
+ ] -side left -fill y -padx 3
+ # Button "Save"
+ set button [ttk::button $icon_bar.but_rightPanel_watch_save \
+ -image ::ICONS::16::filesave \
+ -command "$this rightPanel_watch_save {} 1" \
+ -style Flat.TButton \
+ ]
+ pack $button -side left -padx 3
+ DynamicHelp::add $button -text [mc "Save"]
+ setStatusTip -widget $button \
+ -text [mc "Save"]
+ # Button "Save as"
+ set button [ttk::button $icon_bar.but_rightPanel_watch_saveas \
+ -image ::ICONS::16::filesaveas \
+ -command "$this rightPanel_watch_saveas" \
+ -style Flat.TButton \
+ ]
+ pack $button -side left -padx 3
+ DynamicHelp::add $button -text [mc "Save under a different filename"]
+ setStatusTip -widget $button \
+ -text [mc "Save under a different filename"]
+ # Separator
+ pack [ttk::separator $icon_bar.sep_rightPanel_watch_ib_sep0 \
+ -orient vertical \
+ ] -side left -fill y -padx 3
+ # Button "Open"
+ set button [ttk::button $icon_bar.but_rightPanel_watch_open \
+ -image ::ICONS::16::fileopen \
+ -command "$this rightPanel_watch_open" \
+ -style Flat.TButton \
+ ]
+ pack $button -side left -padx 3
+ DynamicHelp::add $button -text [mc "Open *.wtc file"]
+ setStatusTip -widget $button \
+ -text [mc "Open *.wtc file"]
+ # Button "Import"
+ set button [ttk::button $icon_bar.but_rightPanel_watch_imp \
+ -image ::ICONS::16::fileimport \
+ -style Flat.TButton \
+ -command "$this rightPanel_watch_import" \
+ ]
+ pack $button -side left -padx 3
+ DynamicHelp::add $button -text [mc "Import list of registers from code listing or WTC file"]
+ setStatusTip -widget $button \
+ -text [mc "Import list of registers from *.lst or *.wtc file"]
+ # Entry "Search"
+ set watch_search_entry [ttk::entry $icon_bar.search_entry \
+ -validate key \
+ -width 0 \
+ -validatecommand "$this rightPanel_watch_search_validate %P" \
+ ]
+ DynamicHelp::add $watch_search_entry \
+ -text [mc "Enter your search string here"]
+ pack $watch_search_entry -side left -fill x -expand 1
+ setStatusTip -widget $watch_search_entry \
+ -text [mc "Search for a name"]
+ # Button "Clear search string"
+ set watch_search_clear [ttk::button $icon_bar.clear_search \
+ -image ::ICONS::16::clear_left \
+ -command "$watch_search_entry delete 0 end" \
+ -state disabled \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $icon_bar.clear_search -text [mc "Clear search string"]
+ pack $watch_search_clear -side right -after $watch_search_entry
+ setStatusTip -widget $icon_bar.clear_search \
+ -text [mc "Clear search string"]
+
+ # Entry "Address"
+ set entry [ttk::entry $tool_bar.ent_rightPanel_watch_addr \
+ -textvariable RightPanel::watch_addr$count \
+ -validatecommand "$this rightPanel_watch_addr_validate %P" \
+ -validate key \
+ -width 4 \
+ ]
+ DynamicHelp::add $entry \
+ -text [mc "Register address:\n 1 or 2 digits\tinternal RAM (not SFR)\n 3 digits\t\texpanded RAM\n 4 digits\t\texternal RAM\n dot and 2 digits\tBit"]
+ setStatusTip -widget $entry \
+ -text [mc "Register address or bit address"]
+ grid $entry -sticky w -row 2 -column 1
+ bind $entry <Return> "$this rightPanel_watch_add"
+ bind $entry <KP_Enter> "$this rightPanel_watch_add"
+
+ # Entry "Name"
+ set entry [ttk::entry $tool_bar.ent_rightPanel_watch_name \
+ -textvariable RightPanel::watch_name$count \
+ -validatecommand "$this rightPanel_watch_name_validate %P" \
+ -validate key \
+ -width 20 \
+ ]
+ setStatusTip -widget $entry \
+ -text [mc "Name of the watch. Any string."]
+ grid $entry -sticky w -row 2 -column 2 -padx 3
+ bind $entry <Return> "$this rightPanel_watch_add"
+ bind $entry <KP_Enter> "$this rightPanel_watch_add"
+ # Button "Add"
+ set watch_add_button [ttk::button $tool_bar.but_rightPanel_watch_add \
+ -image ::ICONS::16::add \
+ -command "$this rightPanel_watch_add" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $watch_add_button -text [mc "Add this entry to register watches"]
+ setStatusTip -widget $watch_add_button \
+ -text [mc "Add this entry to register watches"]
+ grid $watch_add_button -sticky w -row 2 -column 3
+ # Button "New"
+ set watch_new_button [ttk::button $tool_bar.but_rightPanel_watch_new \
+ -image ::ICONS::16::filenew \
+ -command "$this rightPanel_watch_new" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $watch_new_button -text [mc "New register watches entry"]
+ setStatusTip -widget $watch_new_button \
+ -text [mc "Create new register watch"]
+ grid $watch_new_button -sticky w -row 2 -column 4
+ # Button "Remove"
+ set watch_remove_button [ttk::button $tool_bar.but_rightPanel_watch_remove \
+ -image ::ICONS::16::button_cancel \
+ -command "$this rightPanel_watch_remove" \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $watch_remove_button -text [mc "Remove this entry"]
+ setStatusTip -widget $watch_remove_button \
+ -text [mc "Remove this entry"]
+ grid $watch_remove_button -sticky w -row 2 -column 5
+ # Label "Addr"
+ set watch_addr_entry [label $tool_bar.lbl_rightPanel_watch_addr \
+ -text [mc "Addr"] \
+ -font ${Simulator_GUI::smallfont} \
+ -fg ${Simulator_GUI::small_color} \
+ ]
+ grid $watch_addr_entry -row 1 -column 1
+ # Label "Register name"
+ grid [label $tool_bar.lbl_rightPanel_watch_name \
+ -text [mc "Register name"] \
+ -font ${Simulator_GUI::smallfont} \
+ -fg ${Simulator_GUI::small_color} \
+ ] -row 1 -column 2
+
+ # Create text widget representing list of register watches
+ set watch_text [text $text_frame.txt_rightPanel_watch \
+ -yscrollcommand "$text_frame.src_rightPanel_watch set" \
+ -bg {#FFFFFF} -font $regfont \
+ -cursor left_ptr \
+ -state disabled -exportselection 0 \
+ ]
+ # Create text tags
+ $this right_panel_create_highlighting_tags $watch_text $watch_text_tags -1
+ $watch_text tag configure tag_curLine -background ${::RightPanel::selection_color_dark}
+
+ # Create scrollbar
+ pack [ttk::scrollbar $text_frame.src_rightPanel_watch \
+ -orient vertical \
+ -command "$watch_text yview" \
+ ] -side right -fill y
+ pack $watch_text -side left -fill both -expand 1
+ # Create event bindings
+ bind $watch_text <ButtonRelease-3> "$this rightPanel_watch_popupmenu %X %Y %x %y; break"
+ bind $watch_text <Button-1> "$this rightPanel_watch_click %x %y; break"
+ bind $watch_text <<Selection>> "false_selection $watch_text; break"
+ bind $watch_text <Key-Menu> {break}
+
+ # Pack frames
+ pack $tool_bar -side bottom -anchor w
+ pack $icon_bar -side top -fill x
+ pack $text_frame -side top -fill both -expand 1
+ rightPanel_watch_switch_line 1
+
+ # Create popup menu
+ set watch_menu $parent.menu_rightPanel_watch
+ regwatches_makePopupMenu
+
+ # Refresh highlighting tags
+ rightPanel_refresh_regwatches_highlighting
+
+ # Open definition file
+ if {$watch_file_name != {}} {
+ rightPanel_watch_openfile $watch_file_name . 0
+ }
+ }
+
+ ## Sort register watches
+ # @parm Char sorting_key
+ # N - Sort by name
+ # A - Sort by address
+ # T - Sort by type
+ # @return void
+ public method rightPanel_watch_sort_by {sorting_key} {
+ # Pack all watches into one sigle list
+ set list_to_sort [list]
+ set type {}
+ foreach addr [array names watch_data] {
+
+ switch -- [string length $addr] {
+ 4 {
+ set type {X}
+ }
+ 3 {
+ if {[string index $addr 0] == {.}} {
+ set type {B}
+ } {
+ set type {E}
+ }
+ }
+ default {
+ set type {D}
+ }
+ }
+
+ lappend list_to_sort [list $addr [lindex $watch_data($addr) 0] $type]
+ }
+
+ # Incremental sorting order
+ if {$::RegWatches::sorting_order} {
+ set order {-increasing}
+ # Decremental sorting order
+ } {
+ set order {-decreasing}
+ }
+
+ switch -- $sorting_key {
+ N { ;# Name
+ set index 1
+ }
+ A { ;# Address
+ set index 0
+ }
+ T { ;# Type
+ set index 2
+ }
+ }
+
+ # Sort the list
+ set list_to_sort [lsort -dictionary $order -index $index $list_to_sort]
+
+ # Refill the panel
+ rightPanel_watch_clear 1
+ foreach entry $list_to_sort {
+ set addr [lindex $entry 0]
+ set name [lindex $entry 1]
+
+ rightPanel_watch_add $addr $name
+ }
+ }
+
+ ## Perform autoload on simulator start
+ # @parm String filename - Code listinf file
+ # @return void
+ public method rightPanel_watch_autoload {filename} {
+ if {!$autoload_flag} {return}
+ if {![file exists $filename]} {return}
+
+ rightPanel_watch_import_file $filename .
+ }
+
+ ## Autoload flag toggled (this function should be invoked from configuration menu)
+ # @return void
+ public method rightPanel_watch_toggle_autoload_flag {} {
+ set autoload_flag $::RegWatches::menu_autoload
+ }
+
+ ## Get configuration list
+ # @return void
+ public method rightPanel_watch_get_config {} {
+ return [list $::RegWatches::menu_autoload $::RegWatches::sorting_order]
+ }
+
+ ## Create configuration menu
+ # @return void
+ private method create_conf_menu {} {
+ if {$conf_menu != {}} {
+ return
+ }
+ set conf_menu $parent.conf_menu
+ menuFactory $CONFMENU $conf_menu 0 "$this " 0 {}
+
+ watch_disEna_buttons
+ }
+
+ ## Invoke configuration menu
+ # @return void
+ public method rightPanel_watch_cfg_menu {} {
+ create_conf_menu
+
+ set x [winfo rootx $conf_button]
+ set y [winfo rooty $conf_button]
+ incr y [winfo height $conf_button]
+
+ set ::RegWatches::menu_autoload $autoload_flag
+ tk_popup $conf_menu $x $y
+ }
+
+ ## Refresh highlighting tags
+ # @return void
+ public method rightPanel_refresh_regwatches_highlighting {} {
+ if {!$gui_initialized} {return}
+ $this right_panel_create_highlighting_tags $watch_text $watch_text_tags -1
+ }
+
+ ## Recreate popup menu
+ # @return void
+ public method regwatches_makePopupMenu {} {
+ if {!$gui_initialized} {return}
+ if {[winfo exists $watch_menu]} {destroy $watch_menu}
+ menuFactory $WATCHMENU $watch_menu 0 "$this " 0 {}
+ }
+
+
+ ## Retrun name of file currently loaded in register watches
+ # @return String - filename
+ public method getWatchesFileName {} {
+ # Determinate project root path
+ set prj_path [$this cget -projectPath]
+ append prj_path {/}
+
+ # Return relative directory location
+ if {![string first $prj_path $watch_file_name]} {
+ return [string range $watch_file_name [string length $prj_path] end]
+ # Return absolute directory location
+ } {
+ return $watch_file_name
+ }
+ }
+
+ ## (Re)set dynamic shortcuts for the given entry widget
+ # @parm Widget entry - Target entry widget
+ # @return void
+ private method watch_entry_shortcuts_reset {entry} {
+ if {!$gui_initialized} {return}
+
+ # Unset previous configuration
+ foreach key $watches_set_shortcuts {
+ bind $entry <$key> {}
+ }
+ set set_shortcuts {}
+
+ # Iterate over shortcuts definition
+ foreach block ${::SHORTCUTS_LIST} {
+ # Determinate category
+ set category [lindex $block 0]
+ if {[lsearch $watches_shortcuts_cat $category] == -1} {continue}
+
+ # Determinate definition list and its length
+ set block [lreplace $block 0 2]
+ set len [llength $block]
+
+ # Iterate over definition list and create bindings
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ # Determinate key sequence
+ set key [lindex $block $i]
+ if {[catch {
+ set key $::SHORTCUTS_DB($category:$key)
+ }]} then {
+ continue
+ }
+ if {$key == {}} {continue}
+
+ # Create and register new binding
+ lappend watches_set_shortcuts $key
+ set cmd [subst [lindex $block [list $j 1]]]
+ append cmd {;break}
+ bind $entry <$key> $cmd
+ }
+ }
+ }
+
+ ## Get adjusted value of address entry (register watches)
+ # @parm String string - input data ("\n" == get value from entry widget)
+ # @return String - result address
+ private method get_watchAddr {string} {
+
+ # Evaluate input string
+ if {$string == {} || $string == {.}} {
+ return { .00}
+ }
+ if {$string == "\n"} {
+ set string [subst "\$::RightPanel::watch_addr${obj_idx}"]
+ regsub {^\s+} $string {} string
+ }
+ if {[string index $string 0] == {.}} {
+ set string [string replace $string 0 0]
+ set bit_addr 1
+ } {
+ set bit_addr 0
+ }
+
+ # Adjust address
+ set len [string length $string]
+ if {$len > 2} {
+ if {$len != 4} {
+ set string " $string"
+ }
+ } {
+ if {$len == 1} {
+ set string "0$string"
+ }
+ set string " $string"
+ }
+
+ # Resturn result
+ if {$bit_addr} {
+ return [string replace $string 1 1 {.}]
+ } {
+ return [string toupper $string]
+ }
+ }
+
+ ## Get adjusted value of register name (Register watches)
+ # @parm String string - input data ("\n" == get value from entry widget)
+ # @return String - resulting register name
+ private method get_watchName {string} {
+ # Conditionaly get value from entry widget
+ if {$string == "\n"} {
+ set string [subst "\$::RightPanel::watch_name${obj_idx}"]
+ regsub {\t+$} $string {} string
+ }
+
+ # Adjust resulting string
+ set len [string length $string]
+ append string [string repeat { } [expr {23 - $len}]]
+
+ # Return result
+ return $string
+ }
+
+ ## Validate content of address entry - Register watches
+ # @parm String value - input value
+ # @return Bool - result
+ public method rightPanel_watch_addr_validate {value} {
+
+ # Check if validation is enabled
+ if {!$watch_AN_valid_ena} {return 1}
+
+ # Check for allowed length
+ if {[string length $value] > 4} {
+ return 0
+ }
+
+ # Check for allowed characters
+ if {!([regexp {^[A-Fa-f0-9]*$} $value] || [regexp {^\.[A-Fa-f0-9]{0,2}$} $value])} {
+ return 0
+ }
+
+ # Change content of address field in register watches text widget
+ if {$watch_curLine != 0 && $value != {}} {
+
+ # Get address
+ set value [get_watchAddr $value]
+ regsub {^\s+} $value {} real_value
+
+ # Check it the desired address is unique
+ if {[lsearch -ascii -exact $watch_addrs $real_value] != -1} {
+ Sbar [mc "Unable to assign, address is already in use"]
+ return 1
+ }
+
+ # Modify variables related to the current entry
+ set idx [expr {$watch_curLine - 1}]
+ set addr [lindex $watch_addrs $idx]
+ set var [lindex $watch_data($addr) 1]
+ set watch_data($real_value) $watch_data($addr)
+ unset watch_data($addr)
+ lset watch_addrs $idx $real_value
+
+ # Synchronize
+ $watch_text.$var configure -state normal
+ rightPanel_watch_sync $real_value
+ $watch_text.$var configure -fg ${Simulator::normal_color}
+ if {!$watches_enabled || [read_from_simulator $real_value] == {--}} {
+ $watch_text.$var configure -state disabled
+ }
+
+ # Enable entry watches text widget
+ $watch_text configure -state normal
+
+ # Change content of address field
+ $watch_text delete $watch_curLine.0 $watch_curLine.4
+ $watch_text insert $watch_curLine.0 $value
+
+ # Bit -> Byte
+ if {[string index $addr 0] == {.} && [string index $real_value 0] != {.}} {
+ $watch_text.$var configure -width 2
+ help_window_hide
+
+ # Byte -> Bit
+ } elseif {[string index $addr 0] != {.} && [string index $real_value 0] == {.}} {
+ $watch_text.$var configure -width 1
+ help_window_hide
+ }
+
+ # Highlight address field
+ set len [string length $real_value]
+ if {$len == 4} {
+ set addr_tag {tag_Xaddr}
+ } elseif {$len == 3 && ([string index $real_value 0] == {.})} {
+ set addr_tag {tag_Baddr}
+ } elseif {$len == 3} {
+ set addr_tag {tag_Eaddr}
+ } else {
+ set addr_tag {tag_addr}
+ }
+ $watch_text tag add $addr_tag $watch_curLine.0 $watch_curLine.4
+
+ # Change selection
+ $watch_text tag remove tag_curLine 1.0 end
+ $watch_text tag add tag_curLine $watch_curLine.0 "$watch_curLine.0 + 1 line"
+
+ $watch_text configure -state disabled
+
+ # Adjust help window
+ help_window_update_addr $addr $real_value
+ bind $watch_text.[lindex $watch_data($real_value) 1] <Enter> \
+ "$this create_help_window_ram ${real_value}h; help_window_variable_addr"
+
+ # Adjust flag: modified
+ set watches_modified 1
+ }
+
+ # Success
+ return 1
+ }
+
+ ## Validate content of register name entry - Register watches
+ # @parm String value - input value
+ # @return Bool - result
+ public method rightPanel_watch_name_validate {value} {
+ # Check if validation is enabled
+ if {!$watch_AN_valid_ena} {return 1}
+
+ # Check for allowed length
+ if {[string length $value] > 23} {
+ return 0
+ }
+
+ # Change content of register name field in register watches text widget
+ if {$watch_curLine != 0} {
+ # Local variables
+ set name [get_watchName $value] ;# Register name
+
+ # Change reg. name in object variable watch_data
+ lset watch_data([lindex $watch_addrs [expr {$watch_curLine - 1}]]) 0 [string trimright $value]
+
+ # Enable list of watches widget
+ $watch_text configure -state normal
+
+ # Change current register name
+ $watch_text delete $watch_curLine.5 "$watch_curLine.0 lineend - 1 char"
+ $watch_text insert $watch_curLine.5 $name
+
+ # Restore reg. name text tag
+ $watch_text tag add tag_name $watch_curLine.5 $watch_curLine.28
+
+ # Adjust selection
+ $watch_text tag remove tag_curLine 1.0 end
+ $watch_text tag add tag_curLine $watch_curLine.0 "$watch_curLine.0 + 1 line"
+
+ # Disable list of watches widget
+ $watch_text configure -state disabled
+
+ # Adjust status modified
+ set watches_modified 1
+ }
+
+ # Success
+ $watch_search_entry delete 0 end
+ return 1
+ }
+
+ ## Validate content of embedded entries in list of register watches
+ # @parm String addr - hexadecimal representation of register addres
+ # @parm String value - string to validate
+ # @return Bool - result
+ public method rightPanel_watch_value_validate {addr value} {
+ if {$validator_engaged} {return 1}
+ set validator_engaged 1
+
+ # Check for allowed length
+ if {[string length $value] > 2} {
+ set validator_engaged 0
+ return 0
+ }
+
+ # Check for allowed characters
+ if {![regexp {^[A-Fa-f0-9]*$} $value]} {
+ set validator_engaged 0
+ return 0
+ }
+
+ ## Synchronize new content with simulator engine
+ if {[string index $addr 0] == {.}} {
+ set addr [string replace $addr 0 0]
+ set bit_addr 1
+ } {
+ set bit_addr 0
+ }
+ set dec_addr [expr "0x$addr"]
+ # Bit
+ if {$bit_addr} {
+ if {$value == {}} {
+ set value 0
+ }
+ if {![regexp {^[01]?$} $value]} {
+ set validator_engaged 0
+ return 0
+ }
+ $this setBit $dec_addr $value
+
+ # External RAM
+ } elseif {[string length $addr] == 4} {
+ $this setXdata $dec_addr $value
+ $this Simulator_XDATA_sync $addr
+
+ # Expanded RAM
+ } elseif {[string length $addr] == 3} {
+ $this setEram $dec_addr $value
+ $this Simulator_XDATA_sync $addr
+
+ # Internal RAM
+ } else {
+ $this setData $dec_addr $value
+ $this SimGUI_disable_sync
+ $this Simulator_GUI_sync I $dec_addr
+ $this SimGUI_enable_sync
+ }
+
+ if {$bit_addr} {
+ set addr .$addr
+ }
+ $watch_text.[lindex $watch_data($addr) 1] configure -fg ${Simulator::normal_color}
+
+ # Synchronize with help window
+ help_window_update $addr $value
+
+ # Done ...
+ set validator_engaged 0
+ return 1
+ }
+
+ ## Enable entry widgets in register watches
+ # AFFECT ALL ENTRIES (not only valid ones) !!!
+ # @return void
+ public method rightPanel_watch_force_enable {} {
+ if {!$gui_initialized} {CreateRegWatchesGUI}
+
+ set watches_enabled 1
+ foreach addr $watch_addrs {
+ $watch_text.[lindex $watch_data($addr) 1] configure -state normal
+ }
+ }
+
+ ## Enable entry widgets in register watches
+ # Affect only entries with valid address (implemented on current MCU)
+ # @return void
+ public method rightPanel_watch_enable {} {
+ if {!$gui_initialized} {CreateRegWatchesGUI}
+
+ set watches_enabled 1
+ foreach addr $watch_addrs {
+ if {[string index $addr 0] == {.}} {
+ set addr [string replace $addr 0 0]
+ set bit_addr 1
+ } {
+ set bit_addr 0
+ }
+ set dec_addr [expr "0x$addr"]
+ set len [string length $addr]
+
+ # Bit
+ if {$bit_addr} {
+ if {$dec_addr > 0x7F} {
+ if {![$this simulator_is_sfr_avaliable [$this getRegOfBit $dec_addr]]} {
+ continue
+ }
+ }
+ set addr ".$addr"
+
+ # Internal RAM
+ } elseif {$len < 3} {
+ if {$dec_addr >= [lindex [$this cget -procData] 3]} {
+ continue
+ }
+
+ # Expanded RAM
+ } elseif {$len == 3} {
+ if {$dec_addr >= [lindex [$this cget -procData] 8]} {
+ continue
+ }
+
+ # External RAM
+ } else {
+ if {$dec_addr >= [$this cget -P_option_mcu_xdata]} {
+ continue
+ }
+ }
+
+ $watch_text.[lindex $watch_data($addr) 1] configure -state normal
+ }
+ }
+
+ ## Disable all entry widgets in register watches
+ # @return void
+ public method rightPanel_watch_disable {} {
+ if {!$gui_initialized} {return}
+
+ set watches_enabled 0
+ foreach addr $watch_addrs {
+ $watch_text.[lindex $watch_data($addr) 1] configure -state disabled
+ }
+ }
+ ## Select line in list of register watches
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative Y coordinate
+ # @return void
+ public method rightPanel_watch_click {x y} {
+ rightPanel_watch_switch_line [expr {int([$watch_text index @$x,$y])}]
+ $watch_search_entry delete 0 end
+ }
+
+ ## Change current line in register watches
+ # @parm Int row - target line
+ # @return void
+ public method rightPanel_watch_switch_line {row} {
+ if {!$gui_initialized} {return}
+ set watch_AN_valid_ena 0
+
+ # Determinate number of the last row
+ set end [$watch_text index end]
+ set end [expr {int($end) - 1}]
+
+ # Restore previous state of the last selected entry box
+ if {$watch_curLine} {
+ set addr [lindex $watch_addrs [expr {$watch_curLine - 1}]]
+ set var [lindex $watch_data($addr) 1]
+ $watch_text.$var selection clear
+ $watch_text.$var configure \
+ -disabledbackground {#FFFFFF} \
+ -bg {#FFFFFF}
+ }
+
+ # Enable/Disable buttons and Clear/Keep entry widgets at the bottom
+ if {$row == $end} {
+ $watch_remove_button configure -state disabled
+ $watch_new_button configure -state disabled
+ $watch_add_button configure -state normal
+ set watch_curLine 0
+ $watch_text tag remove tag_curLine 1.0 end
+ set ::RightPanel::watch_name${obj_idx} {}
+ set ::RightPanel::watch_addr${obj_idx} {}
+ set watch_AN_valid_ena 1
+ return 0
+ } {
+ set watch_curLine $row
+ $watch_remove_button configure -state normal
+ $watch_new_button configure -state normal
+ $watch_add_button configure -state disabled
+ }
+
+ # Determinate text indexes
+ set idx0 "$row.0"
+ set idx1 [expr {$row + 1}]
+ append idx1 {.0}
+
+ # Set selection tag
+ $watch_text tag remove tag_curLine 1.0 end
+ $watch_text tag add tag_curLine $idx0 $idx1
+
+ # Adjust content of entry widgets at the bottom
+ set addr [lindex $watch_addrs [expr {$watch_curLine - 1}]]
+ set name [lindex $watch_data($addr) 0]
+ set var [lindex $watch_data($addr) 1]
+
+ set ::RightPanel::watch_name${obj_idx} [string trimright $name]
+ set ::RightPanel::watch_addr${obj_idx} [string trimright $addr]
+
+ # Change foreground color of current value entry
+ $watch_text.$var configure \
+ -fg ${Simulator::normal_color} \
+ -bg ${::RightPanel::selection_color_dark} \
+ -disabledbackground ${::RightPanel::selection_color_dark}
+
+ # Focus on value entry
+ focus $watch_text.$var
+ $watch_text.$var selection range 0 end
+ $watch_text see $row.0
+
+ set watch_AN_valid_ena 1
+ }
+
+ ## Create a new register watch
+ # @parm String - Hex address, {} == Content of address entry
+ # @parm String - Register name, {} == Content of name entry
+ # @return void
+ public method rightPanel_watch_add args {
+ # Local variables
+ set row [$watch_text index end] ;# Last row in the list
+ set row [expr {int($row) - 1}]
+ set addr [lindex $args 0] ;# Register address (Hex String)
+ set name [lindex $args 1] ;# Watch name
+ set shortAddr {} ;# Register address (Hex Number)
+
+ if {$addr == {} || $name == {}} {
+ set addr [get_watchAddr "\n"]
+ set name [get_watchName "\n"]
+ set no_sbar 0
+ } {
+ set addr [get_watchAddr $addr]
+ set name [get_watchName $name]
+ set no_sbar 1
+ }
+ set shortAddr [regsub {^\s*} $addr {}]
+
+ # Check address validity
+ if {$shortAddr == {}} {
+ if {!$no_sbar} {
+ Sbar [mc "You must specify the register address."]
+ }
+ return 0
+ }
+ if {[lsearch -ascii -exact $watch_addrs $shortAddr] != -1} {
+ if {!$no_sbar} {
+ Sbar [mc "Specified address is already used."]
+ }
+ return 0
+ }
+
+ # Enable text widget
+ $watch_text configure -state normal
+ # Insert address and watch name
+ $watch_text insert end "$addr $name"
+ # Insert text tags
+ regsub {^ +} $addr {} addr
+ set entry [watch_create_entry $addr $row $watch_entry_count]
+ $watch_text window create end -window $entry -pady 0
+ $watch_text insert end "\n"
+ set len [string length $addr]
+ if {$len == 4} {
+ set addr_tag {tag_Xaddr}
+ } elseif {$len == 3 && ([string index $addr 0] == {.})} {
+ set addr_tag {tag_Baddr}
+ } elseif {$len == 3} {
+ set addr_tag {tag_Eaddr}
+ } else {
+ set addr_tag {tag_addr}
+ }
+ $watch_text tag add $addr_tag $row.0 $row.4
+ $watch_text tag add tag_name $row.5 $row.28
+ # Disable text widget
+ $watch_text configure -state disabled
+
+ # Register new watch
+ regsub {\t+$} $name {} name
+ lappend watch_addrs $addr
+ set watch_data($addr) [list $name $watch_entry_count]
+
+ # Synchronize
+ rightPanel_watch_sync $addr
+ $entry configure -fg ${Simulator::normal_color}
+
+ # Enable/Disable the entry widget
+ if {!$watches_enabled} {
+ $entry configure -state disabled
+ }
+
+ incr watch_entry_count
+
+ # Reevaluate button states
+ watch_disEna_buttons
+
+ # Clear search entry
+ $watch_search_entry delete 0 end
+
+ # Adjust status modified
+ set watches_modified 1
+ }
+
+ ## Create entry widget for embedding in list of watches
+ # @parm String addr - hexadecimal register address
+ # @parm Int row - target row in text widget
+ # @parm Variable var - entry text variable
+ # @return Widget - resulting entry widget
+ private method watch_create_entry {addr row var} {
+ if {[string index $addr 0] == {.}} {
+ set width 1
+ } {
+ set width 2
+ }
+
+ # Create entry widget
+ set entry [entry $watch_text.$var \
+ -width $width \
+ -font ${::Simulator_GUI::entry_font} \
+ -bg {#FFFFFF} -validate key \
+ -takefocus 0 -highlightthickness 0 \
+ -disabledbackground {#FFFFFF} \
+ -vcmd "$this rightPanel_watch_value_validate $addr %P" \
+ -bd 0 -justify right \
+ ]
+
+ # Set event bindings
+ bind $entry <Button-1> "$this rightPanel_watch_switch_line $row"
+ bind $entry <Key-Up> "$this rightPanel_watch_up 1"
+ bind $entry <Key-Down> "$this rightPanel_watch_down 1"
+ bind $entry <Key-Next> "$this rightPanel_watch_down 4"
+ bind $entry <Key-Prior> "$this rightPanel_watch_up 4"
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide}
+ bind $entry <Enter> "$this create_help_window_ram ${addr}h; help_window_variable_addr"
+ bind $entry <Button-4> "$watch_text yview scroll -5 units"
+ bind $entry <Button-5> "$watch_text yview scroll +5 units"
+ watch_entry_shortcuts_reset $entry
+
+ # Return entry reference
+ return $entry
+ }
+
+ ## Clear highlight for all registers
+ # @return void
+ public method rightPanel_watch_clear_highlight {} {
+ if {!$gui_initialized} {return}
+
+ foreach addr $watch_addrs {
+ $watch_text.[lindex $watch_data($addr) 1] configure -fg ${Simulator::normal_color}
+ }
+ }
+
+ ## Clear highlight for the given register
+ # @return void
+ public method rightPanel_watch_unhighlight {addr} {
+ if {!$gui_initialized} {return}
+
+ if {[lsearch $watch_addrs $addr] == -1} {
+ return
+ }
+ $watch_text.[lindex $watch_data($addr) 1] configure -fg ${Simulator::normal_color}
+ }
+
+ ## Move current watch to the top
+ # @return void
+ public method rightPanel_watch_move_top {} {
+ rightPanel_watch_move 1
+ }
+
+ ## Move current watch to up
+ # @return void
+ public method rightPanel_watch_move_up {} {
+ # Determinate target line
+ set target_line [expr {$watch_curLine - 1}]
+ if {$target_line == 0} {return 0}
+ # Move watch
+ rightPanel_watch_move $target_line
+ }
+
+ ## Move current watch to down
+ # @return void
+ public method rightPanel_watch_move_down {} {
+ # Determinate target line
+ set target_line [expr {$watch_curLine + 1}]
+ set end [$watch_text index end]
+ set end [expr {int($end) - 1}]
+ if {$target_line == $end} {return 0}
+ # Move watch
+ rightPanel_watch_move $target_line
+ }
+
+ ## Move current watch to the bottom
+ # @return void
+ public method rightPanel_watch_move_bottom {} {
+ # Determinate target line
+ set target_line [$watch_text index end]
+ set target_line [expr {int($target_line) - 2}]
+ # Move watch
+ rightPanel_watch_move $target_line
+ }
+
+ ## Move current watch to the given line
+ # @parm Int target_line - target line
+ # @return void
+ private method rightPanel_watch_move {target_line} {
+ # Validate current line value
+ if {$watch_curLine == 0} {return}
+
+ # Local variables
+ set cur_idx [expr {$watch_curLine - 1}] ;# index in $watch_addrs -- current line
+ set trg_idx [expr {$target_line - 1}] ;# index in $watch_addrs -- target line
+ set addr [lindex $watch_addrs $cur_idx] ;# register address
+ set name [lindex $watch_data($addr) 0] ;# watch name
+ set var [lindex $watch_data($addr) 1] ;# textvariable of the value entry
+
+ # Modify variables related to the watch
+ set watch_addrs [lreplace $watch_addrs $cur_idx $cur_idx]
+ set watch_addrs [linsert $watch_addrs $trg_idx $addr]
+
+ # Enable the widget
+ $watch_text configure -state normal
+ # Change textual content
+ $watch_text delete $watch_curLine.0 "$watch_curLine.0 + 1 line linestart"
+ $watch_text insert $target_line.0 "[get_watchAddr $addr] [get_watchName $name]\n"
+ # Destroy the current entry widget
+ destroy $watch_text.$var
+ # Change embedded entry
+ set entry [watch_create_entry $addr $target_line $var]
+ $watch_text window create [list $target_line.0 lineend] -window $entry -pady 0
+ set len [string length $addr]
+ if {$len == 4} {
+ set addr_tag {tag_Xaddr}
+ } elseif {$len == 3 && ([string index [string trim $addr] 0] == {.})} {
+ set addr_tag {tag_Baddr}
+ } elseif {$len == 3} {
+ set addr_tag {tag_Eaddr}
+ } {
+ set addr_tag {tag_addr}
+ }
+ # Restore text tags
+ $watch_text tag add $addr_tag $target_line.0 $target_line.4
+ $watch_text tag add tag_name $target_line.5 $target_line.28
+ # Disable the widget
+ $watch_text configure -state disabled
+
+ # Synchronize entry widget content
+ rightPanel_watch_sync $addr
+
+ # Enable/Disable the entry widget
+ if {!$watches_enabled} {
+ $entry configure -state disabled
+ }
+
+ # Set current line
+ set watch_curLine $target_line
+ rightPanel_watch_switch_line $target_line
+
+ # Clear search entry
+ $watch_search_entry delete 0 end
+
+ # Adjust status modified
+ set watches_modified 1
+ }
+
+ ## Change current line in list of register watches to the line above the current one
+ # @parm Int lines - number of lines to skip - 1
+ # @return void
+ public method rightPanel_watch_up {lines} {
+ # Determinate number of last row in the widget
+ set end [$watch_text index end]
+ set end [expr {int($end) - 2}]
+
+ # Change current line (logicaly)
+ set line $watch_curLine
+ incr line -$lines
+ if {$line < 1} {
+ set line 1
+ }
+
+ # Change current line (physicaly)
+ $watch_text see $watch_curLine.0
+ rightPanel_watch_switch_line $line
+
+ # Clear search entry
+ $watch_search_entry delete 0 end
+ }
+
+ ## Change current line in list of register watches to the line below the current one
+ # @parm Int lines - number of lines to skip - 1
+ # @return void
+ public method rightPanel_watch_down {lines} {
+ # Determinate number of last row in the widget
+ set end [$watch_text index end]
+ set end [expr {int($end) - 2}]
+
+ # Change current line (logicaly)
+ set line $watch_curLine
+ incr line $lines
+ if {$line > $end} {
+ set line $end
+ }
+
+ # Change current line (physicaly)
+ $watch_text see $watch_curLine.0
+ rightPanel_watch_switch_line $line
+
+ # Clear search entry
+ $watch_search_entry delete 0 end
+ }
+
+ ## Binding for button "New" (Clears entry widgets at the bottom and unselect current watch)
+ # @return void
+ public method rightPanel_watch_new {} {
+ set end [$watch_text index end]
+ set end [expr {int($end) - 1}]
+ rightPanel_watch_switch_line $end
+
+ # Clear search entry
+ $watch_search_entry delete 0 end
+ }
+
+ ## Remove the current register watch
+ # @return void
+ public method rightPanel_watch_remove {} {
+ # Determinate register address
+ set addr [lindex $watch_addrs [expr {$watch_curLine - 1}]]
+ # Destroy value entry
+ set var [lindex $watch_data($addr) 1]
+ destroy $watch_text.$var
+ # Unregister watch
+ unset watch_data($addr)
+ set idx [lsearch $watch_addrs $addr]
+ set watch_addrs [lreplace $watch_addrs $idx $idx]
+
+ # Remove watch from the text widget
+ $watch_text configure -state normal
+ $watch_text delete $watch_curLine.0 "$watch_curLine.0 + 1 line"
+ $watch_text configure -state disabled
+
+ # Change current line
+ if {$watch_curLine > [llength $watch_addrs]} {
+ set watch_curLine [llength $watch_addrs]
+ }
+ if {$watch_curLine} {
+ rightPanel_watch_switch_line $watch_curLine
+ }
+
+ # Reevaluate button states
+ watch_disEna_buttons
+ # Clear search entry
+ $watch_search_entry delete 0 end
+ # Adjust status modified
+ set watches_modified 1
+ }
+
+ ## Save watches definition to a file
+ # @parm String filename - Target filename or an empty string
+ # @parm Bool force = 0 - Do not ask for overwrite
+ # @return void
+ public method rightPanel_watch_save args {
+ if {!$gui_initialized} {CreateRegWatchesGUI}
+
+ set filename [lindex $args 0]
+ set force [lindex $args 1]
+ if {$filename != {}} {
+ set watch_file_name $filename
+ }
+ if {$force != {1}} {
+ set force 0
+ }
+
+ # If no filename specified -> invoke dislog "Save as"
+ if {$watch_file_name == {}} {
+ rightPanel_watch_saveas
+
+ # Save file
+ } {
+ # Set new filename
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $watch_file_name]} {
+ set filename "[$this cget -ProjectDir]/$watch_file_name"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $watch_file_name]} {
+ set filename [file join [$this cget -ProjectDir] $watch_file_name]
+ }
+ }
+
+ set watch_file_name [file normalize $watch_file_name]
+ # Adjust file extension
+ if {![regexp {\.wtc$} $watch_file_name]} {
+ append watch_file_name {.wtc}
+ }
+
+ if {[file exists $watch_file_name] && [file isfile $watch_file_name]} {
+ # Ask user for overwrite existing file
+ if {!$force && [tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent . \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $watch_file_name]]
+ ] != {yes}
+ } {
+ return
+ }
+ # Create a backup file
+ catch {
+ file rename -force $watch_file_name "$watch_file_name~"
+ }
+ }
+ if {[catch {
+ set file [open $watch_file_name w 420]
+ }]} {
+ if {[winfo exists .fsd]} {
+ set parent .fsd
+ } {
+ set parent .
+ }
+ tk_messageBox -type ok \
+ -parent $parent -icon warning \
+ -title [mc "Error - MCU 8051 IDE"] \
+ -message [mc "Unable to access file \"%s\", check your permissions." $watch_file_name]
+ return
+ }
+
+ # Write file header
+ puts $file "# Watches definition file -- ${::APPNAME}"
+ puts $file "# Date: [clock format [clock seconds] -format {%D}]"
+
+ # Write watches definition
+ puts -nonewline $file [regsub -all -line {\s+$} [$watch_text get 1.0 end] {}]
+
+ # Finish
+ close $file
+ Sbar [mc "Definitions saved to \"%s\"" $watch_file_name]
+
+ # Adjust status modified
+ set watches_modified 0
+ }
+ }
+
+ ## Invoke dialog "Save as" - Register watches
+ # @return void
+ public method rightPanel_watch_saveas {} {
+
+ # Abort if there is already opened some file selection dialog
+ if {[winfo exists .fsd]} {return}
+
+ # Invoke the dialog
+ KIFSD::FSD ::fsd \
+ -title [mc "Save watches - MCU 8051 IDE"] \
+ -directory [$this cget -ProjectDir] \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{MCU 8051 IDE watch definition} {*.wtc} }
+ {{All files} {*} }
+ }
+ # Save file after press of OK button
+ ::fsd setokcmd {
+ set ::filename [::fsd get]
+ if {$::filename != {} && ![file isdirectory $::filename]} {
+ ${::X::actualProject} rightPanel_watch_save $::filename
+ }
+ }
+ # Activate the dialog
+ ::fsd activate
+ }
+
+ ## Open and process watches definition file
+ # @parm String filename - name of source file
+ # @parm Widget parent - GUI parent (for error dialogs)
+ # @parm Bool clear - Clear watches before loading
+ # @return Bool - result
+ public method rightPanel_watch_openfile {filename parent clear} {
+ if {!$gui_initialized} {CreateRegWatchesGUI}
+
+ # Normalize filename
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[$this cget -projectPath]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [$this cget -projectPath] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+
+ # Set new watches filename
+ set watch_file_name $filename
+
+ # Open file
+ if {[catch {
+ set file [open $filename r]
+ }]} then {
+ tk_messageBox -parent $parent -icon warning -type ok \
+ -title [mc "File access error"] \
+ -message [mc "Unable to read file '%s'" $filename]
+ set watch_file_name {}
+ return 0
+ }
+
+ # Verify input data validity
+ while {![eof $file]} {
+ set line [gets $file]
+
+ # Skip comments and empty lines
+ if {[regexp {^\s*#} $line]} {continue}
+ if {[regexp {^\s*$} $line]} {continue}
+
+ # Local variables
+ regexp {^\s*\.?\w+} $line addr ;# Register address
+ regsub {^\s*\.?\w+\s*} $line {} name ;# Watch name
+ regsub {\s+$} $name {} name
+
+ # Check for address and name validity
+ if {
+ ![regexp {^\s*\.?[A-Fa-f0-9]+$} $addr] ||
+ [string length $addr] > 4 ||
+ [string length $name] > 23
+ } {
+ tk_messageBox \
+ -title [mc "Corrupted file"] \
+ -icon error -type ok -parent $parent \
+ -message [mc "file: %s is eighter corrupted or it is not a file in expected format." $filename]
+ return 0
+ }
+ }
+
+ # Clear watches
+ if {$clear} {
+ rightPanel_watch_clear 1
+ }
+
+ # Parse input data
+ seek $file 0
+ while {![eof $file]} {
+ set line [gets $file]
+
+ # Skip comments and empty lines
+ if {[regexp {^\s*#} $line]} {continue}
+ if {[regexp {^\s*$} $line]} {continue}
+
+ regexp {^\s*\.?\w+} $line addr ;# Register address
+ regsub {^\s*\.?\w+\s*} $line {} name ;# Watch name
+ set addr [string trimleft $addr]
+ set name [string trimright $name]
+
+ # Create new register watch
+ rightPanel_watch_add $addr $name
+ }
+
+ # Deselect all
+ rightPanel_watch_new
+
+ # Reevaluate button states (icon bar)
+ watch_disEna_buttons
+
+ # Adjust status modified
+ set watches_modified 0
+
+ # Success
+ close $file
+ return 1
+ }
+
+ ## Invoke dialog "Open file"
+ # @return void
+ public method rightPanel_watch_open {} {
+ # Invoke the dialog
+ KIFSD::FSD ::fsd \
+ -title [mc "Load watches from file - MCU 8051 IDE"] \
+ -directory [$this cget -ProjectDir] -autoclose 0 \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{MCU 8051 IDE watches definition} {*.wtc} }
+ {{All files} {*} }
+ }
+
+ # Open file after press of OK button
+ fsd setokcmd {
+ # Get chosen file name
+ set filename [::fsd get]
+ if {[${X::actualProject} rightPanel_watch_openfile $filename [::fsd get_window_name] 1]} {
+ ::fsd deactivate
+ delete object fsd
+ }
+ }
+
+ # Activate the dialog
+ fsd activate
+ }
+
+ ## Invoke dialog "Import file"
+ # @return void
+ public method rightPanel_watch_import {} {
+ # Invoke the dialog
+ KIFSD::FSD ::fsd \
+ -title [mc "Import file - MCU 8051 IDE"] \
+ -directory [$this cget -ProjectDir] -autoclose 0 \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{Code listing} {*.lst} }
+ {{MCU 8051 IDE watches definition} {*.wtc} }
+ {{All files} {*} }
+ }
+
+ # Open file after press of OK button
+ fsd setokcmd {
+ # Get chosen file name
+ set filename [::fsd get]
+ if {[${X::actualProject} rightPanel_watch_import_file $filename [::fsd get_window_name]]} {
+ ::fsd deactivate
+ delete object fsd
+ }
+ }
+
+ # Activate the dialog
+ fsd activate
+ }
+
+ ## Import file
+ # @parm String filename - Name of source file (*.lst or *.wtc)
+ # @parm Widget parent - GUI parent (for error dialogs)
+ # @return Bool - result
+ public method rightPanel_watch_import_file {filename parent} {
+ if {!$gui_initialized} {CreateRegWatchesGUI}
+
+ # Determinate file type
+ set filename [file normalize [file join [$this cget -ProjectDir] $filename]]
+ set file_type 0
+ switch -- [file extension $filename] {
+ {.wtc} { ;# Watches definition file
+ set file_type 1
+ }
+ {.lst} { ;# Code listing
+ set file_type 2
+ }
+ default { ;# Try to detect file type by file header
+ catch {
+ set file [open $filename r]
+ if {[string first {# Watches definition file} [gets $file]] == 0} {
+ set file_type 1
+ }
+ close $file
+ }
+ }
+ }
+
+ # Unknown file type
+ if {!$file_type} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Unknown file"] \
+ -message [mc "Unable to recognize file format"]
+ return 0
+ }
+
+ # -----------------------------------------------------------------------
+ ## WTC file - load and exit procedure
+ # -----------------------------------------------------------------------
+ if {$file_type == 1} {
+ return [rightPanel_watch_openfile $filename $parent 0]
+ }
+
+
+ # -----------------------------------------------------------------------
+ # LST file
+ # -----------------------------------------------------------------------
+
+ # Try to open file
+ if {[catch {
+ set file [open $filename r]
+ }]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "File access error"] \
+ -message [mc "Unable to open file:\n'%s'" $filename]
+ return 0
+ }
+
+ # Parse file
+ set read_line 0
+ set line {}
+ set name {}
+ set addr {}
+ set type {}
+ set bita 0
+ while {![eof $file]} {
+ set bita 0
+ set line [gets $file]
+
+ # Empty line - stop reading
+ if {![string length [string trimright $line "  \f"]]} {
+ set read_line 0
+ continue
+
+ # MCU 8051 IDE Assembler symbol table
+ } elseif {![string first {SYMBOL TABLE:} $line]} {
+ set read_line 1
+ continue
+
+ # ASEM-51 Assembler symbol table
+ } elseif {![string first {------------------------------------------------------------} $line]} {
+ set read_line 2
+ continue
+ }
+
+
+ # MCU 8051 IDE Assembler symbol
+ if {$read_line == 1} {
+ if {![regexp {^\w+} $line name]} {
+ continue
+ }
+ if {![regexp {[\w\s]+$} $line line]} {
+ continue
+ }
+ set type [lindex $line 0]
+
+ # Ignore all types except address
+ if {[lindex $line 1] != {ADDR}} {
+ continue
+ }
+
+ # Internal data memory
+ if {$type == {D} || $type == {I}} {
+ set addr [string range [lindex $line 2] 2 3]
+ # External data memory (inluding ERAM, EEPROM, etc.)
+ } elseif {$type == {X}} {
+ set addr [string range [lindex $line 2] 0 3]
+ # Bit addressable area
+ } elseif {$type == {B}} {
+ set bita 1
+ set addr [string range [lindex $line 2] 2 3]
+ # Another type of memory -> IGNORE
+ } else {
+ continue
+ }
+
+ # Ignore unused symbols
+ if {[lindex $line end-1] == {NOT} || [lindex $line end-2] == {NOT}} {
+ continue
+ }
+
+ # ASEM-51 Assembler symbol
+ } elseif {$read_line == 2} {
+ # Remove dangerous characters
+ regsub -all {\{\}\"\"} $line {} line
+
+ # Ignore unused symbols
+ if {[llength $line] < 4} {
+ continue
+ }
+
+ # Determinate address and symbol name
+ set type [lindex $line 1]
+ set addr [lindex $line 2]
+ set name [lindex $line 0]
+
+ # Accept only internal and external data memory
+ if {$type != {IDATA} && $type != {DATA} && $type != {XDATA} && $type != {BIT}} {
+ continue
+ }
+ if {$type == {BIT}} {
+ set bita 1
+ }
+
+ # This line is not a part of symbol table
+ } else {
+ continue
+ }
+
+ # Address must be a valid hexadecimal value
+ if {![string is xdigit -strict $addr]} {
+ continue
+ }
+
+ # Exclude SFR's
+ if {[lsearch -ascii -exact ${::ASMsyntaxHighlight::spec_registers} $name] != -1} {
+ continue
+ }
+
+ # Create new register watch
+ if {[string length $name] > 23} {
+ set name [string range $name 0 16]
+ append name {..}
+ }
+
+ if {$bita} {
+ set addr .$addr
+ }
+
+ rightPanel_watch_add $addr $name
+ set watches_modified 1
+ }
+
+ # Finalize
+ rightPanel_watch_new
+ watch_disEna_buttons
+ close $file
+ return 1
+ }
+
+ ## Remove all register watches
+ # Bool force = 0 - Don't ask user for comfirmation
+ # @return void
+ public method rightPanel_watch_clear args {
+ if {!$gui_initialized} {CreateRegWatchesGUI}
+
+ # Parse arguments
+ set force [lindex $args 0]
+ if {$force == {}} {
+ set force 0
+ }
+
+ # Ask user for comfirmation
+ if {!$force} {
+ if {[tk_messageBox \
+ -parent . \
+ -type yesno \
+ -icon question \
+ -title [mc "Are you sure ?"] \
+ -message [mc "Do you really want to clear the panel ?"]
+ ] != {yes}} {
+ return
+ }
+ }
+
+ # Clear text widget
+ $watch_text configure -state normal
+ $watch_text delete 1.0 end
+ $watch_text configure -state disabled
+
+ # Destroy all embedded entry widgets
+ foreach addr $watch_addrs {
+ destroy $watch_text.[lindex $watch_data($addr) 1]
+ }
+
+ # Clear entries on the bottom bar
+ set watch_curLine 0
+ set ::RightPanel::watch_name${obj_idx} {}
+ set ::RightPanel::watch_addr${obj_idx} {}
+
+ # Unregister all watches
+ set watch_addrs {}
+ catch {
+ array unset watch_data
+ }
+
+ # Reevaluate button states (icon bar)
+ watch_disEna_buttons
+
+ # Adjust status modified
+ set watches_modified 1
+ }
+
+ ## Search for the given string in the list of register watches -- search entry validator
+ # @parm String content - String to find/validate
+ # @return Bool - result
+ public method rightPanel_watch_search_validate {content} {
+ if {$search_val_in_progress} {return 0}
+ set search_val_in_progress 1
+
+ # Enable/Disable button "Clear search entry"
+ if {$content == {}} {
+ $watch_search_clear configure -state disabled
+ } {
+ $watch_search_clear configure -state normal
+ }
+
+ # Validate search string
+ if {[regexp {^\s*$} $content]} {
+ $watch_search_entry configure -style TEntry
+ set search_val_in_progress 0
+ return 1
+ }
+ if {[string length $content] > 23} {
+ set search_val_in_progress 0
+ return 0
+ }
+
+ # Search for the given string
+ set i 1
+ set content [string trimright $content]
+ set content [string tolower $content]
+ foreach addr $watch_addrs {
+ if {![string first $content [string tolower [lindex $watch_data($addr) 0]]]} {
+ $watch_search_entry configure -style StringFound.TEntry
+ rightPanel_watch_switch_line $i
+ focus $watch_search_entry
+ set search_val_in_progress 0
+ return 1
+ }
+ incr i
+ }
+
+ # String not found
+ $watch_search_entry configure -style StringNotFound.TEntry
+ set search_val_in_progress 0
+ return 1
+ }
+
+ ## Syncronize all register watches
+ # @return void
+ public method rightPanel_watch_sync_all {} {
+ if {!$gui_initialized} {CreateRegWatchesGUI}
+
+ # Iterate over addresses
+ foreach addr $watch_addrs {
+ # Synchronize
+ rightPanel_watch_sync $addr
+ # Clear highligh
+ set var [lindex $watch_data($addr) 1]
+ $watch_text.$var configure -fg ${Simulator::normal_color}
+ }
+ }
+
+ ## Read value from simulator engine
+ # @parm String addr - hexadecimal register address
+ # @return String - hexadecimal value or {--}
+ private method read_from_simulator {addr} {
+ ## Determinate address type (Bit / Internal / Enternal / Expanded)
+ if {[string index $addr 0] == {.}} {
+ set addr [string replace $addr 0 0]
+ if {![string length $addr]} {
+ return {--}
+ }
+ set bit_addr 1
+ } {
+ set bit_addr 0
+ }
+ set len [string length $addr]
+ set val {--}
+ set addr_dec [expr "0x$addr"]
+
+ # Bit
+ if {$bit_addr} {
+ if {$addr_dec > 0x7F} {
+ if {[$this simulator_is_sfr_avaliable [$this getRegOfBit $addr_dec]]} {
+ set val [$this getBit $addr_dec]
+ }
+ } {
+ set val [$this getBit $addr_dec]
+ }
+
+ # Internal RAM
+ } elseif {$len < 3} {
+ # Normalize address
+ if {$len == 1} {
+ set addr "0$addr"
+ }
+ # Get register value
+ if {$addr_dec < [lindex [$this cget -procData] 3]} {
+ set val [$this getData $addr_dec]
+ }
+
+ # Expanded RAM
+ } elseif {$len == 3} {
+ if {$addr_dec < [lindex [$this cget -procData] 8]} {
+ set val [$this getEram $addr_dec]
+ }
+
+ # External RAM
+ } elseif {$len == 4} {
+ if {$addr_dec < [$this cget -P_option_mcu_xdata]} {
+ set val [$this getXdata $addr_dec]
+ }
+ }
+
+ return $val
+ }
+
+ ## Synchronize all bits in the specified SFR
+ # @parm Int dec_addr - SFR register address
+ # @return void
+ public method rightPanel_watch_sync_sfr {dec_addr} {
+ if {$validator_engaged} {
+ return
+ }
+ if {$dec_addr % 8} {
+ return
+ }
+
+ for {set i 0} {$i < 8} {incr i} {
+ rightPanel_watch_sync .[format %X $dec_addr]
+ incr dec_addr
+ }
+ }
+
+ ## Synchronize one register watch
+ # @parm String addr - hexadecimal register address
+ # @return Bool - result
+ public method rightPanel_watch_sync {addr} {
+ if {$validator_engaged} {return 1}
+ if {!$gui_initialized} {CreateRegWatchesGUI}
+
+ # Detect bit address
+ if {[string index $addr 0] == {.}} {
+ set bit_addr 1
+ } {
+ set bit_addr 0
+ }
+
+ # Get register value
+ set val [read_from_simulator $addr]
+
+ # Synchronize bits in the given register
+ if {!$validator_engaged && [string length $addr] == 2} {
+ set dec_addr [expr "0x$addr"]
+
+ if {$dec_addr >= 0x20 && $dec_addr <= 0x2F} {
+ set dec_addr [expr {($dec_addr - 0x20) * 8}]
+ for {set i 0} {$i < 8} {incr i} {
+
+ set hex_addr [format %X $dec_addr]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ }
+ rightPanel_watch_sync .$hex_addr
+ incr dec_addr
+ }
+ }
+ }
+
+ # Check for watch presence
+ if {[lsearch -ascii -exact $watch_addrs $addr] == -1} {
+ return 0
+ }
+
+ # Normalize register value
+ if {!$bit_addr && [string length $val] == 1} {
+ set val "0$val"
+ }
+
+ set var [lindex $watch_data($addr) 1]
+ set path $watch_text.$var ;# Path to watch entry widget
+
+ # Determinate original value
+ set original_val [$watch_text.$var get]
+
+ # Highlight value entry
+ if { "0x$original_val" != "0x$val"} {
+ $path configure -fg ${Simulator::highlight_color}
+ }
+
+ # Set new entry value
+ set validator_engaged 1
+ $watch_text.$var delete 0 end
+ $watch_text.$var insert 0 $val
+ set validator_engaged 0
+
+ # Synchronize with help window
+ help_window_update $addr $val
+
+ # Done ...
+ return 1
+ }
+
+ ## Enable/Disable buttons on watches icon bar
+ # @return void
+ private method watch_disEna_buttons {} {
+ if {!$gui_initialized} {return}
+
+ if {[$watch_text index end] == {2.0}} {
+ set state {disabled}
+ } {
+ set state {normal}
+ }
+
+ if {$conf_menu != {}} {
+ $conf_menu entryconfigure [::mc "Sort by"] -state $state
+ $conf_menu entryconfigure [::mc "Remove all"] -state $state
+ }
+ }
+
+ ## Get status modified for register watches
+ # @return Bool - true if register watches were modified
+ public method rightPanel_watch_modified {} {
+ return $watches_modified
+ }
+
+ ## Invoke register watches popup menu
+ # @parm Int X - absolute X coordinate
+ # @parm Int Y - absolute Y coordinate
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative Y coordinate
+ # @return void
+ public method rightPanel_watch_popupmenu {X Y x y} {
+ # Change current line
+ rightPanel_watch_click $x $y
+
+ ## Enable/Disable menu items
+
+ # If address entry is not empty -> disable all
+ set addr [subst "\$::RightPanel::watch_addr${obj_idx}"]
+ if {$addr != {}} {
+ set end [$watch_text index end]
+ } {
+ set end {2.0}
+ }
+ # Empty list
+ if {$end == {2.0}} {
+ $watch_menu entryconfigure [::mc "Move top"] -state disabled
+ $watch_menu entryconfigure [::mc "Move up"] -state disabled
+ $watch_menu entryconfigure [::mc "Move down"] -state disabled
+ $watch_menu entryconfigure [::mc "Move bottom"] -state disabled
+ $watch_menu entryconfigure [::mc "Remove"] -state disabled
+ $watch_menu entryconfigure [::mc "Remove all"] -state disabled
+ # One item
+ } elseif {$end == {3.0}} {
+ $watch_menu entryconfigure [::mc "Move top"] -state disabled
+ $watch_menu entryconfigure [::mc "Move up"] -state disabled
+ $watch_menu entryconfigure [::mc "Move down"] -state disabled
+ $watch_menu entryconfigure [::mc "Move bottom"] -state disabled
+ $watch_menu entryconfigure [::mc "Remove"] -state normal
+ $watch_menu entryconfigure [::mc "Remove all"] -state normal
+ # More items
+ } else {
+ # First item
+ if {$watch_curLine == 1} {
+ $watch_menu entryconfigure [::mc "Move top"] -state disabled
+ $watch_menu entryconfigure [::mc "Move up"] -state disabled
+ $watch_menu entryconfigure [::mc "Move down"] -state normal
+ $watch_menu entryconfigure [::mc "Move bottom"] -state normal
+ # Last item
+ } elseif {$watch_curLine == ($end - 2)} {
+ $watch_menu entryconfigure [::mc "Move top"] -state normal
+ $watch_menu entryconfigure [::mc "Move up"] -state normal
+ $watch_menu entryconfigure [::mc "Move down"] -state disabled
+ $watch_menu entryconfigure [::mc "Move bottom"] -state disabled
+ # Any other item
+ } else {
+ $watch_menu entryconfigure [::mc "Move top"] -state normal
+ $watch_menu entryconfigure [::mc "Move up"] -state normal
+ $watch_menu entryconfigure [::mc "Move down"] -state normal
+ $watch_menu entryconfigure [::mc "Move bottom"] -state normal
+ }
+ $watch_menu entryconfigure [::mc "Remove"] -state normal
+ $watch_menu entryconfigure [::mc "Remove all"] -state normal
+ }
+
+ # Invoke popup menu
+ tk_popup $watch_menu $X $Y
+ }
+
+
+ ## Create bindings for defined key shortcuts -- register watches
+ # @return void
+ public method rightPanel_watch_shortcuts_reevaluate {} {
+ if {!$gui_initialized} {return}
+ foreach addr $watch_addrs {
+ watch_entry_shortcuts_reset watch_text.[lindex $watch_data($addr) 1]
+ }
+ }
+
+ ## Set flag enabled
+ # @parm Bool bool - New value
+ # @return void
+ public method right_panel_watches_set_enabled {bool} {
+ set enabled $bool
+ }
+}
+
+set ::RegWatches::menu_autoload [lindex $::CONFIG(REGWATCHES_CONFIG) 0]
+set ::RegWatches::sorting_order [lindex $::CONFIG(REGWATCHES_CONFIG) 1]
diff --git a/lib/rightpanel/rightpanel.tcl b/lib/rightpanel/rightpanel.tcl
new file mode 100755
index 0000000..061f1f5
--- /dev/null
+++ b/lib/rightpanel/rightpanel.tcl
@@ -0,0 +1,2273 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements Right Panel
+# Right Panel Notebook consist of:
+# - List of bookmarks
+# - List of breakpoints
+# - List of register watches
+# - Instruction details
+# - List of active subprograms
+# --------------------------------------------------------------------------
+
+# Import nesesary sources
+source "${::LIB_DIRNAME}/rightpanel/regwatches.tcl" ;# Register watches
+source "${::LIB_DIRNAME}/rightpanel/instructiondetails.tcl" ;# Instruction details
+source "${::LIB_DIRNAME}/rightpanel/subprograms.tcl" ;# List of active subprograms
+source "${::LIB_DIRNAME}/rightpanel/hwmanager.tcl" ;# Hardware tools manager
+
+class RightPanel {
+ inherit RegWatches InstructionDetails SubPrograms HwManager
+
+ ## COMMON
+ # Conter of instances
+ common count 0
+ # Background color for selected rows -- light
+ common selection_color {#EEFFDD}
+ # Background color for selected rows -- dark
+ common selection_color_dark {#DDDDFF}
+ # Default font size for text widgets
+ common fontSize ${Editor::fontSize}
+ # Default font family for text widgets
+ common fontFamily ${Editor::fontFamily}
+ # Font used in Editor
+ common editor_font [font create -size -$fontSize -family $fontFamily]
+ # Definition of popup menu for bookmark list
+ common BOOKMARKMENU {
+ {command {Remove} {$edit:bookmark} 0 "editor_procedure {} Bookmark {}"
+ {button_cancel} "Add/Remove editor bookmark to/from current line"}
+ {separator}
+ {command {Previous} {} 0 "rightPanel_bm_up" {1uparrow}
+ "Goto previous bookmark"}
+ {command {Next} {} 0 "rightPanel_bm_up" {1downarrow}
+ "Goto next bookmark"}
+ {separator}
+ {command {Remove all} {} 0 "editor_procedure {} clear_all_bookmarks {}"
+ {editdelete} "Remove all bookmarks from the editor"}
+ }
+ # Definition of popup menu for breakpoint list
+ common BREAKPOINTMENU {
+ {command {Remove} {$edit:breakpoint} 0 "editor_procedure {} Breakpoint {}"
+ {button_cancel} "Add/Remove editor breakpoint to/from current line"}
+ {separator}
+ {command {Previous} {} 0 "rightPanel_bp_up" {1uparrow}
+ "Goto previous breakpoint"}
+ {command {Next} {} 0 "rightPanel_bp_up" {1downarrow}
+ "Goto next breakpoint"}
+ {separator}
+ {command {Remove all} {} 0 "editor_procedure {} clear_all_breakpoints {}"
+ {editdelete} "Remove all breakpoints from the editor"}
+ }
+ # Definition of popup menu for symbols list
+ common SYMBOLSKMENU {}
+
+ ## PRIVATE
+ private variable notebook_frame ;# ID of panel main frame
+ private variable notebook ;# ID of panel NoteBook
+ private variable bookmarks ;# ID of tab "Bookmarks"
+ private variable breakpoints ;# ID of tab "Breakpoints"
+ private variable watches ;# ID of tab "Register watches"
+ private variable instruction ;# ID of tab "Instruction details"
+ private variable subprograms ;# ID of tab "Active subprograms"
+ private variable hwmanager ;# ID of tab "Hardware manager"
+ private variable table_of_symbols ;# ID of tab "Table of symbols"
+ private variable obj_idx ;# Number of this object
+
+ private variable bookmarks_menu ;# ID of popup menu for "Bookmarks"
+ private variable breakpoints_menu ;# ID of popup menu for "Breakpoints"
+ private variable symbols_menu ;# ID of popup menu for "Symbol list"
+
+ private variable bm_pagesManager ;# ID of pages manager for tab "Bookmarks"
+ private variable bp_pagesManager ;# ID of pages manager for tab "Breakpoints"
+ private variable sm_pagesManager ;# ID of pages manager for tab "Symbol list"
+
+ private variable bookmarks_lineNumbers ;# ID of text widget showing line numbers - tab "Bookmarks"
+ private variable breakpoints_lineNumbers ;# ID of text widget showing line numbers - tab "Breakpoints"
+ private variable bookmarks_text ;# ID of list of bookmarks (text widget) - tab "Bookmarks"
+ private variable breakpoints_text ;# ID of list of breakpoints (text widget) - tab "Breakpoints"
+ private variable bm_up_button ;# ID of button "Up" - tab "Bookmarks"
+ private variable bm_down_button ;# ID of button "Down" - tab "Bookmarks"
+ private variable bm_clear_button ;# ID of button "Clear all" - tab "Bookmarks"
+ private variable bp_up_button ;# ID of button "Up" - tab "Breakpoints"
+ private variable bp_down_button ;# ID of button "Down" - tab "Breakpoints"
+ private variable bp_clear_button ;# ID of button "Clear all" - tab "Breakpoints"
+ private variable sm_text ;# ID of symbol list text widget - tab "Symbols"
+ private variable sm_lineNumbers ;# ID of text widget showing line numbers - tab "Symbols"
+
+ private variable LIST_bookmarks_lineNumbers {} ;# List of $bookmarks_lineNumbers (for each editor)
+ private variable LIST_breakpoints_lineNumbers {} ;# List of $breakpoints_lineNumbers (for each editor)
+ private variable LIST_bookmarks_text {} ;# List of $bookmarks_text (for each editor)
+ private variable LIST_breakpoints_text {} ;# List of $breakpoints_text (for each editor)
+ private variable LIST_bm_up_button {} ;# List of $bm_up_button (for each editor)
+ private variable LIST_bm_down_button {} ;# List of $bm_down_button (for each editor)
+ private variable LIST_bm_clear_button {} ;# List of $bm_clear_button (for each editor)
+ private variable LIST_bp_up_button {} ;# List of $bp_up_button (for each editor)
+ private variable LIST_bp_down_button {} ;# List of $bp_down_button (for each editor)
+ private variable LIST_bp_clear_button {} ;# List of $bp_clear_button (for each editor)
+ private variable LIST_sm_text {} ;# List of $sm_text (for each editor)
+ private variable LIST_sm_lineNumbers {} ;# List of $sm_lineNumbers (for each editor)
+
+ private variable bm_bp_pages_list {} ;# List of editor numbers present in the panel
+ private variable editors_count 0 ;# Counter of added editors
+ private variable current_editor_idx 0 ;# Int: Index of currently active editor
+
+ private variable block_select 0 ;# Bool: Block selection of an item for certain procedures
+ private variable search_val_in_progress 0 ;# Bool: Search procedure is in progress
+
+ private variable button_bar ;# ID of button bar which replaces notebook on hide
+ private variable redraw_pane_in_progress 0 ;# (see procedure right_panel_redraw_pane)
+ private variable parentPane ;# ID of parent container (some frame)
+ private variable last_PanelSize ;# Last panel widgth
+ private variable PanelSize $::CONFIG(RIGHT_PANEL_SIZE) ;# Current panel width
+ private variable active_page $::CONFIG(RIGHT_PANEL_ACTIVE_PAGE) ;# ID of the active page
+ private variable PanelVisible $::CONFIG(RIGHT_PANEL) ;# Bool: is panel visible
+
+ private variable enabled 0 ;# Bool: enable procedures which are needless while loading project
+
+ ## Object constructor
+ constructor {} {
+ incr count
+ set obj_idx $count
+ }
+
+ ## Object destructor
+ destructor {
+ # Clean up GUI
+ destroy $notebook_frame
+
+ # Remove status bar tips for popup menus
+ menu_Sbar_remove $bookmarks_menu
+ menu_Sbar_remove $breakpoints_menu
+ }
+
+ ## Create right panel
+ # @parm Widget notebookframe - frame where to pack NoteBook
+ # @parm Widget ParentPane - parent paned window
+ # @parm String watches_file - definition file for register watches
+ # @return void
+ public method Initialize_rightPanel {notebookframe ParentPane watches_file} {
+
+ # Object variables
+ set parentPane $ParentPane ;# Parent container (some frame)
+ # Main frame of this panel
+ set notebook_frame $notebookframe
+
+ ## Create NoteBook
+ set notebook [NoteBook $notebook_frame.ntb_rightPanel \
+ -side top -bg {#EEEEEE} \
+ -arcradius 4 \
+ ]
+
+ # Register notebook status bar tips
+ notebook_Sbar_set {rightpanel} [list \
+ Bookmarks [mc "List of bookmarks in the current editor"] \
+ Breakpoints [mc "List of breakpoints in the current editor"] \
+ Instruction [mc "Details for instruction on the current line"] \
+ Watches [mc "Register watches (for internal data memory, external data memory, expanded data memory and bits)"] \
+ Subprograms [mc "List of active subprograms"] \
+ Symbols [mc "Symbol list"] \
+ Hardware [mc "Hardware manager"] \
+ Hide [mc "Hide the panel"] \
+ ]
+ $notebook bindtabs <Enter> "notebook_Sbar rightpanel"
+ $notebook bindtabs <Leave> "Sbar {} ;#"
+
+ #
+ # Create tabs
+ #
+
+ if {!${::Editor::editor_to_use}} {
+ # Tab "Bookmarks"
+ set bookmarks [$notebook insert end [mc "Bookmarks"] \
+ -image ::ICONS::16::bookmark_toolbar \
+ -raisecmd "$this rightPanel_set_active_page Bookmarks" \
+ -helptext [mc "List of bookmarks in editor (Ctrl+6)"] \
+ ]
+ # Tab "Breakpoints"
+ set breakpoints [$notebook insert end [mc "Breakpoints"] \
+ -image ::ICONS::16::flag \
+ -raisecmd "$this rightPanel_set_active_page Breakpoints" \
+ -helptext [mc "List of breakpoints in editor (Ctrl+7)"] \
+ ]
+ # Tab "Symbols"
+ set table_of_symbols [$notebook insert end [mc "Symbols"] \
+ -image ::ICONS::16::_blockdevice \
+ -raisecmd "$this rightPanel_set_active_page Symbols" \
+ -helptext [mc "Symbol List"] \
+ ]
+ # Tab "Instruction"
+ set instruction [$notebook insert end [mc "Instruction"] \
+ -image ::ICONS::16::info \
+ -raisecmd "$this rightPanel_set_active_page Instruction" \
+ -helptext [mc "Instruction details (Ctrl+8)"] \
+ -createcmd [list $this CreateInstructionDetailsGUI] \
+ ]
+ }
+ # Tab "Watches"
+ set watches [$notebook insert end [mc "Watches"] \
+ -image ::ICONS::16::player_playlist \
+ -raisecmd "$this rightPanel_set_active_page Watches" \
+ -helptext [mc "Register watches (Ctrl+9)"] \
+ -createcmd [list $this CreateRegWatchesGUI] \
+ ]
+ # Tab "Subprograms"
+ set subprograms [$notebook insert end [mc "Subprograms"] \
+ -image ::ICONS::16::queue \
+ -raisecmd "$this rightPanel_set_active_page Subprograms"\
+ -helptext [mc "Active subprograms (Ctrl+0)"] \
+ -createcmd [list $this CreateSubProgramsGUI] \
+ ]
+ # Tab "Hardware manager"
+ set hwmanager [$notebook insert end [mc "Hardware"] \
+ -image ::ICONS::16::kcmpci \
+ -raisecmd "$this rightPanel_set_active_page Hardware" \
+ -helptext [mc "Hardware manager"] \
+ -createcmd [list $this CreateHwManagerGUI] \
+ ]
+
+ # Tab "Hide"
+ $notebook insert end [mc "Hide"] \
+ -image ::ICONS::16::2rightarrow \
+ -raisecmd "$this right_panel_show_hide" \
+ -helptext [mc "Hide the panel"]
+
+ # Prepare panel componenets but do not create GUI elements
+ PrepareRegWatches $watches $watches_file
+ PrepareSubPrograms $subprograms
+ PrepareHwManager $hwmanager
+
+ if {!${::Editor::editor_to_use}} {
+ PrepareInstructionDetails $instruction
+ }
+
+
+ ## Create Button bar
+ # Button "Show"
+ set button_bar [frame $notebook_frame.button_bar]
+ pack [ttk::button $button_bar.but_show \
+ -image ::ICONS::16::2leftarrow \
+ -style ToolButton.TButton \
+ -command "$this right_panel_show_hide" \
+ ]
+ DynamicHelp::add $button_bar.but_show -text [mc "Show the panel"]
+ setStatusTip -widget $button_bar.but_show -text [mc "Show the panel"]
+ # Separator
+ pack [ttk::separator $button_bar.sep -orient horizontal] -fill x -pady 2
+ # Button "Hardware manager"
+ pack [ttk::button $button_bar.but_hwman \
+ -image ::ICONS::16::kcmpci \
+ -style ToolButton.TButton \
+ -command "$this rightPanel_show_up Hardware" \
+ ]
+ DynamicHelp::add $button_bar.but_hwman -text [mc "Hardware tools"]
+ setStatusTip -widget $button_bar.but_hwman \
+ -text [mc "Hardware tools manager"]
+ # Button "Active Subprograms"
+ pack [ttk::button $button_bar.but_subprog \
+ -image ::ICONS::16::queue \
+ -style ToolButton.TButton \
+ -command "$this rightPanel_show_up Subprograms" \
+ ]
+ DynamicHelp::add $button_bar.but_subprog -text [mc "Active subprograms (Ctrl+0)"]
+ setStatusTip -widget $button_bar.but_subprog \
+ -text [mc "List of active subprograms"]
+ # Button "Register watches"
+ pack [ttk::button $button_bar.but_reg_watch \
+ -image ::ICONS::16::player_playlist \
+ -style ToolButton.TButton \
+ -command "$this rightPanel_show_up Watches" \
+ ]
+ DynamicHelp::add $button_bar.but_reg_watch -text [mc "MCU register watches (Ctrl+9)"]
+ setStatusTip -widget $button_bar.but_reg_watch \
+ -text [mc "Register watches for internal data memory, external data memory and expanded data memory"]
+ if {!${::Editor::editor_to_use}} {
+ # Button "Instruction details"
+ pack [ttk::button $button_bar.but_ins_det \
+ -image ::ICONS::16::info \
+ -style ToolButton.TButton \
+ -command "$this rightPanel_show_up Instruction" \
+ -state [expr {${::Editor::editor_to_use} ? {disabled} : {!disabled}}] \
+ ]
+ DynamicHelp::add $button_bar.but_ins_det -text [mc "Instruction details (Ctrl+8)"]
+ setStatusTip -widget $button_bar.but_ins_det \
+ -text [mc "Details for instruction on the current line"]
+ # Button "Symbol List"
+ pack [ttk::button $button_bar.but_symbols \
+ -image ::ICONS::16::_blockdevice \
+ -style ToolButton.TButton \
+ -command "$this rightPanel_show_up Symbols" \
+ -state [expr {${::Editor::editor_to_use} ? {disabled} : {!disabled}}] \
+ ]
+ DynamicHelp::add $button_bar.but_symbols -text [mc "Symbol List"]
+ setStatusTip -widget $button_bar.but_symbols \
+ -text [mc "Symbol List"]
+ # Button "Breakpoints"
+ pack [ttk::button $button_bar.but_breakpoints \
+ -image ::ICONS::16::flag \
+ -style ToolButton.TButton \
+ -command "$this rightPanel_show_up Breakpoints" \
+ -state [expr {${::Editor::editor_to_use} ? {disabled} : {!disabled}}] \
+ ]
+ DynamicHelp::add $button_bar.but_breakpoints -text [mc "List of breakpoints in editor (Ctrl+7)"]
+ setStatusTip -widget $button_bar.but_breakpoints \
+ -text [mc "List of breakpoints in the current editor"]
+ # Button "Bookmarks"
+ pack [ttk::button $button_bar.but_bookmarks \
+ -image ::ICONS::16::bookmark_toolbar \
+ -style ToolButton.TButton \
+ -command "$this rightPanel_show_up Bookmarks" \
+ -state [expr {${::Editor::editor_to_use} ? {disabled} : {!disabled}}] \
+ ]
+ DynamicHelp::add $button_bar.but_bookmarks -text [mc "List of bookmarks in editor (Ctrl+6)"]
+ setStatusTip -widget $button_bar.but_bookmarks \
+ -text [mc "List of bookmarks in the current editor"]
+ }
+
+ if {!${::Editor::editor_to_use}} {
+ # Pack pages managers
+ set bm_pagesManager [PagesManager $bookmarks.pgm_rightPanel_bm -background {#eeeeee}]
+ pack $bm_pagesManager -expand 1 -fill both
+ $bm_pagesManager compute_size
+
+ set bp_pagesManager [PagesManager $breakpoints.pgm_rightPanel_pm -background {#eeeeee}]
+ pack $bp_pagesManager -expand 1 -fill both
+ $bp_pagesManager compute_size
+
+ set sm_pagesManager [PagesManager $table_of_symbols.sm_pagesManager -background {#eeeeee}]
+ pack $sm_pagesManager -expand 1 -fill both
+ $sm_pagesManager compute_size
+
+ # Create popup menus
+ set bookmarks_menu $notebook_frame.menu_rightPanel_bookmarks
+ set breakpoints_menu $notebook_frame.menu_rightPanel_breakpoints
+ set symbols_menu $notebook_frame.menu_rightPanel_symbols
+ menuFactory $BREAKPOINTMENU $breakpoints_menu 0 "$this " 0 {}
+ menuFactory $BOOKMARKMENU $bookmarks_menu 0 "$this " 0 {}
+ menuFactory $SYMBOLSKMENU $symbols_menu 0 "$this " 0 {}
+ }
+
+
+ #
+ # Post-initialization
+ #
+
+ bind $parentPane <ButtonRelease-1> "$this right_panel_set_size"
+
+ # Show panel GUI components
+ if {$PanelVisible} {
+ # Show NoteBook
+ $parentPane paneconfigure $notebook_frame -minsize 295
+ pack $notebook -expand 1 -fill both
+ $parentPane configure -sashwidth 2
+
+ if {[catch {
+ $notebook raise $active_page
+ if {
+ ${::Editor::editor_to_use} &&
+ ([lsearch {Bookmarks Breakpoints Instruction Symbols} $active_page] != -1)
+ } {
+ set active_page {Watches}
+ $notebook raise {Watches}
+ }
+ }]} {
+ set active_page {Watches}
+ $notebook raise {Watches}
+ }
+ } {
+ # Show button bar
+ $parentPane paneconfigure $notebook_frame -minsize 0
+ pack $button_bar -anchor nw
+ $parentPane configure -sashwidth 0
+ bind $parentPane <Button> {break}
+ set last_PanelSize $PanelSize
+ set PanelSize 60
+ }
+ }
+
+ ## Synchronously scroll list of bookmarks and its line numbers
+ # @parm Char - what (m == Bookmarks; p == Breakpoints; s == Symbols)
+ # @parm String - string "moveto"
+ # @parm Float - number between 0.0 and 1.0 (0.0 == 'start', 1.0 == 'end')
+ # @return void
+ public method rightPanel_scroll args {
+ # Local variables
+ set what [lindex $args 0]
+ set cmd [lindex $args 1] ;# Scroll command (moveto, scroll and such)
+ set frac [lindex $args 2] ;# Fraction where to move
+ set units [lindex $args 3] ;# Units (optonal)
+
+ switch -- $what {
+ {m} { ;# Bookmarks
+ set lnb $bookmarks_lineNumbers
+ set txt $bookmarks_text
+ }
+ {p} { ;# Breakpoints
+ set lnb $breakpoints_lineNumbers
+ set txt $breakpoints_text
+ }
+ {s} { ;# Symbols
+ set lnb $sm_lineNumbers
+ set txt $sm_text
+ }
+ }
+
+ if {$units == {}} {
+ $lnb yview $cmd $frac
+ $txt yview $cmd $frac
+ } {
+ $lnb yview $cmd $frac $units
+ $txt yview $cmd $frac $units
+ }
+ }
+
+ ## Set position for scrollbar and line numbers in bookmark list
+ # @parm Char what - (m == Bookmarks; p == Breakpoints; s == Symbols)
+ # @parm Widget scrollbar - ID of scrollbar widget to adjust
+ # @parm Float fraction0 - y position
+ # @parm Float fraction1 - x position
+ # @return Bool - result
+ public method rightPanel_scrollSet {what scrollbar fraction0 fraction1} {
+ switch -- $what {
+ {m} { ;# Bookmarks
+ set txt $bookmarks_text
+ }
+ {p} { ;# Breakpoints
+ set txt $breakpoints_text
+ }
+ {s} { ;# Symbols
+ set txt $sm_text
+ }
+ }
+
+ if {![winfo exists $txt]} {
+ return 0
+ }
+
+ catch {
+ if {$fraction0 == {0.0} && $fraction1 == {1.0}} {
+ if {[winfo ismapped $scrollbar]} {
+ pack forget $scrollbar
+ }
+ } {
+ if {![winfo ismapped $scrollbar]} {
+ pack $scrollbar -side right -fill y -after $txt
+ }
+ }
+ }
+
+
+ $scrollbar set $fraction0 $fraction1
+ rightPanel_scroll $what moveto $fraction0
+
+ return 1
+ }
+
+ ## Refresh font settings for all text widgets in the panel
+ # @parm Bool for_all - 0 == only for the current editor; 1 == for all editors
+ # @return void
+ public method rightPanel_refresh_font_settings {for_all} {
+ if {${::Editor::editor_to_use}} {return}
+ if {$for_all} {
+ foreach widget $LIST_bookmarks_lineNumbers {
+ $widget configure -font ${Editor::defaultFont_bold}
+ }
+
+ foreach widget $LIST_breakpoints_lineNumbers {
+ $widget configure -font ${Editor::defaultFont_bold}
+ }
+
+ set i 0
+ foreach widget $LIST_bookmarks_text {
+ $widget configure -font ${Editor::defaultFont_bold}
+ ASMsyntaxHighlight::create_tags $widget ${Editor::fontSize} ${Editor::fontFamily}
+ set language [$this editor_procedure $i get_language {}]
+ if {$language == 1} {
+ CsyntaxHighlight::create_tags \
+ $widget ${Editor::fontSize} ${Editor::fontFamily}
+ } elseif {$language == 2} {
+ LSTsyntaxHighlight::create_tags \
+ $widget ${Editor::fontSize} ${Editor::fontFamily}
+ }
+ incr i
+ }
+
+ set i 0
+ foreach widget $LIST_breakpoints_text {
+ $widget configure -font ${Editor::defaultFont_bold}
+ ASMsyntaxHighlight::create_tags $widget ${Editor::fontSize} ${Editor::fontFamily}
+ set language [$this editor_procedure $i get_language {}]
+ if {$language == 1} {
+ CsyntaxHighlight::create_tags \
+ $widget ${Editor::fontSize} ${Editor::fontFamily}
+ } elseif {$language == 2} {
+ LSTsyntaxHighlight::create_tags \
+ $widget ${Editor::fontSize} ${Editor::fontFamily}
+ }
+ incr i
+ }
+ } {
+ $bookmarks_lineNumbers configure -font ${Editor::defaultFont_bold}
+ $bookmarks_text configure -font ${Editor::defaultFont_bold}
+ $breakpoints_lineNumbers configure -font ${Editor::defaultFont_bold}
+ $breakpoints_text configure -font ${Editor::defaultFont_bold}
+ $sm_lineNumbers configure -font ${Editor::defaultFont_bold}
+ $sm_text configure -font ${Editor::defaultFont_bold}
+
+ ASMsyntaxHighlight::create_tags $bookmarks_text ${Editor::fontSize} ${Editor::fontFamily}
+ ASMsyntaxHighlight::create_tags $breakpoints_text ${Editor::fontSize} ${Editor::fontFamily}
+ set language [$this editor_procedure {end} get_language {}]
+ if {$language == 1} {
+ CsyntaxHighlight::create_tags \
+ $bookmarks_text ${Editor::fontSize} ${Editor::fontFamily}
+ CsyntaxHighlight::create_tags \
+ $breakpoints_text ${Editor::fontSize} ${Editor::fontFamily}
+ } elseif {$language == 2} {
+ CsyntaxHighlight::create_tags \
+ $bookmarks_text ${Editor::fontSize} ${Editor::fontFamily}
+ CsyntaxHighlight::create_tags \
+ $breakpoints_text ${Editor::fontSize} ${Editor::fontFamily}
+ }
+
+ create_tags_in_symbol_list
+ }
+ }
+
+ ## Create highlight tag for list of bookmarks and breakpoints for the current editor
+ # @return void
+ public method rightPanel_add_Editor__create_menu_and_tags {} {
+ if {${::Editor::editor_to_use}} {return}
+ ASMsyntaxHighlight::create_tags $breakpoints_text $fontSize $fontFamily
+ ASMsyntaxHighlight::create_tags $bookmarks_text $fontSize $fontFamily
+ set language [$this editor_procedure {end} get_language {}]
+ if {$language == 1} {
+ rightPanel_bm_bp_create_c_hg_tags
+ } elseif {$language == 2} {
+ rightPanel_bm_bp_create_lst_hg_tags
+ }
+
+ create_tags_in_symbol_list
+ }
+
+ ## Create highlighting tags in the text widget in the "List of Symbols"
+ # @return void
+ private method create_tags_in_symbol_list {} {
+ set tags_to_define [list tag_label tag_constant tag_normal tag_macro]
+ foreach tag_def [concat ${::ASMsyntaxHighlight::hightlight_tags} ${::CsyntaxHighlight::hightlight_tags}] {
+ if {[lsearch -ascii -exact $tags_to_define [lindex $tag_def 0]] == -1} {
+ continue
+ }
+
+ # Create array of tag attributes
+ for {set i 0} {$i < 5} {incr i} {
+ set tag_def_item($i) [lindex $tag_def $i]
+ }
+
+ # Foreground color
+ if {$tag_def_item(1) == {}} {
+ set tag_def_item(1) black
+ }
+ # Fonr slant
+ if {$tag_def_item(3) == 1} {
+ set tag_def_item(3) italic
+ } {
+ set tag_def_item(3) roman
+ }
+ # Font weight
+ if {$tag_def_item(4) == 1} {
+ set tag_def_item(4) bold
+ } {
+ set tag_def_item(4) normal
+ }
+
+ # Create the tag in the target text widget
+ $sm_text tag configure $tag_def_item(0) \
+ -foreground $tag_def_item(1) \
+ -font [font create \
+ -overstrike $tag_def_item(2) \
+ -slant $tag_def_item(3) \
+ -weight $tag_def_item(4) \
+ -size -$::Editor::fontSize \
+ -family $::Editor::fontFamily \
+ ]
+ }
+
+ # Create tag for C function
+ $sm_text tag configure tag_c_func \
+ -foreground {#0000DD} \
+ -font ${::Editor::defaultFont}
+ }
+
+ ## Create highlighting tags for Codelisting for the current editor
+ # @return void
+ public method rightPanel_bm_bp_create_lst_hg_tags {} {
+ LSTsyntaxHighlight::create_tags $breakpoints_text $fontSize $fontFamily
+ LSTsyntaxHighlight::create_tags $bookmarks_text $fontSize $fontFamily
+ }
+ ## Create highlighting tags for C language for the current editor
+ # @return void
+ public method rightPanel_bm_bp_create_c_hg_tags {} {
+ CsyntaxHighlight::create_tags $breakpoints_text $fontSize $fontFamily
+ CsyntaxHighlight::create_tags $bookmarks_text $fontSize $fontFamily
+ }
+
+ ## Add new list of bookmarks and list of breakpoints for new editor
+ # @parm Bool create_menu_and_tags - Create popup menus and highlighting tags
+ # @return void
+ public method rightPanel_add_Editor {create_menu_and_tags} {
+ if {${::Editor::editor_to_use}} {return}
+
+ # Local variables
+ set bm_page [$bm_pagesManager add $editors_count] ;# ID of current bookmarks page
+ set bp_page [$bp_pagesManager add $editors_count] ;# ID of current breakpoints page
+ set sm_page [$sm_pagesManager add $editors_count] ;# ID of current page in symbol list
+
+ # Register new editor
+ set current_editor_idx $editors_count
+ lappend bm_bp_pages_list $editors_count
+ incr editors_count ;# increment counter of editors
+
+
+ #
+ # Create tab "Bookmarks"
+ #
+
+ ## Create icon bar (up, down, bookmark, clear all)
+ # Create button frame
+ set button_frame [frame $bm_page.frm_rightPanel_bm_button_frame]
+ pack $button_frame -side top -fill x
+ # Button "Up"
+ set bm_up_button [ttk::button $button_frame.but_rightPanel_bm_up \
+ -image ::ICONS::16::1uparrow \
+ -state disabled \
+ -command "$this rightPanel_bm_up" \
+ -style ToolButton.TButton \
+ ]
+ pack $bm_up_button -side left
+ DynamicHelp::add $bm_up_button -text [mc "Move to previous bookmark"]
+ setStatusTip -widget $bm_up_button \
+ -text [mc "Goto to line of previous bookmark"]
+ # Button "Down"
+ set bm_down_button [ttk::button $button_frame.but_rightPanel_bm_down \
+ -image ::ICONS::16::1downarrow \
+ -state disabled \
+ -command "$this rightPanel_bm_down" \
+ -style ToolButton.TButton \
+ ]
+ pack $bm_down_button -side left
+ DynamicHelp::add $bm_down_button -text [mc "Move to the next bookmark"]
+ setStatusTip -widget $bm_down_button \
+ -text [mc "Goto to line of next bookmark"]
+ # Separator
+ pack [ttk::separator $button_frame.but_rightPanel_bm_sep \
+ -orient vertical \
+ ] -side left -fill y -padx 2
+ # Button "Bookmark"
+ set button [ttk::button $button_frame.but_rightPanel_bm_bookmark \
+ -image ::ICONS::16::bookmark_add \
+ -command "$this editor_procedure {} Bookmark {}" \
+ -style ToolButton.TButton \
+ ]
+ pack $button -side left
+ DynamicHelp::add $button -text [mc "Add/Remove bookmark on the current line"]
+ setStatusTip -widget $button \
+ -text [mc "Add/Remove bookmark on the current line in editor"]
+ # Button "Clear all"
+ set bm_clear_button [ttk::button $button_frame.but_rightPanel_bm_clear \
+ -image ::ICONS::16::editdelete \
+ -state disabled \
+ -command "$this editor_procedure {} clear_all_bookmarks {}" \
+ -style ToolButton.TButton \
+ ]
+ pack $bm_clear_button -side right
+ DynamicHelp::add $bm_clear_button -text [mc "Clear all bookmarks"]
+ setStatusTip -widget $bm_clear_button \
+ -text [mc "Clear all bookmarks from editor"]
+
+ # Create text frame (Contains: text widget, scrollbar, LineNumbers)
+ set text_frame [frame $bm_page.frm_rightPanel_bm_text_frame -bd 1 -relief sunken]
+ pack $text_frame -fill both -expand 1 -side bottom
+
+ # Create scrollbar
+ set scrollbar [ttk::scrollbar \
+ $text_frame.scr_rightPanel_bookmars \
+ -orient vertical \
+ -command "$this rightPanel_scroll m" \
+ ]
+ # Create line numbers
+ set bookmarks_lineNumbers [text $text_frame.txt_rightPanel_bm_lineNumbers \
+ -yscrollcommand "$this rightPanel_scrollSet m $scrollbar" \
+ -cursor left_ptr \
+ -width 1 -height 1 \
+ -bg gray \
+ -fg white \
+ -relief flat \
+ -bd 1 \
+ -state disabled \
+ -exportselection 0 \
+ -takefocus 0 \
+ -font ${Editor::defaultFont_bold} \
+ ]
+ $bookmarks_lineNumbers tag configure right -justify right
+ # Create list of bookmarks
+ set bookmarks_text [text $text_frame.txt_rightPanel_bookmars \
+ -cursor left_ptr -state disabled -width 1 -height 1 \
+ -wrap none -exportselection 0 -bd 1 -relief flat \
+ -yscrollcommand "$this rightPanel_scrollSet m $scrollbar" \
+ -font ${Editor::defaultFont_bold} \
+ ]
+ $bookmarks_text tag configure curLine \
+ -borderwidth 1 \
+ -relief raised \
+ -background ${::RightPanel::selection_color}
+
+ # Set bindings
+ bind $bookmarks_text <<Selection>> "false_selection $bookmarks_text; break"
+ bind $bookmarks_text <Button-1> "$this rightPanel_xx_txt_click m %x %y; break"
+ bind $bookmarks_text <ButtonRelease-3> "$this rightPanel_bm_popupmenu %X %Y %x %y; break; break"
+ bind $bookmarks_lineNumbers <ButtonRelease-3> "$this rightPanel_bm_popupmenu %X %Y %x %y; break; break"
+ bind $bookmarks_text <Key-Menu> {break}
+ bind $bookmarks_lineNumbers <<Selection>> "false_selection $bookmarks_lineNumbers; break"
+
+ # Pack components of "Text frame"
+ pack $bookmarks_lineNumbers -side left -fill y
+ pack $bookmarks_text -side left -expand 1 -fill both
+
+
+ #
+ # Breakpoints tab
+ #
+
+ ## Create icon bar (up, down, breakpoint, clear all)
+ # Create button frame
+ set button_frame [frame $bp_page.frm_rightPanel_bp_button_frame]
+ pack $button_frame -side top -fill x
+ # Button "Up"
+ set bp_up_button [ttk::button $button_frame.but_rightPanel_bp_up \
+ -image ::ICONS::16::1uparrow \
+ -state disabled \
+ -command "$this rightPanel_bp_up" \
+ -style ToolButton.TButton \
+ ]
+ pack $bp_up_button -side left
+ DynamicHelp::add $bp_up_button -text [mc "Move to previous breakpoint"]
+ setStatusTip -widget $bp_up_button \
+ -text [mc "Goto to line of previous breakpoint"]
+ # Button "Down"
+ set bp_down_button [ttk::button $button_frame.but_rightPanel_bp_down \
+ -image ::ICONS::16::1downarrow \
+ -state disabled \
+ -command "$this rightPanel_bp_down" \
+ -style ToolButton.TButton \
+ ]
+ pack $bp_down_button -side left
+ DynamicHelp::add $bp_down_button -text [mc "Move to next breakpoint"]
+ setStatusTip -widget $bp_down_button \
+ -text [mc "Goto to line of next breakpoint"]
+ # Separator
+ pack [ttk::separator $button_frame.but_rightPanel_bp_sep \
+ -orient vertical \
+ ] -side left -fill y -padx 2
+ # Button "Breakpoint"
+ set button [ttk::button $button_frame.but_rightPanel_bp_breakpoint \
+ -image ::ICONS::16::flag \
+ -command "$this editor_procedure {} Breakpoint {}" \
+ -style ToolButton.TButton \
+ ]
+ pack $button -side left
+ DynamicHelp::add $button -text [mc "Add/Remove breakpoint on the current line"]
+ setStatusTip -widget $button \
+ -text [mc "Add/Remove breakpoint on the current line in editor"]
+ # Buttton "Clear all"
+ set bp_clear_button [ttk::button $button_frame.but_rightPanel_bp_clear \
+ -image ::ICONS::16::editdelete \
+ -state disabled \
+ -command "$this editor_procedure {} clear_all_breakpoints {}" \
+ -style ToolButton.TButton \
+ ]
+ pack $bp_clear_button -side right
+ DynamicHelp::add $bp_clear_button -text [mc "Clear all breakpoints"]
+ setStatusTip -widget $bp_clear_button \
+ -text [mc "Clear all breakpoints from editor"]
+
+ # Create text frame (Contains: text widget, scrollbar, LineNumbers)
+ set text_frame [frame $bp_page.frm_rightPanel_bp_text_frame -bd 1 -relief sunken]
+ pack $text_frame -fill both -expand 1 -side bottom
+
+ # Create scrollbar
+ set scrollbar [ttk::scrollbar \
+ $text_frame.scr_rightPanel_breakpoints \
+ -orient vertical \
+ -command "$this rightPanel_scroll p" \
+ ]
+ # Create line numbers
+ set breakpoints_lineNumbers [text $text_frame.txt_rightPanel_bp_lineNumbers \
+ -yscrollcommand "$this rightPanel_scrollSet p $scrollbar" \
+ -cursor left_ptr \
+ -width 1 -height 1 \
+ -exportselection 0 \
+ -bg gray \
+ -fg white \
+ -relief flat \
+ -bd 1 \
+ -state disabled \
+ -takefocus 0 \
+ -font ${Editor::defaultFont_bold} \
+ ]
+ $breakpoints_lineNumbers tag configure right -justify right
+ # Create list of breakpoints
+ set breakpoints_text [text $text_frame.txt_rightPanel_breakpoints \
+ -cursor left_ptr -state disabled \
+ -wrap none -exportselection 0 -bd 1 -relief flat \
+ -font ${Editor::defaultFont_bold} -width 1 -height 1 \
+ -yscrollcommand "$this rightPanel_scrollSet p $scrollbar" \
+ ]
+ $breakpoints_text tag configure curLine \
+ -borderwidth 1 \
+ -relief raised \
+ -background ${::RightPanel::selection_color}
+
+ # Pack widgets of the text frame
+ pack $breakpoints_lineNumbers -side left -fill y
+ pack $breakpoints_text -side left -expand 1 -fill both
+
+ # Set bindings
+ bind $breakpoints_text <<Selection>> "false_selection $breakpoints_text; break"
+ bind $breakpoints_text <Button-1> "$this rightPanel_xx_txt_click p %x %y; break"
+ bind $breakpoints_text <ButtonRelease-3> "$this rightPanel_bp_popupmenu %X %Y %x %y; break; break"
+ bind $breakpoints_lineNumbers <ButtonRelease-3> "$this rightPanel_bp_popupmenu %X %Y %x %y; break; break"
+ bind $breakpoints_text <Key-Menu> {break}
+ bind $breakpoints_lineNumbers <<Selection>> "false_selection $breakpoints_lineNumbers; break"
+
+
+ #
+ # Symbol list
+ #
+
+ ## Create icon bar (up, down, breakpoint, clear all)
+ # Create button frame
+ set button_frame [frame $sm_page.button_frame]
+ pack $button_frame -side top -fill x
+ # Button "Refresh"
+ set refresh_but [ttk::button $button_frame.refresh_but \
+ -image ::ICONS::16::reload \
+ -command "$this rightPanel_refresh_symbols" \
+ -style ToolButton.TButton \
+ ]
+ pack $refresh_but -side left
+ DynamicHelp::add $refresh_but -text [mc "Reevaluate"]
+ setStatusTip -widget $refresh_but \
+ -text [mc "Reevaluate ..."]
+
+ # Button "Clear search string"
+ set sm_search_clear [ttk::button $button_frame.clear_search \
+ -image ::ICONS::16::clear_left \
+ -style Flat.TButton \
+ -command "$button_frame.search_entry delete 0 end" \
+ -state disabled \
+ ]
+ DynamicHelp::add $button_frame.clear_search -text [mc "Clear search string"]
+ pack $sm_search_clear -side right
+ setStatusTip -widget $sm_search_clear \
+ -text [mc "Clear search string"]
+ # Entry "Search"
+ set sm_search_entry [ttk::entry $button_frame.search_entry \
+ -validate key \
+ -width 0 \
+ -validatecommand "$this rightPanel_sm_search_validate %P %W $sm_search_clear" \
+ ]
+ DynamicHelp::add $sm_search_entry -text [mc "Search for a constant, variable, function or macro"]
+ pack $sm_search_entry -side right -fill x -expand 1
+ setStatusTip -widget $sm_search_entry \
+ -text [mc "Search for a constant, variable, function or macro"]
+ # Label "Search:"
+ pack [label $button_frame.search_lbl -text [mc " Search:"]] -side right
+
+ # Create text frame (Contains: text widget, scrollbar, LineNumbers)
+ set text_frame [frame $sm_page.text_frame -bd 1 -relief sunken]
+ pack $text_frame -fill both -expand 1 -side bottom
+
+ # Create scrollbar
+ set scrollbar [ttk::scrollbar $text_frame.scr \
+ -orient vertical \
+ -command "$this rightPanel_scroll s" \
+ ]
+ set sm_lineNumbers [text $text_frame.ln \
+ -yscrollcommand "$this rightPanel_scrollSet s $scrollbar" \
+ -cursor left_ptr -width 1 \
+ -exportselection 0 -bg gray \
+ -height 1 -fg white \
+ -relief flat -bd 1 \
+ -state disabled -takefocus 0 \
+ -font ${Editor::defaultFont_bold} \
+ ]
+ $sm_lineNumbers tag configure right -justify right
+ set sm_text [text $text_frame.txt \
+ -cursor left_ptr -state disabled \
+ -wrap none -exportselection 0 -bd 1 -relief flat \
+ -font ${Editor::defaultFont_bold} -width 1 -height 1 \
+ -yscrollcommand "$this rightPanel_scrollSet s $scrollbar" \
+ ]
+ $sm_text tag configure curLine \
+ -borderwidth 1 \
+ -relief raised \
+ -background ${::RightPanel::selection_color}
+
+ # Pack widgets of the text frame
+ pack $scrollbar -side right -fill y
+ pack $sm_lineNumbers -side left -fill y
+ pack $sm_text -side left -expand 1 -fill both
+
+ # Set bindings
+ bind $sm_text <<Selection>> "false_selection $sm_text; break"
+ bind $sm_text <Button-1> "$this rightPanel_xx_txt_click s %x %y; break"
+ bind $sm_text <Key-Menu> {break}
+ bind $sm_text <ButtonRelease-3> {break}
+ bind $sm_lineNumbers <<Selection>> "false_selection $sm_lineNumbers; break"
+ bind $sm_lineNumbers <Key-Menu> {break}
+ bind $sm_lineNumbers <ButtonRelease-3> {break}
+
+ ## FINISH
+
+ # Append create d widgets to lists
+ lappend LIST_bookmarks_lineNumbers $bookmarks_lineNumbers
+ lappend LIST_breakpoints_lineNumbers $breakpoints_lineNumbers
+ lappend LIST_bookmarks_text $bookmarks_text
+ lappend LIST_breakpoints_text $breakpoints_text
+ lappend LIST_bm_up_button $bm_up_button
+ lappend LIST_bm_down_button $bm_down_button
+ lappend LIST_bm_clear_button $bm_clear_button
+ lappend LIST_bp_up_button $bp_up_button
+ lappend LIST_bp_down_button $bp_down_button
+ lappend LIST_bp_clear_button $bp_clear_button
+ lappend LIST_sm_text $sm_text
+ lappend LIST_sm_lineNumbers $sm_lineNumbers
+
+ if {$create_menu_and_tags} {
+ rightPanel_add_Editor__create_menu_and_tags
+ }
+ }
+
+ ## Enable/Disable buttons on Bookmarks+Breakpoints icon bar
+ # @return void
+ private method bm_bp_disEna_buttons {} {
+
+ # Bookmarks
+ set end [$bookmarks_text index end]
+ switch -- $end {
+ {2.0} { ;# Empty list
+ $bm_up_button configure -state disabled
+ $bm_down_button configure -state disabled
+ $bm_clear_button configure -state disabled
+ }
+ {3.0} { ;# One item
+ $bm_up_button configure -state disabled
+ $bm_down_button configure -state disabled
+ $bm_clear_button configure -state normal
+ }
+ default { ;# More items
+ $bm_up_button configure -state normal
+ $bm_down_button configure -state normal
+ $bm_clear_button configure -state normal
+ }
+ }
+
+ # Breakpoints
+ set end [$breakpoints_text index end]
+ switch -- $end {
+ {2.0} { ;# Empty list
+ $bp_up_button configure -state disabled
+ $bp_down_button configure -state disabled
+ $bp_clear_button configure -state disabled
+ }
+ {3.0} { ;# One item
+ $bp_up_button configure -state disabled
+ $bp_down_button configure -state disabled
+ $bp_clear_button configure -state normal
+ }
+ default { ;# More items
+ $bp_up_button configure -state normal
+ $bp_down_button configure -state normal
+ $bp_clear_button configure -state normal
+ }
+ }
+ }
+
+ ## Recreate popup menus
+ # @return void
+ public method rightPanel_makePopupMenu {} {
+ regwatches_makePopupMenu
+
+ if {[winfo exists $breakpoints_menu]} {destroy $breakpoints_menu}
+ if {[winfo exists $bookmarks_menu]} {destroy $bookmarks_menu}
+ menuFactory $BREAKPOINTMENU $breakpoints_menu 0 "$this " 0 {}
+ menuFactory $BOOKMARKMENU $bookmarks_menu 0 "$this " 0 {}
+ }
+
+ ## Invoke bookmarks popup menu
+ # @parm Int X - Absolute X coordinate
+ # @parm Int Y - Absolute Y coordinate
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method rightPanel_bm_popupmenu {X Y x y} {
+
+ # Change position in the list
+ rightPanel_xx_txt_click m $x $y
+
+ # Enable/Disable menu items
+ set end [$bookmarks_text index end]
+ switch -- $end {
+ {2.0} { ;# Empty list
+ $bookmarks_menu entryconfigure [::mc "Remove"] -state disabled
+ $bookmarks_menu entryconfigure [::mc "Next"] -state disabled
+ $bookmarks_menu entryconfigure [::mc "Previous"] -state disabled
+ $bookmarks_menu entryconfigure [::mc "Remove all"] -state disabled
+ }
+ {3.0} { ;# One item
+ $bookmarks_menu entryconfigure [::mc "Remove"] -state normal
+ $bookmarks_menu entryconfigure [::mc "Next"] -state disabled
+ $bookmarks_menu entryconfigure [::mc "Previous"] -state disabled
+ $bookmarks_menu entryconfigure [::mc "Remove all"] -state normal
+ }
+ default { ;# More items
+ $bookmarks_menu entryconfigure [::mc "Remove"] -state normal
+ $bookmarks_menu entryconfigure [::mc "Next"] -state normal
+ $bookmarks_menu entryconfigure [::mc "Previous"] -state normal
+ $bookmarks_menu entryconfigure [::mc "Remove all"] -state normal
+ }
+ }
+
+ # Invoke the menu
+ tk_popup $bookmarks_menu $X $Y
+ }
+
+ ## Invoke breakpoints popup menu
+ # @parm Int X - Absolute X coordinate
+ # @parm Int Y - Absolute Y coordinate
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method rightPanel_bp_popupmenu {X Y x y} {
+
+ # Change position in the list
+ rightPanel_xx_txt_click p $x $y
+
+ # Enable/Disable menu items
+ set end [$breakpoints_text index end]
+ switch -- $end {
+ {2.0} { ;# Empty list
+ $breakpoints_menu entryconfigure [::mc "Remove"] -state disabled
+ $breakpoints_menu entryconfigure [::mc "Next"] -state disabled
+ $breakpoints_menu entryconfigure [::mc "Previous"] -state disabled
+ $breakpoints_menu entryconfigure [::mc "Remove all"] -state disabled
+ }
+ {3.0} { ;# One item
+ $breakpoints_menu entryconfigure [::mc "Remove"] -state normal
+ $breakpoints_menu entryconfigure [::mc "Next"] -state disabled
+ $breakpoints_menu entryconfigure [::mc "Previous"] -state disabled
+ $breakpoints_menu entryconfigure [::mc "Remove all"] -state normal
+ } default { ;# More items
+ $breakpoints_menu entryconfigure [::mc "Remove"] -state normal
+ $breakpoints_menu entryconfigure [::mc "Next"] -state normal
+ $breakpoints_menu entryconfigure [::mc "Previous"] -state normal
+ $breakpoints_menu entryconfigure [::mc "Remove all"] -state normal
+ }
+ }
+
+ # Invoke the menu
+ tk_popup $breakpoints_menu $X $Y
+ }
+
+ ## Remove editor from the list
+ # @parm Int idx - editor index
+ # @return void
+ public method rightPanel_remove_Editor {idx} {
+ if {${::Editor::editor_to_use}} {return}
+
+ # Remove pages from pages managers
+ $bm_pagesManager delete [lindex $bm_bp_pages_list $idx]
+ $bp_pagesManager delete [lindex $bm_bp_pages_list $idx]
+ $sm_pagesManager delete [lindex $bm_bp_pages_list $idx]
+ set bm_bp_pages_list [lreplace $bm_bp_pages_list $idx $idx]
+
+ # Remove widget references from its lists
+ set LIST_bookmarks_lineNumbers [lreplace $LIST_bookmarks_lineNumbers $idx $idx]
+ set LIST_breakpoints_lineNumbers [lreplace $LIST_breakpoints_lineNumbers $idx $idx]
+ set LIST_bookmarks_text [lreplace $LIST_bookmarks_text $idx $idx]
+ set LIST_breakpoints_text [lreplace $LIST_breakpoints_text $idx $idx]
+ set LIST_bm_up_button [lreplace $LIST_bm_up_button $idx $idx]
+ set LIST_bm_down_button [lreplace $LIST_bm_down_button $idx $idx]
+ set LIST_bm_clear_button [lreplace $LIST_bm_clear_button $idx $idx]
+ set LIST_bp_up_button [lreplace $LIST_bp_up_button $idx $idx]
+ set LIST_bp_down_button [lreplace $LIST_bp_down_button $idx $idx]
+ set LIST_bp_clear_button [lreplace $LIST_bp_clear_button $idx $idx]
+ set LIST_sm_text [lreplace $LIST_sm_text $idx $idx]
+ set LIST_sm_lineNumbers [lreplace $LIST_sm_lineNumbers $idx $idx]
+ }
+
+ ## Change the current editor
+ # @parm Int idx - editor index
+ # @return void
+ public method rightPanel_switch_editor {idx} {
+ if {${::Editor::editor_to_use}} {return}
+
+ set current_editor_idx $idx
+ rightPanel_switch_page $idx
+ rightPanel_switch_editor_vars $idx
+ }
+
+ ## Change the current page in pages managers
+ # @parm Int idx - editor index
+ # @return void
+ public method rightPanel_switch_page {idx} {
+ if {${::Editor::editor_to_use}} {return}
+
+ set current_editor_idx $idx
+ $bm_pagesManager raise [lindex $bm_bp_pages_list $idx]
+ $bp_pagesManager raise [lindex $bm_bp_pages_list $idx]
+ $sm_pagesManager raise [lindex $bm_bp_pages_list $idx]
+
+ if {$active_page == {Symbols}} {
+ catch {$this editor_procedure {} comp_win_highlight_all_in_background {}}
+ }
+ }
+
+ ## Change current editor but don not affect GUI
+ # @parm Int idx - editor index
+ # @return void
+ public method rightPanel_switch_editor_vars {idx} {
+ if {${::Editor::editor_to_use}} {return}
+
+ # Set active widgets
+ set current_editor_idx $idx
+ set bookmarks_lineNumbers [lindex $LIST_bookmarks_lineNumbers $idx]
+ set breakpoints_lineNumbers [lindex $LIST_breakpoints_lineNumbers $idx]
+ set bookmarks_text [lindex $LIST_bookmarks_text $idx]
+ set breakpoints_text [lindex $LIST_breakpoints_text $idx]
+ set bm_up_button [lindex $LIST_bm_up_button $idx]
+ set bm_down_button [lindex $LIST_bm_down_button $idx]
+ set bm_clear_button [lindex $LIST_bm_clear_button $idx]
+ set bp_up_button [lindex $LIST_bp_up_button $idx]
+ set bp_down_button [lindex $LIST_bp_down_button $idx]
+ set bp_clear_button [lindex $LIST_bp_clear_button $idx]
+ set sm_text [lindex $LIST_sm_text $idx]
+ set sm_lineNumbers [lindex $LIST_sm_lineNumbers $idx]
+ }
+
+
+ ## Binding for event <Button-1> for list of ...
+ # Change selection in the widget and change current line in the editor
+ # @parm Char - what (m == Bookmarks; p == Breakpoints; s == Symbols)
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative Y coordinate
+ # @return Bool - result
+ public method rightPanel_xx_txt_click {what x y} {
+ if {$block_select} {return}
+
+ switch -- $what {
+ {m} { ;# Bookmarks
+ set lnb $bookmarks_lineNumbers
+ set txt $bookmarks_text
+ }
+ {p} { ;# Breakpoints
+ set lnb $breakpoints_lineNumbers
+ set txt $breakpoints_text
+ }
+ {s} { ;# Symbols
+ set lnb $sm_lineNumbers
+ set txt $sm_text
+ }
+ }
+
+ # Determinate line number
+ set lineNum [rightPanel_txt_click $txt $lnb $x $y]
+ if {$lineNum == {}} {return 0}
+
+ # Change current line in the editor
+ set block_select 1
+ $this editor_procedure {} goto $lineNum
+ update idle
+ set block_select 0
+
+ return 1
+ }
+
+ ## Determinate line number and select the line
+ # @parm Widget txt_widget - ID of the text widget
+ # @parm Widget ln_widget - ID of line numbers widget
+ # @parm Int x - relative X coordinate
+ # @parm Int y - relative X coordinate
+ # @return Int - line number (from line numbers panel)
+ private method rightPanel_txt_click {txt_widget ln_widget x y} {
+ set idx [$txt_widget index @$x,$y]
+
+ # Determinate traslated line number
+ set lineNum [$ln_widget get [list $idx linestart] [list $idx lineend]]
+
+ # Select the line
+ if {$lineNum != {}} {
+ $txt_widget tag remove curLine 1.0 end
+ $txt_widget tag add curLine [list $idx linestart] [list $idx+1l linestart]
+ }
+
+ # Retrun result
+ return $lineNum
+ }
+
+ ## If the given line contain bookmark then select it in the list
+ # This function should be called after change line in the editor
+ # @parm Int lineNum - line number
+ # @return Bool - result
+ public method rightPanel_bm_select {lineNum} {
+ if {!$enabled || $block_select} {return}
+ if {![info exists bookmarks_text]} {return}
+
+ # Check for bookmark presence
+ set idx0 [lsearch -ascii -exact [$bookmarks_lineNumbers get 1.0 end] $lineNum]
+ if {$idx0 == -1} {return 0}
+
+ # Select the line
+ incr idx0
+ set idx1 $idx0
+ incr idx1
+ $bookmarks_text tag remove curLine 1.0 end
+ $bookmarks_text tag add curLine $idx0.0 $idx1.0
+ $bookmarks_text see $idx0.0
+ return 1
+ }
+
+ ## If the given line contain bookmark then select it in the list
+ # This function should be called after change line in the editor
+ # @parm Int lineNum - line number
+ # @return Bool - result
+ public method rightPanel_bp_select {lineNum} {
+ if {!$enabled || $block_select} {return}
+ if {![info exists breakpoints_text]} {return}
+
+ # Check for bookmark presence
+ set idx0 [lsearch [$breakpoints_lineNumbers get 1.0 end] $lineNum]
+ if {$idx0 == -1} {return 0}
+
+ # Select the line
+ incr idx0
+ set idx1 $idx0
+ incr idx1
+ $breakpoints_text tag remove curLine 1.0 end
+ $breakpoints_text tag add curLine $idx0.0 $idx1.0
+ $breakpoints_text see $idx0.0
+ return 1
+ }
+
+ ## Unset selection in list of bookmarks
+ # @return void
+ public method rightPanel_bm_unselect {} {
+ if {!$enabled || $block_select} {return}
+ if {![info exists bookmarks_text]} {return}
+ $bookmarks_text tag remove curLine 1.0 end
+ }
+
+ ## Unset selection in list of breakpoints
+ # @return void
+ public method rightPanel_bp_unselect {} {
+ if {!$enabled || $block_select} {return}
+ if {![info exists breakpoints_text]} {return}
+ $breakpoints_text tag remove curLine 1.0 end
+ }
+
+ ## Copy line from the editor to target widget and preserve highlight
+ # @parm Widget target_widget - target widget, where to copy the line
+ # @parm TextIndex idx - target text index
+ # @parm Int lineNum - source line number
+ # @parm Int editor_idx - editor index
+ # @return void
+ private method insert_text {target_widget idx lineNum editor_idx} {
+
+ # Copy text
+ set line [$this editor_procedure $editor_idx getLineContent $lineNum]
+ regsub -all {\t} $line { } line
+ append line "\n"
+ $target_widget insert $idx $line
+
+ # Gain list of text tags in source widget
+ set ranges [$this editor_procedure $editor_idx getTagsRanges $lineNum]
+ # Determinate row in the target widget
+ if {$idx == {end}} {
+ set row [$target_widget index end]
+ set row [expr {int($row) - 2}]
+ } {
+ set row [expr {int($idx)}]
+ }
+ # Iterate over source text tags and add them to target widget
+ foreach range $ranges {
+ # Local variables
+ set tag [lindex $range 0] ;# Text tag
+ set range [lindex $range 1] ;# Tag range
+ set range_len [llength $range] ;# Number of indexes in tag range
+
+ # Iterate over ranges
+ for {set i 0} {$i < $range_len} {incr i} {
+
+ # Translate indexes
+ set idx0 [lindex $range $i]
+ regsub {^\d+} $idx0 $row idx0
+ incr i
+ set idx1 [lindex $range $i]
+ regsub {^\d+} $idx1 $row idx1
+
+ # Set tag
+ $target_widget tag add $tag $idx0 $idx1
+ }
+ }
+ }
+
+ ## Add bookmark to the list
+ # @parm Int lineNum - line number in the editor
+ # @return void
+ public method rightPanel_add_bookmark {lineNum} {
+ if {$block_select} {return}
+
+ ## Determinate target text index
+ set indexes [$bookmarks_lineNumbers get 1.0 end]
+
+ set idx -1
+ set i 0
+ foreach line $indexes {
+ incr i
+ if {$line > $lineNum} {
+ set idx $i
+ break
+ }
+ }
+
+ if {$idx == -1} {
+ set idx {end}
+ } {
+ append idx {.0}
+ }
+
+ # Enable widgets
+ $bookmarks_lineNumbers configure -state normal
+ $bookmarks_text configure -state normal
+
+ # Insert new line to line numbers
+ $bookmarks_lineNumbers insert $idx "$lineNum\n"
+ adjust_width $bookmarks_lineNumbers
+
+ # Insert text to the list
+ insert_text $bookmarks_text $idx $lineNum {}
+
+ # Disable widgets
+ $bookmarks_lineNumbers configure -state disabled
+ $bookmarks_text configure -state disabled
+
+ # Reevaluate icon bar button states
+ bm_bp_disEna_buttons
+ }
+
+ ## Remove bookmark from the list
+ # @parm Int lineNum - line number (in Editor)
+ # @return void
+ public method rightPanel_remove_bookmark {lineNum} {
+ if {$block_select} {return}
+
+ # Determinate start and end index
+ set idx [lsearch [$bookmarks_lineNumbers get 1.0 end] $lineNum]
+ if {$idx == -1} {return}
+
+ set idx0 [expr {int($idx) + 1}]
+ set idx1 [expr {int($idx) + 2}]
+
+ # Enable widgets
+ $bookmarks_lineNumbers configure -state normal
+ $bookmarks_text configure -state normal
+
+ # Remove line from line numbers
+ $bookmarks_lineNumbers delete $idx0.0 $idx1.0
+ adjust_width $bookmarks_lineNumbers
+
+ # Remove line from the list
+ $bookmarks_text delete $idx0.0 $idx1.0
+
+ # Disable widgets
+ $bookmarks_lineNumbers configure -state disabled
+ $bookmarks_text configure -state disabled
+
+ # Reevaluate icon bar button states
+ bm_bp_disEna_buttons
+ }
+
+ ## Add breakpoint to the list
+ # @parm Int lineNum - line number in the editor
+ # @return void
+ public method rightPanel_add_breakpoint {lineNum} {
+ if {$block_select} {return}
+
+ ## Determinate target text index
+ set indexes [$breakpoints_lineNumbers get 1.0 end]
+
+ set idx -1
+ set i 0
+ foreach line $indexes {
+ incr i
+ if {$line > $lineNum} {
+ set idx $i
+ break
+ }
+ }
+
+ if {$idx == -1} {
+ set idx {end}
+ } {
+ append idx {.0}
+ }
+
+ # Enable widgets
+ $breakpoints_lineNumbers configure -state normal
+ $breakpoints_text configure -state normal
+
+ # Insert new line to line numbers
+ $breakpoints_lineNumbers insert $idx "$lineNum\n"
+ adjust_width $breakpoints_lineNumbers
+
+ # Insert text to the list
+ insert_text $breakpoints_text $idx $lineNum {}
+
+ # Disable widgets
+ $breakpoints_lineNumbers configure -state disabled
+ $breakpoints_text configure -state disabled
+
+ # Reevaluate icon bar button states
+ bm_bp_disEna_buttons
+ }
+
+ ## Remove breakpoint from the list
+ # @parm Int lineNum - line number (in Editor)
+ # @return void
+ public method rightPanel_remove_breakpoint {lineNum} {
+ if {$block_select} {return}
+
+ # Determinate start and end index
+ set idx [lsearch [$breakpoints_lineNumbers get 1.0 end] $lineNum]
+ if {$idx == -1} {return}
+
+ set idx0 [expr {int($idx) + 1}]
+ set idx1 [expr {int($idx) + 2}]
+
+ # Enable widgets
+ $breakpoints_lineNumbers configure -state normal
+ $breakpoints_text configure -state normal
+
+ # Remove line from line numbers
+ $breakpoints_lineNumbers delete $idx0.0 $idx1.0
+ adjust_width $breakpoints_lineNumbers
+
+ # Remove line from the list
+ $breakpoints_text delete $idx0.0 $idx1.0
+
+ # Disable widgets
+ $breakpoints_lineNumbers configure -state disabled
+ $breakpoints_text configure -state disabled
+
+ # Reevaluate icon bar button states
+ bm_bp_disEna_buttons
+ }
+
+ ## Adjust width of given text widget to fit lenght of the last line
+ # @parm Widget widget - target text widget
+ # @return void
+ private method adjust_width {widget} {
+ $widget configure -width [string length [lindex [$widget get end-2l end] end]]
+
+ catch {
+ $widget tag add right 0.0 end
+ }
+ }
+
+ ## Binding for button "Up" (Bookmarks icon bar) - select bookmark above the current line
+ # @return void
+ public method rightPanel_bm_up {} {
+
+ # Gain list of bookmarks (line numbers)
+ set lineNumbers [$bookmarks_lineNumbers get 1.0 end]
+ if {[llength $lineNumbers] == 0} {return}
+
+ # Get current line in the editor
+ set curLineNum [$this editor_procedure {} get_current_line_number {}]
+
+ # Find nearest bookmark
+ set lineNum [lindex $lineNumbers end]
+ set idx -2
+ foreach line $lineNumbers {
+ incr idx
+ if {$line >= $curLineNum} {
+ if {$idx >= 0} {
+ set lineNum [lindex $lineNumbers $idx]
+ }
+ break
+ }
+ }
+
+ # Select designated bookmark and jump to its line
+ rightPanel_bm_select $lineNum
+ $this editor_procedure {} goto $lineNum
+ }
+
+ ## Binding for button "Up" (Breakpoints icon bar) - select breakpoint above the current line
+ # @return void
+ public method rightPanel_bp_up {} {
+
+ # Gain list of breakpoints (line numbers)
+ set lineNumbers [$breakpoints_lineNumbers get 1.0 end]
+ if {[llength $lineNumbers] == 0} {return}
+
+ # Get current line in the editor
+ set curLineNum [$this editor_procedure {} get_current_line_number {}]
+
+ # Find nearest breakpoint
+ set lineNum [lindex $lineNumbers end]
+ set idx -2
+ foreach line $lineNumbers {
+ incr idx
+ if {$line >= $curLineNum} {
+ if {$idx >= 0} {
+ set lineNum [lindex $lineNumbers $idx]
+ }
+ break
+ }
+ }
+
+ # Select designated breakpoint and jump to its line
+ rightPanel_bp_select $lineNum
+ $this editor_procedure {} goto $lineNum
+ }
+
+ ## Binding for button "Down" (Bookmarks icon bar) - select bookmark below the current line
+ # @return void
+ public method rightPanel_bm_down {} {
+ # Gain list of bookmarks (line numbers)
+ set lineNumbers [$bookmarks_lineNumbers get 1.0 end]
+ if {[llength $lineNumbers] == 0} {return}
+
+ # Get current line in the editor
+ set curLineNum [$this editor_procedure {} get_current_line_number {}]
+
+ # Find nearest bookmark
+ set lineNum [lindex $lineNumbers 0]
+ set idx -1
+ foreach line $lineNumbers {
+ incr idx
+ if {$line > $curLineNum} {
+ set lineNum [lindex $lineNumbers $idx]
+ break
+ }
+ }
+
+ # Select designated bookmark and jump to its line
+ rightPanel_bm_select $lineNum
+ $this editor_procedure {} goto $lineNum
+ }
+
+ ## Binding for button "Down" (Breakpoints icon bar) - select breakpoint below the current line
+ # @return void
+ public method rightPanel_bp_down {} {
+ # Gain list of breakpoints (line numbers)
+ set lineNumbers [$breakpoints_lineNumbers get 1.0 end]
+ if {[llength $lineNumbers] == 0} {return}
+
+ # Get current line in the editor
+ set curLineNum [$this editor_procedure {} get_current_line_number {}]
+
+ # Find nearest breakpoint
+ set lineNum [lindex $lineNumbers 0]
+ set idx -1
+ foreach line $lineNumbers {
+ incr idx
+ if {$line > $curLineNum} {
+ set lineNum [lindex $lineNumbers $idx]
+ break
+ }
+ }
+
+ # Select designated breakpoint and jump to its line
+ rightPanel_bp_select $lineNum
+ $this editor_procedure {} goto $lineNum
+ }
+
+ ## Remove all bookmarks from the list
+ # @return void
+ public method rightPanel_clear_all_bookmarks {} {
+ # Enable widgets
+ $bookmarks_lineNumbers configure -state normal
+ $bookmarks_text configure -state normal
+ # Clear text widgets
+ $bookmarks_lineNumbers delete 1.0 end
+ adjust_width $bookmarks_lineNumbers
+ $bookmarks_text delete 1.0 end
+ # Disable widgets
+ $bookmarks_lineNumbers configure -state disabled
+ $bookmarks_text configure -state disabled
+
+ # Reevaluate button states (icon bar)
+ bm_bp_disEna_buttons
+ }
+
+ ## Remove all breapoints editor
+ # @return void
+ public method rightPanel_clear_all_breakpoints {} {
+ # Enable widgets
+ $breakpoints_lineNumbers configure -state normal
+ $breakpoints_text configure -state normal
+ # Clear text widgets
+ $breakpoints_lineNumbers delete 1.0 end
+ adjust_width $breakpoints_lineNumbers
+ $breakpoints_text delete 1.0 end
+ # Disable widgets
+ $breakpoints_lineNumbers configure -state disabled
+ $breakpoints_text configure -state disabled
+
+ # Reevaluate button states (icon bar)
+ bm_bp_disEna_buttons
+ }
+
+ ## Manage list of bookmarks - some lines have been removed from editor widget
+ # @parm Int start_line - start of deleted area
+ # @parm Int end_line - end of deleted area
+ # @return void
+ public method rightPanel_remove_bookmarks {start_line end_line} {
+
+ # Gain list of bookmarks
+ set lineNumbers [$bookmarks_lineNumbers get 1.0 end]
+
+ ## Determinate start and end text indexes (list of bookmarks)
+
+ # Start index
+ set start_idx {}
+ set idx 0
+ foreach line $lineNumbers {
+ incr idx
+ if {$line >= $start_line} {
+ set start_idx $idx.0
+ break
+ }
+ }
+
+ # End index
+ set end_idx {end}
+ set idx 0
+ foreach line $lineNumbers {
+ incr idx
+ if {$line > $end_line} {
+ if {$idx != 0} {
+ set end_idx $idx.0
+ }
+ break
+ }
+ }
+
+ # Default start index
+ if {$start_idx == {}} {
+ if {[lindex $lineNumbers end] != $end_line} {
+ return
+ } {
+ set start_idx 1.0
+ }
+ }
+
+ # Determinate number of lines to remove
+ set diff [expr {$end_line - $start_line + 1}]
+
+ # Enable line numbers
+ $bookmarks_lineNumbers configure -state normal
+ # Gain list of lines to recomputation
+ set lineNumbers [$bookmarks_lineNumbers get $end_idx end]
+ # Remove lines from line numbers
+ $bookmarks_lineNumbers delete $start_idx end
+ if {[llength [$bookmarks_lineNumbers get 1.0 end]] != 0} {
+ $bookmarks_lineNumbers insert end "\n"
+ }
+ # Compute missing lines in line numbers
+ foreach line $lineNumbers {
+ $bookmarks_lineNumbers insert end [expr {$line - $diff}]
+ $bookmarks_lineNumbers insert end "\n"
+ }
+ # Finish adjustemnt of line numbers
+ adjust_width $bookmarks_lineNumbers
+ $bookmarks_lineNumbers configure -state disabled
+
+ # Remove lines from list of bookmarks
+ $bookmarks_text configure -state normal
+ $bookmarks_text delete $start_idx $end_idx
+ $bookmarks_text configure -state disabled
+
+ # Reevaluate button states (icon bar)
+ bm_bp_disEna_buttons
+ }
+
+ ## Manage list of breakpoints - some lines have been removed from editor widget
+ # @parm Int start_line - start of deleted area
+ # @parm Int end_line - end of deleted area
+ # @return void
+ public method rightPanel_remove_breakpoints {start_line end_line} {
+
+ # Gain list of breakpoints
+ set lineNumbers [$breakpoints_lineNumbers get 1.0 end]
+
+ ## Determinate start and end text indexes (list of breakpoints)
+
+ # Start index
+ set start_idx {}
+ set idx 0
+ foreach line $lineNumbers {
+ incr idx
+ if {$line >= $start_line} {
+ set start_idx $idx.0
+ break
+ }
+ }
+
+ # End index
+ set end_idx {end}
+ set idx 0
+ foreach line $lineNumbers {
+ incr idx
+ if {$line > $end_line} {
+ if {$idx != 0} {
+ set end_idx $idx.0
+ }
+ break
+ }
+ }
+
+ # Default start index
+ if {$start_idx == {}} {
+ if {[lindex $lineNumbers end] != $end_line} {
+ return
+ } {
+ set start_idx 1.0
+ }
+ }
+
+ # Determinate number of lines to remove
+ set diff [expr {$end_line - $start_line + 1}]
+
+ # Enable line numbers
+ $breakpoints_lineNumbers configure -state normal
+ # Gain list of lines to recomputation
+ set lineNumbers [$breakpoints_lineNumbers get $end_idx end]
+ # Remove lines from line numbers
+ $breakpoints_lineNumbers delete $start_idx end
+ if {[llength [$breakpoints_lineNumbers get 1.0 end]] != 0} {
+ $breakpoints_lineNumbers insert end "\n"
+ }
+ # Compute missing lines in line numbers
+ foreach line $lineNumbers {
+ $breakpoints_lineNumbers insert end [expr {$line - $diff}]
+ $breakpoints_lineNumbers insert end "\n"
+ }
+ # Finish adjustemnt of line numbers
+ adjust_width $breakpoints_lineNumbers
+ $breakpoints_lineNumbers configure -state disabled
+
+ # Remove lines from list of breakpoints
+ $breakpoints_text configure -state normal
+ $breakpoints_text delete $start_idx $end_idx
+ $breakpoints_text configure -state disabled
+
+ # Reevaluate button states (icon bar)
+ bm_bp_disEna_buttons
+ }
+
+ ## Clear the list of symbols
+ # @return void
+ public method rightPanel_clear_symbol_list {} {
+ $sm_lineNumbers configure -state normal
+ $sm_text configure -state normal
+
+ $sm_lineNumbers delete 0.0 end
+ $sm_text delete 0.0 end
+ adjust_width $sm_lineNumbers
+
+ $sm_lineNumbers configure -state disabled
+ $sm_text configure -state disabled
+ }
+
+ ## Refresh the list of symbols
+ # @return void
+ public method rightPanel_refresh_symbols {} {
+ rightPanel_clear_symbol_list
+
+ $this editor_procedure {} autocompletion_turned_on {}
+ $this editor_procedure {} clear_autocompletion_list {}
+ $this editor_procedure {} comp_win_highlight_all_in_background {}
+ }
+
+ ## Validator for search entrybox in the list of symbols
+ # @parm String content - A string to search for
+ # @parm Widget widget - Search entrybox widget
+ # @parm Widget clr_b - Clear button
+ # @return Bool - Success
+ public method rightPanel_sm_search_validate {content widget clr_b} {
+ # No recursion ...
+ if {$search_val_in_progress} {return 0}
+ set search_val_in_progress 1
+
+ # Empty string
+ if {![string length $content]} {
+ $widget configure -style TEntry
+ $clr_b configure -state disabled
+
+ set search_val_in_progress 0
+ return 1
+
+ # Not empty string
+ } {
+ $clr_b configure -state normal
+ }
+
+ # Perform the search
+ set content [string toupper $content]
+ set e [expr {int([$sm_text index insert])}]
+ for {set i 1} {$i < $e} {incr i} {
+ if {![string first $content [string toupper [$sm_text get $i.0 [list $i.0 lineend]]]]} {
+ $widget configure -style StringFound.TEntry
+
+ $sm_text tag remove curLine 1.0 end
+ $sm_text tag add curLine [list $i.0 linestart] [list $i.0+1l linestart]
+
+ set block_select 1
+ $this editor_procedure {} goto $i
+ update idle
+ set block_select 0
+ set search_val_in_progress 0
+ return 1
+ }
+ }
+
+ $widget configure -style StringNotFound.TEntry
+ set search_val_in_progress 0
+ return 1
+ }
+
+ ## Adjust list of symbols
+ # @parm Int lineNum - Line number
+ # @parm String symbol_name - Symbol name
+ # @parm Int symbol_type -
+ # 0 - Label
+ # 1 - Constant
+ # 2 - Something else
+ # 3 - Macro
+ # @parm Bool add__remove - 1 == Add; 0 == Remove
+ # @return void
+ public method rightPanel_adjust_symbol_list {lineNum symbol_name symbol_type add__remove} {
+ $sm_lineNumbers configure -state normal
+ $sm_text configure -state normal
+
+ # Add symbol
+ if {$add__remove} {
+ set indexes [$sm_lineNumbers get 1.0 end]
+
+ set idx -1
+ set i 0
+ foreach line $indexes {
+ incr i
+ if {$line > $lineNum} {
+ set idx $i
+ break
+ }
+ }
+
+ if {$idx == -1} {
+ set idx [$sm_text index {end-1l}]
+ } {
+ append idx {.0}
+ }
+
+ $sm_lineNumbers insert $idx "$lineNum\n"
+ $sm_text insert $idx "$symbol_name\n"
+
+ switch -- $symbol_type {
+ 0 { ;# Label
+ set tag {tag_label}
+ }
+ 1 { ;# Constant
+ set tag {tag_constant}
+ }
+ 2 { ;# C variable
+ set tag {tag_normal}
+ }
+ 3 { ;# Macro
+ set tag {tag_macro}
+ }
+ 7 { ;# C function
+ set tag {tag_c_func}
+ }
+ default {
+ set tag {}
+ }
+ }
+
+ if {$tag != {}} {
+ $sm_text tag add $tag $idx [list $idx lineend]
+ }
+
+ # Remove symbol
+ } {
+ if {$lineNum == {all}} {
+ set idx [list]
+ set e [expr {int([$sm_lineNumbers index end]) - 1}]
+ for {set i 0} {$i < $e} {incr i} {
+ lappend idx $i
+ }
+ } {
+ set idx [lsearch -all [$sm_lineNumbers get 1.0 end] $lineNum]
+ }
+
+ if {$idx == {}} {
+ return
+ }
+ foreach i $idx {
+ incr i
+ if {[string equal [$sm_text get $i.0 [list $i.0 lineend]] $symbol_name]} {
+ $sm_text delete $i.0 $i.0+1l
+ $sm_lineNumbers delete $i.0 $i.0+1l
+ break
+ }
+ }
+ }
+
+ adjust_width $sm_lineNumbers
+ $sm_lineNumbers configure -state disabled
+ $sm_text configure -state disabled
+ }
+
+ ## Shift list of symbols by certain number of lines
+ # @parm Int lineNum - Starting line
+ # @parm Int length - Number of lines to shift by
+ # @return void
+ public method rightPanel_shift_symbols {lineNum length} {
+ if {![info exists sm_lineNumbers]} {return}
+
+ # Get list of bookmarks
+ set lineNumbers [$sm_lineNumbers get 1.0 end]
+
+ # Deterinate start index
+ set start_idx {}
+ set idx 0
+ foreach line $lineNumbers {
+ incr idx
+ if {$line >= $lineNum} {
+ set start_idx $idx.0
+ break
+ }
+ }
+
+ if {$start_idx == {}} {return}
+
+ # Adjust line numbers
+ $sm_lineNumbers configure -state normal
+ set lineNumbers [$sm_lineNumbers get $start_idx end]
+ $sm_lineNumbers delete $start_idx end
+ if {[llength [$sm_lineNumbers get 1.0 end]] != 0} {
+ $sm_lineNumbers insert end "\n"
+ }
+ foreach line $lineNumbers {
+ $sm_lineNumbers insert end [expr {$line + $length}]
+ $sm_lineNumbers insert end "\n"
+ }
+ adjust_width $sm_lineNumbers
+ $sm_lineNumbers configure -state disabled
+ }
+
+ ## Manage list of bookmarks - some lines have been added to editor widget
+ # @parm Int lineNum - line number
+ # @parm Int length - number of lines
+ # @return void
+ public method rightPanel_shift_bookmarks {lineNum length} {
+ if {![info exists bookmarks_lineNumbers]} {return}
+
+ # Get list of bookmarks
+ set lineNumbers [$bookmarks_lineNumbers get 1.0 end]
+
+ # Deterinate start index
+ set start_idx {}
+ set idx 0
+ foreach line $lineNumbers {
+ incr idx
+ if {$line >= $lineNum} {
+ set start_idx $idx.0
+ break
+ }
+ }
+
+ if {$start_idx == {}} {return}
+
+ # Adjust line numbers
+ $bookmarks_lineNumbers configure -state normal
+ set lineNumbers [$bookmarks_lineNumbers get $start_idx end]
+ $bookmarks_lineNumbers delete $start_idx end
+ if {[llength [$bookmarks_lineNumbers get 1.0 end]] != 0} {
+ $bookmarks_lineNumbers insert end "\n"
+ }
+ foreach line $lineNumbers {
+ $bookmarks_lineNumbers insert end [expr {$line + $length}]
+ $bookmarks_lineNumbers insert end "\n"
+ }
+ adjust_width $bookmarks_lineNumbers
+ $bookmarks_lineNumbers configure -state disabled
+ }
+
+ ## Manage list of breakpoints - some lines have been added to editor widget
+ # @parm Int lineNum - line number
+ # @parm Int length - number of lines
+ # @return void
+ public method rightPanel_shift_breakpoints {lineNum length} {
+ if {![info exists bookmarks_lineNumbers]} {return}
+
+ # Get list of bookmarks
+ set lineNumbers [$breakpoints_lineNumbers get 1.0 end]
+
+ # Deterinate start index
+ set start_idx {}
+ set idx 0
+ foreach line $lineNumbers {
+ incr idx
+ if {$line >= $lineNum} {
+ set start_idx $idx.0
+ break
+ }
+ }
+
+ if {$start_idx == {}} {return}
+
+ # Adjust line numbers
+ $breakpoints_lineNumbers configure -state normal
+ set lineNumbers [$breakpoints_lineNumbers get $start_idx end]
+ $breakpoints_lineNumbers delete $start_idx end
+ if {[llength [$breakpoints_lineNumbers get 1.0 end]] != 0} {
+ $breakpoints_lineNumbers insert end "\n"
+ }
+ foreach line $lineNumbers {
+ $breakpoints_lineNumbers insert end [expr {$line + $length}]
+ $breakpoints_lineNumbers insert end "\n"
+ }
+ adjust_width $breakpoints_lineNumbers
+ $breakpoints_lineNumbers configure -state disabled
+ }
+
+ ## Invoke right panel configuration dialog
+ # This function takes any list of arguments
+ # @return void
+ public method rightPanel_configure args {
+ ::configDialogs::rightPanel::mkDialog $args
+ }
+
+ ## Return true if this panel is in visible state
+ # @return Bool - result
+ public method isRightPanelVisible {} {return $PanelVisible}
+
+ ## Get width of the panel
+ # @return Int - width in pixels
+ public method getRightPanelSize {} {
+ if {$PanelVisible} {
+ return $PanelSize
+ } {
+ return $last_PanelSize
+ }
+ }
+
+ ## Get ID of currently active page
+ # @return String - the ID
+ public method getRightPanelActivePage {} {return $active_page}
+
+ ## Show/Hide this panel
+ # @return void
+ public method right_panel_show_hide {} {
+ # Hide the panel
+ if {$PanelVisible} {
+ $parentPane paneconfigure $notebook_frame -minsize 0
+
+ pack forget $notebook ;# Hide notebook
+ set last_PanelSize $PanelSize ;# Save current panel width
+ set PanelSize 60 ;# Change panel width
+ right_panel_redraw_pane ;# Redraw panel
+
+ # Show button bar
+ pack $button_bar -anchor nw
+ # Hide pane sash
+ $parentPane configure -sashwidth 0
+ bind $parentPane <Button> {break}
+ # Set panel visibility flag
+ set PanelVisible 0
+
+ # Show the panel
+ } {
+ $parentPane paneconfigure $notebook_frame -minsize 295
+
+ # Hide button bar
+ pack forget $button_bar
+ # Show panel notebook
+ set PanelSize $last_PanelSize
+ right_panel_redraw_pane
+ $notebook raise $active_page
+ pack $notebook -expand 1 -fill both
+ # Show pane sash
+ $parentPane configure -sashwidth 2
+ bind $parentPane <Button> {}
+ # Set panel visibility flag
+ set PanelVisible 1
+ }
+ }
+
+ ## Change panel active page
+ # @parm String page - ID of the page to show
+ # @return void
+ public method rightPanel_show_up {page} {
+ if {!$PanelVisible} right_panel_show_hide
+ $notebook raise $page
+ }
+
+ ## Set active page but do not show it
+ # @parm String pageName - ID of the page
+ # @return void
+ public method rightPanel_set_active_page {pageName} {
+ switch -- $active_page {
+ {Symbols} {
+ catch {
+ $this editor_procedure {} comp_win_highlight_all_in_background {}
+ }
+ }
+ {Instruction} {
+ right_panel_instruction_details_set_enabled 0
+ }
+ }
+
+ set active_page $pageName
+
+ switch -- $active_page {
+ {Symbols} {
+ catch {
+ $this editor_procedure {} comp_win_highlight_all_in_background {}
+ }
+ }
+ {Instruction} {
+ right_panel_instruction_details_set_enabled $enabled
+ catch {
+ $this editor_procedure {} adjust_instruction_details {}
+ }
+ }
+ }
+ }
+
+ ## Set panel width acording to current sash position
+ # @return void
+ public method right_panel_set_size {} {
+ set PanelSize [lindex [$parentPane sash coord 0] 0]
+ set PanelSize [expr {${::WIN_GEOMETRY_width} - $PanelSize}]
+ }
+
+ ## Redraw panel (move pane sash) acorning to current value of $PanelSize
+ # @return void
+ public method right_panel_redraw_pane {} {
+ if {$redraw_pane_in_progress} {
+ after 50 "$this right_panel_redraw_pane"
+ return
+ }
+ set redraw_pane_in_progress 1
+
+ update
+ $parentPane sash place 0 [expr {${::WIN_GEOMETRY_width} - $PanelSize}] 0
+ update
+
+ set redraw_pane_in_progress 0
+ }
+
+ ## Create text tags inteded for "Instruction details"
+ # @parm Widget widget - tagret text widget
+ # @parm List definition_list - List of tags to create ({tag_name fg_color ?bold_or_italic?} ...)
+ # @parm Bool use_editor_font - Use font family and size from code editor
+ # @return void
+ public method right_panel_create_highlighting_tags {widget definition_list use_editor_font} {
+ if {$use_editor_font == 1} {
+ set font $fontFamily
+ set size $fontSize
+ } elseif {$use_editor_font == -1} {
+ set font $::DEFAULT_FIXED_FONT
+ set size -14
+ } {
+ set font $::DEFAULT_FIXED_FONT
+ set size -12
+ }
+
+ # Iterate over tags definition
+ foreach tag $definition_list {
+
+ # Explicit flag "Bold or Italic"
+ if {[lindex $tag 2] != {}} {
+ # Bold font
+ if {[lindex $tag 2]} {
+ $widget tag configure [lindex $tag 0] \
+ -foreground [lindex $tag 1] \
+ -font [font create -size $size \
+ -family $font \
+ -weight {bold} \
+ -slant {roman}]
+ # Italic font
+ } {
+ $widget tag configure [lindex $tag 0] \
+ -foreground [lindex $tag 1] \
+ -font [font create -size $size \
+ -family $font \
+ -weight {normal} \
+ -slant {italic}]
+ }
+
+ # No bold, no italic
+ } {
+ $widget tag configure [lindex $tag 0] \
+ -foreground [lindex $tag 1] \
+ -font [font create -size $size \
+ -family $font \
+ -weight {normal} \
+ -slant {roman}]
+ }
+ }
+ }
+
+ ## Enable selections in list of bookmarks and breakpoints and enbale instruction details
+ # @return void
+ public method rightPanel_enable {} {
+ set enabled 1
+ $this right_panel_watches_set_enabled $enabled
+ $this right_panel_instruction_details_set_enabled $enabled
+ }
+
+ ## Disable selections in list of bookmarks and breakpoints and enbale instruction details
+ # @return void
+ public method rightPanel_disable {} {
+ set enabled 0
+ $this right_panel_watches_set_enabled $enabled
+ $this right_panel_instruction_details_set_enabled $enabled
+ }
+}
diff --git a/lib/rightpanel/subprograms.tcl b/lib/rightpanel/subprograms.tcl
new file mode 100755
index 0000000..6385266
--- /dev/null
+++ b/lib/rightpanel/subprograms.tcl
@@ -0,0 +1,704 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides panel for watching subprogram calls
+# --------------------------------------------------------------------------
+
+class SubPrograms {
+ ## COMMON
+ common fsd_filename {} ;# Filename choosen by FSD
+ # Main font for the text widget
+ common main_font [font create \
+ -family {helvetica} \
+ -size -14 \
+ ]
+ # Bold font for the text widget
+ common bold_font [font create \
+ -family {helvetica} \
+ -size -14 -weight {bold} \
+ ]
+ # Font for status bar below the text box
+ common large_font [font create \
+ -family {helvetica} \
+ -size -14 \
+ ]
+ # Bold font for status bar below the text box
+ common large_bold_font [font create \
+ -family {helvetica} \
+ -size -14 -weight {bold} \
+ ]
+
+ ## PRIVATE
+ private variable parent ;# Widget: parent widget
+ private variable gui_initialized 0 ;# Bool: GUI initialized
+
+ private variable text_widget ;# Widget: Text widget containg almost all the information
+ private variable scrollbar ;# Widget: Scrollbar for the text widget
+ private variable enable_chbut ;# Widget: Check button "Enable"
+ private variable intr_chbut ;# Widget: Check button "Include interrupts"
+ private variable total_val_lbl ;# Widget: Label containg the count of subprograms recorded
+ private variable menu {} ;# Widget: Popup menu for the text widget
+ private variable enabled 1 ;# Bool: Panel active
+ private variable ena_intr 1 ;# Bool: Taking interrupts enabled
+ private variable return_but ;# Widget: Button "RETURN"
+ private variable save_but ;# Widget: Button "Save"
+ private variable clear_but ;# Widget: Button "Clear"
+ private variable count 0 ;# Int: Number of subprograms mentioned in the text widget
+ private variable menu_source {} ;# String: Auxiliary variable for the popup menu -- Source address
+ private variable menu_target {} ;# String: Auxiliary variable for the popup menu -- Target address
+
+ constructor {} {
+ }
+
+ destructor {
+ if {$gui_initialized} {
+ menu_Sbar_remove $menu
+ }
+ }
+
+ ## Prepare this panel for initialization of its GUI
+ # MUST BE called before "CreateSubProgramsGUI"
+ # @parm Widget _parent - Frame where this panel would be created
+ # @return void
+ public method PrepareSubPrograms {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ load_config $::CONFIG(SUBP_MON_CONFIG)
+ }
+
+ ## Finalize initialization of this panel
+ # @return void
+ public method CreateSubProgramsGUI {} {
+ create_gui
+ subprograms_create_tags
+ create_menus
+ set_bindings
+ }
+
+ ## Get configuration list for this panel
+ # @return void
+ public method subprograms_get_config {} {
+ return [list $enabled $ena_intr]
+ }
+
+ ## Load configuration list for this panel
+ # @parm List conf - Configuration list
+ # @return void
+ private method load_config {conf} {
+ if {![regexp {^[01] [01]$} $conf]} {
+ return
+ }
+ set enabled [lindex $conf 0]
+ set ena_intr [lindex $conf 1]
+ }
+
+ ## Create all widgets which this panel consist of
+ # @return void
+ private method create_gui {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Create top frame (checkbuttons)
+ set top_frame [frame $parent.top]
+ set enable_chbut [checkbutton $top_frame.enable_chbut \
+ -text [mc "Enable"] \
+ -command "$this subprograms_dis_ena" \
+ ]
+ set intr_chbut [checkbutton $top_frame.intr_chbut \
+ -text [mc "Include interrupts"] \
+ -command "$this subprograms_intr_yesno" \
+ ]
+ pack $enable_chbut -side left -padx 10
+ pack $intr_chbut -side left -padx 10
+
+ # Adjust check buttons
+ if {$enabled} {
+ $enable_chbut select
+ } {
+ $enable_chbut deselect
+ }
+ if {$ena_intr} {
+ $intr_chbut select
+ } {
+ $intr_chbut deselect
+ }
+
+ # Create button frame (Buttons: Save, Clear and Return)
+ set button_frame [frame $parent.button_frame]
+ set return_but [ttk::button $button_frame.return_but \
+ -text [mc "RETURN"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "$this subprograms_force_return" \
+ -state disabled \
+ -width 6 \
+ ]
+ set clear_but [ttk::button $button_frame.clear_but \
+ -text [mc "Clear"] \
+ -style Flat.TButton \
+ -compound left \
+ -state disabled \
+ -image ::ICONS::16::editdelete \
+ -command "$this subprograms_clear" \
+ -width 5 \
+ ]
+ set save_but [ttk::button $button_frame.filesaveas \
+ -text [mc "Save"] \
+ -style Flat.TButton \
+ -compound left \
+ -state disabled \
+ -image ::ICONS::16::filesaveas \
+ -command "$this subprograms_save" \
+ -width 5 \
+ ]
+ pack $save_but -pady 0 -side left
+ pack $clear_but -pady 0 -side left -padx 5
+ pack $return_but -pady 0 -side right
+
+ # Create middle frame (text widget and its scrollbar)
+ set middle_frame [frame $parent.middle]
+ set text_widget [text $middle_frame.text \
+ -yscrollcommand "$middle_frame.scrollbar set" \
+ -bg {#FFFFFF} -width 0 -height 0 \
+ -font $main_font -insertontime 0 -wrap none \
+ -cursor left_ptr -takefocus 0 \
+ -tabstyle wordprocessor \
+ ]
+ set scrollbar [ttk::scrollbar $middle_frame.scrollbar \
+ -orient vertical \
+ -command "$text_widget yview" \
+ ]
+ pack $text_widget -side left -fill both -expand 1
+ pack $scrollbar -side right -fill y -after $text_widget
+
+ # Create bottom frame
+ set bottom_frame [frame $parent.bottom]
+ pack [label $bottom_frame.total_lbl \
+ -text [mc "TOTAL: "] -font $large_font \
+ -fg {#555555} \
+ ] -side left
+ set total_val_lbl [label $bottom_frame.total_val_lbl \
+ -font $large_bold_font -text {0} \
+ ]
+ pack $total_val_lbl -side left
+
+ # Pack all main frames
+ pack $top_frame -fill x
+ pack $button_frame -fill x
+ pack $middle_frame -fill both -expand 1
+ pack $bottom_frame -fill x -side bottom
+ }
+
+ ## Set event bindings for the text widget
+ # @return void
+ private method set_bindings {} {
+ foreach event {
+ <B1-Enter> <B1-Leave>
+ <B2-Motion> <Button-5> <Button-4>
+ <MouseWheel>
+ } {
+ bind $text_widget $event [bind Text $event]
+ }
+ bind $text_widget <Button-1> "$this subprograms_click %x %y"
+ bind $text_widget <ButtonRelease-3> "$this subprograms_popup %x %y %X %Y"
+ bindtags $text_widget $text_widget
+ }
+
+ ## Create popup menu for the text widget
+ # @return void
+ private method create_menus {} {
+ set menu "$text_widget.popup_menu"
+ if {[winfo exists $menu]} {destroy $menu}
+ menuFactory {
+ {command {Go to source line} {} 0 "subprograms_menu_action 0"
+ {goto} "Navigate code editor to the line from which this subprogram was invoked"}
+ {command {Go to target line} {} 0 "subprograms_menu_action 1"
+ {goto} "Navigate code editor to the line from where this subprogram resides"}
+ {separator}
+ {command {Copy source address to clipboard} {} 0 "subprograms_menu_action 2"
+ {editcopy} "Copy return address to clipboard (hexadecimal representation)"}
+ {command {Copy target address to clipboard} {} 0 "subprograms_menu_action 3"
+ {editcopy} "Copy address where this subprogram begins to the clipboard"}
+ {separator}
+ {command {Remove this} {} 0 "subprograms_menu_action 4"
+ {editdelete} "Remove this entry"}
+ } $menu 0 "$this " 0 {}
+ }
+
+ ## Create highlighting tags for the text widget
+ # @return void
+ private method subprograms_create_tags {} {
+ $text_widget tag configure tag_sel -borderwidth 1 -relief raised
+ $text_widget tag configure tag_from -foreground {#00AA00}
+ $text_widget tag configure tag_to -foreground {#0000AA}
+ $text_widget tag configure tag_ins -font $bold_font
+ $text_widget tag configure tag_first -background {#DDDDDD}
+ }
+
+ ## Toggle state enabled for whole panel
+ # @return void
+ public method subprograms_dis_ena {} {
+ set enabled [expr {!$enabled}]
+ if {$enabled} subprograms_clear
+ }
+
+ ## Toggle flag "Enable interrupts"
+ # @return void
+ public method subprograms_intr_yesno {} {
+ set ena_intr [expr {!$ena_intr}]
+ }
+
+ ## Event handler for the text widget: <Button-1>
+ # @parm Int x - Relative pointer position
+ # @parm Int y - Relative pointer position
+ # @return void
+ public method subprograms_click {x y} {
+ set menu_source {}
+ set menu_target {}
+ $text_widget configure -state normal
+
+ # Remove selection and determinate line number
+ $text_widget tag remove tag_sel 1.0 end
+ set line [expr {int([$text_widget index @$x,$y])}]
+
+ # Adjust selection
+ if {$line % 3} {
+ set line [expr {($line / 3) * 3}]
+ if {($line / 3) < $count} {
+ # Set selection
+ incr line
+ $text_widget tag add tag_sel $line.0 [expr {$line+2}].0
+
+ # Determinate source address of the selected subprogram
+ regexp {\w+\s*$} [$text_widget get \
+ $line.0 [list $line.0 lineend] \
+ ] menu_target
+ set menu_target [string trimright $menu_target { h}]
+ if {![string is xdigit $menu_target]} {
+ set menu_target {}
+ }
+
+ # Determinate target address of the selected subprogram
+ regexp {\w+\s*$} [$text_widget get \
+ [expr {$line + 1}].0 \
+ [list [expr {$line + 1}].0 lineend] \
+ ] menu_source
+ set menu_source [string trimright $menu_source { h}]
+ if {![string is xdigit $menu_source]} {
+ set menu_source {}
+ }
+ }
+ }
+
+ # Disable the text widget again
+ $text_widget configure -state disabled
+ }
+
+ ## Perform certain menu action (popup menu for the text widget)
+ # @parm Int action - ID of action to execute
+ # @return void
+ public method subprograms_menu_action {action} {
+ switch -- $action {
+ 0 { ;# Action: "Go to source line"
+ if {$menu_source != {}} {
+ goto_line [expr {"0x$menu_source" - 1}]
+ }
+ }
+ 1 { ;# Action: "Go to target line"
+ if {$menu_target != {}} {
+ goto_line [expr "0x$menu_target"]
+ }
+ }
+ 2 { ;# Action: "Copy source address to clipboard"
+ clipboard clear
+ clipboard append $menu_source
+ }
+ 3 { ;# Action: "Copy target address to clipboard"
+ clipboard clear
+ clipboard append $menu_target
+ }
+ 4 { ;# Remove this entry
+ if {[llength [$text_widget tag nextrange tag_sel 1.0]]} {
+ $text_widget configure -state normal
+ $text_widget delete tag_sel.first tag_sel.last+1l
+ $text_widget configure -state disabled
+ }
+ }
+ }
+ }
+
+ ## Action: "Go to source line" / "Go to target line"
+ # @parm Int address - Address in code memory
+ # @return void
+ private method goto_line {address} {
+ # Resolve line number and source address
+ set line [$this simulator_address2line $address]
+ set address [$this simulator_line2address [lindex $line 0] [lindex $line 1]]
+
+ # Line resolved
+ if {$line != {}} {
+ # Simulator is running
+ if {[$this is_frozen]} {
+ $this setPC $address
+ $this Simulator_sync_PC_etc
+ $this move_simulator_line $line
+ # Simulator is not running
+ } {
+ set filename [$this simulator_get_filename [lindex $line 1]]
+ set filename [file tail $filename]
+ if {[$this fucus_specific_editor $filename 0]} {
+ $this editor_procedure {} goto [lindex $line 0]
+ }
+ }
+ # Line unresolved
+ } {
+ tk_messageBox \
+ -parent . \
+ -title [mc "Line not found"] \
+ -message [mc "There is no matching line in the source code"]
+ }
+ }
+
+ ## Invoke popup menu for the text widget
+ # @parm Int x - Relative position of mouse pointer
+ # @parm Int y - Relative position of mouse pointer
+ # @parm Int X - Absolute position of mouse pointer
+ # @parm Int Y - Absolute position of mouse pointer
+ # @return void
+ public method subprograms_popup {x y X Y} {
+ # Adjust selection
+ subprograms_click $x $y
+
+ # Determinate line and what to do with the menu
+ set line [expr {int([$text_widget index @$x,$y])}]
+ if {$line % 3} {
+ set line [expr {$line / 3}]
+ if {$line >= $count} {
+ set state {disabled}
+ } {
+ set state {normal}
+ }
+ } {
+ set state {disabled}
+ }
+
+ # Adjust states of certain items in the menu
+ foreach entry {
+ {Go to source line}
+ {Go to target line}
+ {Copy source address to clipboard}
+ {Copy target address to clipboard}
+ {Remove this}
+ } {
+ $menu entryconfigure [::mc $entry] -state $state
+ }
+
+ # Invoke the menu
+ tk_popup $menu $X $Y
+ }
+
+ ## Register subprogram call
+ # @parm Int type - Invoked by: 0 == LCALL; 1 == ACALL; 2 == Interrupt; 3 == LCALL or ACALL
+ # @parm Int from - Source address (return address)
+ # @parm Int to - Target address
+ # @return void
+ public method subprograms_call {type from to} {
+ if {!$enabled} {return}
+ if {!$gui_initialized} CreateSubProgramsGUI
+
+ # Determinate string to print as an instruction
+ switch -- $type {
+ 0 {set ins " LCALL\t"}
+ 1 {set ins " ACALL\t"}
+ 2 {
+ set ins " Interrupt\t"
+ if {!$ena_intr} {
+ return
+ }
+ }
+ 3 {set ins " CALL\t"}
+ }
+
+ # Convert value of source address to hexadecimal representation
+ if {$from < 0} {
+ set from {-----}
+ } {
+ set from [format %X $from]
+ set len [string length $from]
+ if {$len < 4} {
+ set from "[string repeat {0} [expr {4 - $len}]]$from"
+ }
+ append from {h}
+ }
+
+ # Convert value of target address to hexadecimal representation
+ if {$to < 0} {
+ set to {-----}
+ } {
+ set to [format %X $to]
+ set len [string length $to]
+ if {$len < 4} {
+ set to "[string repeat {0} [expr {4 - $len}]]$to"
+ }
+ append to {h}
+ }
+
+ # Enable the text widget
+ $text_widget configure -state normal
+
+ # Insert separator
+ if {$count} {
+ $text_widget insert 1.0 "\n"
+ }
+
+ # Print return address
+ $text_widget insert 1.0 "\n"
+ $text_widget insert 1.0 [mc " Return address:\t"]
+ set idx [$text_widget index {1.0 lineend}]
+ $text_widget insert {1.0 lineend} $from
+ $text_widget tag add tag_from $idx {1.0 lineend}
+
+ # Print type and target address
+ $text_widget insert 1.0 "\n"
+ $text_widget insert 1.0 "$ins\t"
+ $text_widget tag add tag_ins 1.0 {1.0 lineend}
+ set idx [$text_widget index {1.0 lineend}]
+ $text_widget insert {1.0 lineend} $to
+ $text_widget tag add tag_to $idx {1.0 lineend}
+
+ $text_widget tag remove tag_first 1.0 end
+ $text_widget tag add tag_first 1.0 3.0
+
+ # Disable the text widget, adjust button bar, labels on the bottom
+ $text_widget configure -state disabled
+ incr count
+ $total_val_lbl configure -text $count
+ disena_buttonbar $count
+ }
+
+ ## Disable or enable buttons on the button bar
+ # @parm Bool bool - 1 == enable; 0 == diable
+ # @return void
+ private method disena_buttonbar {bool} {
+ if {$bool} {
+ set state {normal}
+ } {
+ set state {disabled}
+ }
+ $return_but configure -state $state
+ $clear_but configure -state $state
+ $save_but configure -state $state
+ }
+
+ ## Register return for subprogram
+ # @parm Bool intr__sub - 0 == Common subprogram; 1== Interrupt
+ # @return void
+ public method subprograms_return {intr__sub} {
+ if {!$enabled} {return}
+ if {!$count} {return}
+ if {$intr__sub && !$ena_intr} {return}
+ if {!$gui_initialized} CreateSubProgramsGUI
+
+ $text_widget configure -state normal
+ $text_widget delete 1.0 4.0
+ $text_widget configure -state disabled
+ incr count -1
+ if {$count} {
+ $text_widget tag remove tag_first 1.0 end
+ $text_widget tag add tag_first 1.0 3.0
+ }
+ $total_val_lbl configure -text $count
+ disena_buttonbar $count
+ }
+
+ ## Clear the text widget
+ # @return void
+ public method subprograms_clear {} {
+ if {!$gui_initialized} {return}
+ set count 0
+ $total_val_lbl configure -text 0
+ $text_widget configure -state normal
+ $text_widget delete 1.0 end
+ $text_widget configure -state disabled
+ disena_buttonbar 0
+ }
+
+ ## Enable or disable this panel
+ # @parm Bool bool - 1 == Enable; 0 == Disbale
+ # @return void
+ public method subprograms_setEnabled {bool} {
+ if {!$gui_initialized} {return}
+ if {!$bool} {
+ $return_but configure -state disabled
+ }
+ }
+
+ ## Force return from active subprogram (the topmost entry)
+ # Binding for button "RETURN" on the button bar
+ # @return void
+ public method subprograms_force_return {} {
+ if {![regexp {^\s*\w+} [$text_widget get 1.0 3.0] word]} {
+ return
+ }
+ set word [string trim $word]
+ if {$word == {Interrupt}} {
+ set word 1
+ } {
+ set word 0
+ }
+ $this simulator_return_from_SP $word
+ }
+
+ ## Invoke file selection dialog to save file
+ # Binding for button "Save" on the button bar
+ # @return void
+ public method subprograms_save {} {
+
+ # Invoke the dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Save file - MCU 8051 IDE"] \
+ -directory [$this cget -projectPath] \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{Plain text} {*.txt} }
+ {{All files} {*} }
+ }
+
+ # Ok button
+ fsd setokcmd {
+ set fsd_filename [::SubPrograms::fsd get]
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $fsd_filename]} {
+ set filename "[${::X::actualProject} cget -ProjectDir]/$fsd_filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $fsd_filename]} {
+ set filename [file join [${::X::actualProject} cget -ProjectDir] $fsd_filename]
+ }
+ }
+
+ set ::SubPrograms::fsd_filename [file normalize $fsd_filename]
+ }
+
+ # Activate the dialog
+ fsd activate
+ if {$fsd_filename != {}} {
+ subprograms_save_proc $fsd_filename
+ }
+ }
+
+ ## Save content of the text widget under certain filename
+ # @parm String filename - Target filename
+ # @return void
+ public method subprograms_save_proc {filename} {
+ # Adjust file extension
+ if {[file extension [file tail $filename]] != {.txt}} {
+ append filename {.txt}
+ }
+ # Make backup copy of the file
+ if {[file exists $filename] && [file isfile $filename]} {
+ # Ask user for overwrite existing file
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent . \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $filename]]
+ ] != {yes}
+ } {
+ return
+ }
+ # Create a backup file
+ catch {
+ file rename -force $filename "$filename~"
+ }
+ }
+ # Try to open the file
+ if {[catch {
+ set file [open $filename w 420]
+ }]} {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to write to file:\n\"%s\"" $filename]
+ return
+ }
+ # Write content of the text widget into the file and close the file
+ puts -nonewline $file [$text_widget get 1.0 end]
+ close $file
+ }
+
+ ## Get number of recorder active subprograms
+ # @return Int - Count
+ public method subprograms_get_count {} {
+ if {!$gui_initialized} {return 0}
+ return $count
+ }
+
+ ## Get content for purpose of program hibernation
+ # @return String - Text
+ public method subprograms_get_formated_content {} {
+ if {!$gui_initialized} {return {}}
+ set result {}
+ set source {}
+ set target {}
+ set type {}
+ set line_num 0
+
+ foreach line [split [$text_widget get 1.0 end] "\n"] {
+ if {$line == {}} {
+ if {$source != {} && $target != {} && $type != {}} {
+ lappend result [list $source $target $type]
+ }
+ set line 0
+ set source {}
+ set target {}
+ set type {}
+ continue
+ }
+ if {$line_num} {
+ regexp {\w+\s*$} $line source
+ set source [string range $source 0 3]
+ set source [expr "0x$source"]
+ } {
+ regexp {\w+\s*$} $line target
+ set target [string range $target 0 3]
+ set target [expr "0x$target"]
+
+ regexp {^\s*\w+} $line type
+ switch -- [string trim $type] {
+ {LCALL} {set type 0}
+ {ACALL} {set type 1}
+ {Interrupt} {set type 2}
+ {CALL} {set type 3}
+ }
+ }
+ incr line_num
+ }
+ return $result
+ }
+}
diff --git a/lib/simulator/bitmap.tcl b/lib/simulator/bitmap.tcl
new file mode 100755
index 0000000..6ed43e0
--- /dev/null
+++ b/lib/simulator/bitmap.tcl
@@ -0,0 +1,510 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2008 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides graphical view on bit addressable area in simulated MCU
+# --------------------------------------------------------------------------
+
+class BitMap {
+ ## COMMON
+ common count 0 ;# Int: Counter of object instances
+ # Last window geometry
+ common win_geometry [lindex $::CONFIG(BITMAP_CONFIG) 0]
+
+ common bit_addr_clr {#0000FF} ;# Color: Bit address
+ common reg_addr_clr {#00DD00} ;# Color: Register address
+ common rect_size 14 ;# Int: Size of rectangle repersenting one bit
+ common rect_sep 2 ;# Int: Space between bits
+ common reg_sep 4 ;# Int: Space between octetes
+ common row_sep 4 ;# Int: Space between rows
+ common bm_x_org 50 ;# Int: Bitmap origin (X)
+ common bm_y_org 20 ;# Int: Bitmap origin (Y)
+
+ common zero_fill #FF0000 ;# Color: Bit fill color for log. 0 (Non-selected)
+ common zero_outline #FF8888 ;# Color: Bit outline color for log. 0 (Non-selected)
+ common zero_a_fill #FF8888 ;# Color: Bit fill color for log. 0 (Selected bit)
+ common zero_a_outline #FFDDDD ;# Color: Bit outline color for log. 0 (Selected bit)
+
+ common one_fill #00FF00 ;# Color: Bit color for log. 1 (Non-selected)
+ common one_outline #88FF88 ;# Color: Bit outline color for log. 1 (Non-selected)
+ common one_a_fill #88FF88 ;# Color: Bit fill color for log. 1 (Selected bit)
+ common one_a_outline #DDFFDD ;# Color: Bit outline color for log. 1 (Selected bit)
+
+ # Font: Normal font for canvas widget
+ common bitmap_n_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ ]
+ # Font: Bold font for canvas widget
+ common bitmap_b_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ ]
+
+
+ ## PRIVATE
+ private variable win ;# Widget: Dialog window
+ private variable dialog_opened 0 ;# Bool: Window opened
+
+ private variable main_frame ;# Widget: Main frame (contains canvas widget)
+ private variable bitmap_canvas ;# Widget: Canvas widget
+ private variable bits ;# Array of Objects: bit rectangles in canvas widget
+ private variable bits_states ;# Array of Booleans: States of particular bits
+
+ private variable bit_addr_lbl ;# Widget: Label showing bit address on status bar
+ private variable reg_addr_lbl ;# Widget: Label showing register address on status bar
+
+ private variable sync_ena 1 ;# Bool: Synchroniation with engine enabled
+ private variable enabled 0 ;# Bool: Changes enabled
+
+
+ constructor {} {
+ }
+
+ destructor {
+ }
+
+ ## Enable or disable changes in registers
+ # @parm Bool _enabled - 1 == Enable; 0 == Disable
+ # @return void
+ public method bitmap_setEnabled {_enabled} {
+ set enabled $_enabled
+ }
+
+ ## Get configuration list (for restoring sessions)
+ # @return List - Dialog configuration
+ public method bitmap_get_config {} {
+ return [list $win_geometry]
+ }
+
+ ## Close dialog
+ # @return void
+ public method bitmap_close_dialog {} {
+ set win_geometry [wm geometry $win]
+ set dialog_opened 0
+ destroy $win
+ }
+
+ ## Open dialog window
+ # @return void
+ public method bitmap_invoke_dialog {} {
+ # Exit if the dialog is already opened
+ if {$dialog_opened} {
+ raise $win
+ return
+ }
+
+ # Create dialog window
+ set win [toplevel .bitmap_$count -class {Bitmap} -bg {#EEEEEE}]
+ incr count
+
+ # ----------------------------------------------------------------
+ # Create main frame and canvas widget
+ # ----------------------------------------------------------------
+
+ set main_frame [frame $win.main_frame]
+ set bitmap_canvas [canvas $main_frame.canvas \
+ -width 620 -height 110 -relief flat -bd 0 \
+ -highlightthickness 0 -takefocus 0 \
+ ]
+
+ ## Create matrix of rectangles
+ set addr 128 ;# Int: Bit address
+ set x0 $bm_x_org ;# Int: Rectangle horizontal coordinate
+ set y0 $bm_y_org ;# Int: Rectangle vertical coordinate
+ # Create 4 rows
+ for {set y 0} {$y < 4} {incr y} {
+ # Create 4 registers in each row
+ for {set r 0} {$r < 4} {incr r} {
+ # Create 8 bits in each register
+ for {set x 0} {$x < 8} {incr x} {
+ # Create bit rectagle
+ set bit [$bitmap_canvas create rectangle $x0 $y0 \
+ [expr {$x0 + $rect_size}] [expr {$y0 + $rect_size}] \
+ -fill $zero_fill -outline $zero_outline \
+ ]
+
+ # Adjust X position for the next rectagle
+ incr x0 $rect_size
+ incr x0 $rect_sep
+
+ # Register created rectagle for future referecing
+ incr addr -1
+ set bits($addr) $bit
+ set bits_states($addr) 0
+
+ # Set rectagle event bindings
+ $bitmap_canvas bind $bit <Enter> "$this bitmap_bit_enter $addr"
+ $bitmap_canvas bind $bit <Leave> "$this bitmap_bit_leave $addr"
+ $bitmap_canvas bind $bit <Button-1> "$this bitmap_bit_click $addr"
+ }
+ # Adjust X position for the next register
+ incr x0 $reg_sep
+ }
+ # Adjust X and Y position for the next row
+ set x0 $bm_x_org
+ incr y0 $rect_size
+ incr y0 $row_sep
+ }
+
+ ## Create bottom horizonal header
+ # Bit addresses
+ foreach txt {{1F 18} {17 10} {0F 08} {07 00}} {
+ # MSB
+ $bitmap_canvas create text $x0 $y0 -text [lindex $txt 0] \
+ -font $bitmap_n_font -anchor nw -justify left -fill $bit_addr_clr
+ incr x0 [expr {7 * ($rect_sep + $rect_size)}]
+ # LSB
+ $bitmap_canvas create text $x0 $y0 -text [lindex $txt 1] \
+ -font $bitmap_n_font -anchor nw -justify left -fill $bit_addr_clr
+ incr x0 [expr {$rect_sep + $rect_size + $reg_sep}]
+ }
+ # Register addresses
+ set x0 [expr {$bm_x_org + 4 * ($rect_sep + $rect_size)}]
+ foreach txt {23 22 21 20} {
+ $bitmap_canvas create text $x0 $y0 -text $txt \
+ -font $bitmap_b_font -anchor n -justify center -fill $reg_addr_clr
+ incr x0 [expr {8 * ($rect_sep + $rect_size) + $reg_sep}]
+ }
+
+ ## Create top horizonal header
+ set y0 $bm_y_org
+ # Bit addresses
+ set x0 $bm_x_org
+ foreach txt {{7F 78} {77 70} {6F 68} {67 60}} {
+ # MSB
+ $bitmap_canvas create text $x0 $y0 -text [lindex $txt 0] \
+ -font $bitmap_n_font -anchor sw -justify left -fill $bit_addr_clr
+ incr x0 [expr {7 * ($rect_sep + $rect_size)}]
+ # LSB
+ $bitmap_canvas create text $x0 $y0 -text [lindex $txt 1] \
+ -font $bitmap_n_font -anchor sw -justify left -fill $bit_addr_clr
+ incr x0 [expr {$rect_sep + $rect_size + $reg_sep}]
+ }
+ # Register addresses
+ set x0 [expr {$bm_x_org + 4 * ($rect_sep + $rect_size)}]
+ foreach txt {2F 2E 2D 2C} {
+ $bitmap_canvas create text $x0 $y0 -text $txt \
+ -font $bitmap_b_font -anchor s -justify center -fill $reg_addr_clr
+ incr x0 [expr {8 * ($rect_sep + $rect_size) + $reg_sep}]
+ }
+
+ ## Create left vertical header
+ # Bit addresses
+ set y0 $bm_y_org
+ set x0 [expr {$bm_x_org - 4}]
+ foreach txt {7F 5F 3F 1F} {
+ $bitmap_canvas create text $x0 $y0 -text $txt \
+ -font $bitmap_n_font -anchor ne -justify right \
+ -fill $bit_addr_clr
+ incr y0 $rect_size
+ incr y0 $row_sep
+ }
+ # Register addresses
+ set y0 $bm_y_org
+ set x0 [expr {$bm_x_org - 25}]
+ foreach txt {2F 2B 27 23} {
+ $bitmap_canvas create text $x0 $y0 -text $txt \
+ -font $bitmap_b_font -anchor ne -justify left \
+ -fill $reg_addr_clr
+ incr y0 $rect_size
+ incr y0 $row_sep
+ }
+
+ ## Create right vertical header
+ # Bit addresses
+ set y0 $bm_y_org
+ set x0 [expr {$bm_x_org + 32 * ($rect_sep + $rect_size) + 4 * $reg_sep}]
+ foreach txt {60 40 20 00} {
+ $bitmap_canvas create text $x0 $y0 -text $txt \
+ -font $bitmap_n_font -anchor nw -justify left \
+ -fill $bit_addr_clr
+ incr y0 $rect_size
+ incr y0 $row_sep
+ }
+ # Register addresses
+ set y0 $bm_y_org
+ set x0 [expr {$bm_x_org + 32 * ($rect_sep + $rect_size) + 4 * $reg_sep + 18}]
+ foreach txt {2C 28 24 20} {
+ $bitmap_canvas create text $x0 $y0 -text $txt \
+ -font $bitmap_b_font -anchor nw -justify left \
+ -fill $reg_addr_clr
+ incr y0 $rect_size
+ incr y0 $row_sep
+ }
+
+
+ # ----------------------------------------------------------------
+ # Create bottom frame
+ # ----------------------------------------------------------------
+
+ set bottom_frame [frame $main_frame.bottom_frame]
+ set bottom_left_frame [frame $bottom_frame.left_frame]
+ set bottom_right_frame [frame $bottom_frame.right_frame]
+
+ ## Create legend
+ # Log. 0
+ set frame [frame $bottom_left_frame.frm_0]
+ pack [label $frame.lg0_lbl \
+ -text [mc "Log. 0"] \
+ ] -side left
+ pack [label $frame.lg0_frm \
+ -bg {#FF0000} -width 3 \
+ -bd 1 -relief raised \
+ -height 1 \
+ ] -side left -pady 2
+ pack $frame -side left -padx 5
+ # Log. 1
+ set frame [frame $bottom_left_frame.frm_1]
+ pack [label $frame.lg0_lbl \
+ -text [mc "Log. 1"] \
+ ] -side left
+ pack [label $frame.lg0_frm \
+ -bg {#00FF00} -width 3 \
+ -bd 1 -relief raised \
+ -height 1 \
+ ] -side left -pady 2
+ pack $frame -side left -padx 5
+ # Bit addr.
+ set frame [frame $bottom_left_frame.frm_2]
+ pack [label $frame.bit_lbl \
+ -text [mc "Bit addr."] \
+ ] -side left
+ pack [label $frame.bit_frm \
+ -bg $bit_addr_clr \
+ -width 3 -height 1 \
+ -bd 1 -relief raised \
+ ] -side left -pady 2
+ pack $frame -side left -padx 5
+ # Reg. addr.
+ set frame [frame $bottom_left_frame.frm_3]
+ pack [label $frame.reg_lbl \
+ -text [mc "Reg. addr."] \
+ ] -side left
+ pack [label $frame.reg_frm \
+ -bg $reg_addr_clr \
+ -width 3 -height 1 \
+ -bd 1 -relief raised \
+ ] -side left -pady 2
+ pack $frame -side left -padx 5
+
+ ## Create address meters
+ # Register address
+ pack [label $bottom_right_frame.reg_n_lbl -text [mc "Register: "] -fg {#888888}] -side left
+ set reg_addr_lbl [label $bottom_right_frame.reg_addr_lbl \
+ -width 4 -fg $reg_addr_clr -text { -- } \
+ ]
+ # Bit address
+ pack $reg_addr_lbl -side left
+ pack [label $bottom_right_frame.bit_n_lbl -text [mc " Bit address: "] -fg {#888888}] -side left
+ set bit_addr_lbl [label $bottom_right_frame.bit_addr_lbl \
+ -width 4 -fg $bit_addr_clr -text { -- } \
+ ]
+ pack $bit_addr_lbl -side left
+
+ # Pack parts of bottom frame
+ pack $bottom_left_frame -side left
+ pack $bottom_right_frame -side right
+
+ # ----------------------------------------------------------------
+ # Finalize
+ # ----------------------------------------------------------------
+
+ # Pack main parts of the window
+ pack $bitmap_canvas
+ pack $bottom_frame -fill x -side bottom
+ pack $main_frame -fill both -expand 1
+
+ # Set window parameters
+ wm protocol $win WM_DELETE_WINDOW "$this bitmap_close_dialog"
+ wm resizable $win 0 0
+ wm title $win [mc "Bit addressable area - %s - %s" [string trim $this {:}] "MCU 8051 IDE"]
+ wm iconphoto $win ::ICONS::16::kcmmemory_BA
+ catch {
+ wm geometry $win $win_geometry
+ }
+ bindtags $win [list $win Toplevel all .]
+
+ # Set flag dialog opened
+ set dialog_opened 1
+
+ # Synchronize with simulator engine
+ for {set i 32} {$i < 48} {incr i} {
+ bitmap_sync $i
+ }
+ bitmap_clear_hg
+ }
+
+ ## Bit rectangle event handler for event <Enter>
+ # @parm Int addr - Register address
+ # @return void
+ public method bitmap_bit_enter {addr} {
+ # Determinate new rectangle outline and fill colors
+ if {$bits_states($addr)} {
+ set outline $one_a_outline
+ set fill $one_a_fill
+ } {
+ set outline $zero_a_outline
+ set fill $zero_a_fill
+ }
+ # Set new rectangle colors and changle cursor
+ if {$enabled} {
+ $bitmap_canvas itemconfigure $bits($addr) -outline $outline -fill $fill
+ $bitmap_canvas configure -cursor hand1
+ }
+
+ ## Adjust address meters
+ # Bit address
+ set hex_addr [format %X $addr]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ }
+ set hex_addr "0x$hex_addr"
+ $bit_addr_lbl configure -text $hex_addr
+ # Register address
+ set hex_addr [format %X [expr {$addr / 8 + 32}]]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ }
+ set hex_addr "0x$hex_addr"
+ $reg_addr_lbl configure -text $hex_addr
+ }
+
+ ## Bit rectangle event handler for event <Leave>
+ # @parm Int addr - Register address
+ # @return void
+ public method bitmap_bit_leave {addr} {
+ # Determinate new rectangle outline and fill colors
+ if {$bits_states($addr)} {
+ set outline $one_outline
+ set fill $one_fill
+ } {
+ set outline $zero_outline
+ set fill $zero_fill
+ }
+
+ # Adjust address meters
+ $bit_addr_lbl configure -text { -- }
+ $reg_addr_lbl configure -text { -- }
+
+ # Set new rectangle colors
+ $bitmap_canvas itemconfigure $bits($addr) -outline $outline -fill $fill
+ $bitmap_canvas configure -cursor left_ptr
+ }
+
+ ## Bit rectangle event handler for event <Button-1>
+ # Invert bit value
+ # @parm Int addr - Register address
+ # @return void
+ public method bitmap_bit_click {addr} {
+ # Dialog must be enabled to perform this operation
+ if {!$enabled} {
+ return
+ }
+
+ # Disable this procedure
+ set sync_ena 0
+
+ # Invert bit value and adjust color
+ set bits_states($addr) [expr {!$bits_states($addr)}]
+ bitmap_bit_enter $addr
+
+ ## Synchronize with simulator engine
+ # Determinate register value
+ set bit_addr [expr {($addr / 8) * 8}]
+ set reg_addr [expr {$addr / 8 + 32}]
+ set reg_val 0
+ set mask 1
+ for {set i 0} {$i < 8} {incr i} {
+ if {$bits_states($bit_addr)} {
+ incr reg_val $mask
+ }
+
+ set mask [expr {$mask << 1}]
+ incr bit_addr
+ }
+ # Synchronize
+ $this setDataDEC $reg_addr $reg_val
+ $this Simulator_sync_reg $reg_addr
+
+ # Enable this procedure
+ set sync_ena 1
+ }
+
+ ## Synchronize with simulator engine (data are taken from the engine)
+ # @parm Int reg_addr - Register address (meaningfull are values from 32 to 47)
+ # @return void
+ public method bitmap_sync {reg_addr} {
+ # Check if this procedure can be done
+ if {!$dialog_opened} {return}
+ if {!$sync_ena} {return}
+ if {$reg_addr < 32 || $reg_addr > 47} {
+ return
+ }
+
+ # Determinate LSB address and rehister address
+ set reg_val [$this getDataDEC $reg_addr]
+ set bit_addr [expr {($reg_addr - 32) * 8}]
+
+ # Synchronize
+ set mask 1
+ for {set i 0} {$i < 8} {incr i} {
+ # Adjust bit value in bitmap
+ set original_val $bits_states($bit_addr)
+ set bits_states($bit_addr) [expr {$mask & $reg_val}]
+
+ # Adjust rectangle colors if bit was changed
+ if {$original_val != $bits_states($bit_addr)} {
+ if {$bits_states($bit_addr)} {
+ set fill $one_fill
+ } {
+ set fill $zero_fill
+ }
+
+ $bitmap_canvas itemconfigure $bits($bit_addr) \
+ -outline {#000000} -fill $fill
+ }
+
+ # Adjust bit address and bit mask
+ incr bit_addr
+ set mask [expr {$mask << 1}]
+ }
+ }
+
+ ## Clear highlight of changed cells
+ # @return void
+ public method bitmap_clear_hg {} {
+ if {!$dialog_opened} {return}
+ for {set i 0} {$i < 128} {incr i} {
+ if {$bits_states($i)} {
+ set outline $one_outline
+ } {
+ set outline $zero_outline
+ }
+ $bitmap_canvas itemconfigure $bits($i) -outline $outline
+ }
+ }
+}
+
diff --git a/lib/simulator/engine/engine_auxiliary_alo_functions.tcl b/lib/simulator/engine/engine_auxiliary_alo_functions.tcl
new file mode 100755
index 0000000..d73b57e
--- /dev/null
+++ b/lib/simulator/engine/engine_auxiliary_alo_functions.tcl
@@ -0,0 +1,171 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# AUXILIARY ALO FUNCTIONS
+# --------------------------------------------------------------------------
+
+## Generate random octet
+ # @return Int - random value in range 0..255
+private method undefined_octet {} {
+ switch -- ${::Simulator::undefined_value} {
+ 0 { ;# Return 0
+ return 0
+ }
+ 1 { ;# Return 255
+ return 255
+ }
+ 2 { ;# Return random value
+ set result [expr {int(rand() * 256)}]
+ if {$result == 256} {set result 255}
+ }
+ }
+ return $result
+}
+
+## Add value to accumulator and affect PSW flags
+ # @parm Int val - value to add
+ # @return void
+private method alo_add {val} {
+
+ # Adjust stepback stack
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+
+ # Local variables
+ set A_h [expr {($sfr(224) & 240) >> 4}] ;# High-order nibble of Acc
+ set A_l [expr {$sfr(224) & 15}] ;# Low-order nibble of Acc
+ set val_h [expr {($val & 0x1f0) >> 4}] ;# High-order nibble of val
+ set val_l [expr {$val & 15}] ;# Low-order nibble of val
+
+ # Compute low-order nibble of result
+ set result [expr {$val_l + $A_l}]
+
+ # Flag AC
+ if {$result > 15} {
+ incr val_h
+ incr result -16
+ setBit $symbol(AC) 1
+ } {
+ setBit $symbol(AC) 0
+ }
+
+ # Compute high-order nibble of result
+ incr result [expr {($val_h + $A_h) << 4}]
+
+ # Flag C
+ if {$result > 255} {
+ incr result -256
+ setBit $symbol(C) 1
+ } {
+ setBit $symbol(C) 0
+ }
+
+ # Flag OV
+ if {($val < 128) && ($sfr(224) < 128) && ($result > 127)} {
+ setBit $symbol(OV) 1
+ } elseif {($val > 127) && ($sfr(224) > 127) && ($result < 128)} {
+ setBit $symbol(OV) 1
+ } {
+ setBit $symbol(OV) 0
+ }
+
+ # Set Acc
+ set sfr(224) $result
+ evaluate_sfr 224
+}
+
+## Add value to accumulator with carry and affect PSW flags
+ # @parm Int val - value to add
+ # @return void
+private method alo_addc {val} {
+ if {[getBit $symbol(C)]} {
+ incr val
+ }
+ alo_add $val
+}
+
+## Subtract tegister from ACC with borrow and affect PSW flags
+ # @parm Int val - value to subtract
+ # @return void
+private method alo_subb {val} {
+
+ # Adjust stepback stack
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+
+ # Flag PSW.C
+ if {[getBit $symbol(C)]} {
+ incr val
+ }
+
+ # Local variables
+ set A_h [expr {($sfr(224) & 240) >> 4}] ;# High-order nibble of Acc
+ set A_l [expr {$sfr(224) & 15}] ;# Low-order nibble of Acc
+ set val_h [expr {($val & 0x1f0) >> 4}] ;# High-order nibble of val
+ set val_l [expr {$val & 15}] ;# Low-order nibble of val
+
+ # Compute low-order nibble of result
+ set result_l [expr {$A_l - $val_l}]
+
+ # Flag AC
+ if {$result_l < 0} {
+ incr result_l 16
+ incr val_h
+ setBit $symbol(AC) 1
+ } {
+ setBit $symbol(AC) 0
+ }
+
+ # Compute high-order nibble of result
+ set result_h [expr {$A_h - $val_h}]
+
+ # Flag C
+ if {$result_h < 0} {
+ incr result_h 16
+ setBit $symbol(C) 1
+ } {
+ setBit $symbol(C) 0
+ }
+
+ # Compute high-order nibble of result
+ set result [expr {($result_h << 4) + $result_l}]
+
+ # Flag OV
+ if {($val > 127) && ($sfr(224) < 128) && ($result > 127)} {
+ setBit $symbol(OV) 1
+ } elseif {($val < 128) && ($sfr(224) > 127) && ($result < 128)} {
+ setBit $symbol(OV) 1
+ } {
+ setBit $symbol(OV) 0
+ }
+
+ # Set Acc
+ set sfr(224) $result
+}
diff --git a/lib/simulator/engine/engine_backward_stepping.tcl b/lib/simulator/engine/engine_backward_stepping.tcl
new file mode 100755
index 0000000..f7e1b66
--- /dev/null
+++ b/lib/simulator/engine/engine_backward_stepping.tcl
@@ -0,0 +1,126 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# BACKWARD STEPPING RELATED PROCEDURES
+# --------------------------------------------------------------------------
+
+## Save current value of the given register for purpose of stepback operation
+ # This function does not check for address validity !
+ # @parm Char mem - Memory type (one of {I E X S P})
+ # @parm Int addr - Register address
+ # @return void
+private method stepback_reg_change {mem addr} {
+ if {!$stepback_ena} {return}
+ if {[lsearch $stepback_local_regs $addr] != -1} {
+ return
+ }
+ lappend stepback_local_regs $addr
+
+ switch -- $mem {
+ {I} {set val $ram($addr) }
+ {E} {set val $eram($addr) }
+ {X} {set val $xram($addr) }
+ {S} {set val $sfr($addr) }
+ {P} {set val $eeprom($addr) }
+ }
+ lappend stepback_local [list $mem $addr $val]
+}
+
+## Save local stepback stack to global stepback stack
+ # This function should be called after each instrucion
+ # @return void
+private method stepback_save_norm {} {
+ if {!$stepback_ena} {return}
+ lappend stepback_normal $stepback_local
+ set stepback_local_regs {}
+ set stepback_local {}
+}
+
+## Save special engine configuration variables for purpose of stepback operation
+ # This function should be called before each instrucion
+ # @return void
+private method stepback_save_spec {} {
+ if {!$stepback_ena} {return}
+ incr stepback_length
+ set discard [expr {$stepback_length - ${::Simulator::reverse_run_steps}}]
+ if {$discard > 0} {
+ incr stepback_length -$discard
+ set stepback_spec [lreplace $stepback_spec 0 0]
+ set stepback_normal [lreplace $stepback_normal 0 0]
+ }
+
+ lappend stepback_spec [simulator_get_special]
+}
+
+## Set the last list element in stepback to current time
+ # @return void
+private method stepback_save_spec_time {} {
+ lset stepback_spec {end end} $time
+}
+
+## Set "subprog" value for stepback function.
+ # This is important for list of subprograms and stack monitor
+ # @parm Int action -
+ # 6 - Instruction POP peformed
+ # 5 - Instruction PUSH performed
+ # 4 - Return from subprogram
+ # 3 - Return from interrupt routine
+ # 2 - Invocaton of subprogram
+ # 1 - Invocaton of interrupt
+ # 0 - Nothing mentioned above
+ # @return void
+private method stepback_save_spec_subprog {action} {
+ lset stepback_spec {end 0} $action
+}
+
+## Discard stack for stepback functions
+ # @return void
+public method stepback_discard_stack {} {
+ set stepback_local_regs {}
+ set stepback_normal {}
+ set stepback_spec {}
+ set stepback_local {}
+ set stepback_length 0
+}
+
+## Get stepback stack length
+ # @return Int - stack length
+public method simulator_get_SBS_len {} {
+ if {${::Simulator::reverse_run_steps}} {
+ return $stepback_length
+ } {
+ return 0
+ }
+}
+
+## Set stepback stack length
+ # @parm Int value - stack length
+ # @return void
+public method simulator_set_SBS_len {value} {
+ set stepback_length $value
+}
diff --git a/lib/simulator/engine/engine_control.tcl b/lib/simulator/engine/engine_control.tcl
new file mode 100755
index 0000000..efa00c9
--- /dev/null
+++ b/lib/simulator/engine/engine_control.tcl
@@ -0,0 +1,759 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# CONTROL PROCEDURES
+# --------------------------------------------------------------------------
+
+
+## Force return from subprogram or interrupt handler
+ # @parm Bool intr__sub - 1 == Interrupt; 0 == subprogram
+ # @retunr void
+public method simulator_return_from_SP {intr__sub} {
+ if {$intr__sub} {
+ simulator_cancel_interrupt [lindex $inter_in_p_flags end]
+ } {
+ ins_ret
+ $this move_simulator_line $Line($pc)
+ }
+}
+
+## Resize external data memory
+ # Warning: This functon is unsafe
+ # @parm Int new_size - New memory size
+ # @return void
+public method simulator_resize_xdata_memory {new_size} {
+ # Shrink memory
+ if {$xram_size > $new_size} {
+ if {!$new_size} {
+ array unset xram
+ }
+
+ # Expand memory
+ } elseif {$xram_size < $new_size} {
+ for {set i $xram_size} {$i < $new_size} {incr i} {
+ set xram($i) 0
+ }
+ }
+
+ set xram_size $new_size
+}
+
+## Resize program memory
+ # Warning: This functon is unsafe
+ # @parm Int new_size - New memory size
+ # @return void
+public method simulator_resize_code_memory {new_size} {
+ set new_size [expr {int($new_size)}]
+
+ # Shrink memory
+ if {$code_size > $new_size} {
+ if {!$new_size} {
+ array unset code
+ }
+
+ # Expand memory
+ } elseif {$code_size < $new_size} {
+ for {set i $code_size} {$i < $new_size} {incr i} {
+ set code($i) 0
+ }
+ }
+
+ set code_size $new_size
+}
+
+## Get list of decimal address of implemented SFR
+ # @return List - Implemented special function registers
+public method simulator_get_avaliable_sfr {} {
+ return $avaliable_sfr
+}
+
+## Determinate whether the specified SFR is avaliable on the target MCU or not
+ # @parm Int sfr_addr - Address of SFR register
+ # @return Bool - 1 == Avaliable; 0 == Not avaliable
+public method simulator_is_sfr_avaliable {sfr_addr} {
+ if {[lsearch -ascii -exact $avaliable_sfr $sfr_addr] == -1} {
+ return 0
+ } {
+ return 1
+ }
+}
+
+## Reset counter of overall program time
+ # @return void
+public method simulator_clear_overall_time {} {
+ set overall_time 0
+ set overall_instructions 0
+}
+
+## Reset vitrual processor
+ # @parm String mode - Reset mode:
+ # '-' == no change (IRAM, ERAM and XRAM)
+ # '0' == all zeroes (IRAM, ERAM and XRAM)
+ # '1' == all ones (IRAM, ERAM and XRAM)
+ # 'r' == random values (IRAM, ERAM and XRAM)
+ # @return void
+public method master_reset {mode} {
+ set break 1 ;# Terminate running program
+ set pc 0 ;# Reset program counter
+ set bank 0 ;# Reset active register bank
+
+ # Reset controllers configurations
+ set controllers_conf(WatchDogTimer) 0 ;# Stop Watchdog Timer
+ set controllers_conf(SM0) 0 ;# UART mode bit 0
+ set controllers_conf(FE) 0 ;# UART frame error flag bit
+ if {$eeprom_size} {
+ simulator_cancel_write_to_eeprom
+ catch {
+ $this sim_GUI_bit_set_clear 1 EECON RDYBSY
+ }
+ }
+
+ # Reset engine configurations
+ set DPL {DP0L} ;# Select DTPR0
+ set DPH {DP0H} ;# Select DTPR0
+ set hidden_DPTR0 {0 0} ;# Value of DPTR0 (if dual DPTR is hidden)
+ set hidden_DPTR1 {0 0} ;# Value of DPTR1 (if dual DPTR is hidden)
+ set idle_mode 0 ;# Normal mode (not IDLE)
+ set timer_0_running 0 ;# Bool: Timer/Counter 0 engaged
+ set timer_1_running 0 ;# Bool: Timer/Counter 1 engaged
+ set timer_2_running 0 ;# Bool: Timer/Counter 2 engaged
+ set pwm_running 0 ;# Bool: PWM controller engaged (uses Timer/Counter 0 & 1)
+ set wdt_prescaler_val 0 ;# Int: Value of Watchdog prescaler
+ set watchdog_value 0 ;# Int: Value of watchdog timer
+ set eeprom_WR 0 ;# Bool: Data EEPROM write cycle in progress
+
+ simulator_Sbar {} 0 $this ;# Clear simulator status bar
+ set interrupt_on_next 0 ;# Bool: Engage interrupt routine on the next instruction cycle
+ set interrupts_in_progress {} ;# Priority flags of interrupts which are in progress
+ set inter_in_p_flags {} ;# Interrupt flags of interrupts which are in progress
+
+ switch -- $mode {
+ - { ;# no changes
+ }
+ 0 { ;# all zeroes
+ for {set i 0} {$i < $iram_size} {incr i} {
+ set ram($i) 0
+ }
+ for {set i 0} {$i < $eram_size} {incr i} {
+ set eram($i) 0
+ }
+ update
+ for {set i 0} {$i < $xram_size} {incr i} {
+ set xram($i) 0
+ }
+ }
+ 1 { ;# all ones
+ for {set i 0} {$i < $iram_size} {incr i} {
+ set ram($i) 255
+ }
+ for {set i 0} {$i < $eram_size} {incr i} {
+ set eram($i) 255
+ }
+ update
+ for {set i 0} {$i < $xram_size} {incr i} {
+ set xram($i) 255
+ }
+ }
+ r { ;# random values
+ for {set i 0} {$i < $iram_size} {incr i} {
+ set ram($i) [expr {int(rand() * 256)}]
+ }
+ for {set i 0} {$i < $eram_size} {incr i} {
+ set eram($i) [expr {int(rand() * 256)}]
+ }
+ update
+ for {set i 0} {$i < $xram_size} {incr i} {
+ set xram($i) [expr {int(rand() * 256)}]
+ }
+ }
+ }
+
+ # Make backup copy of all SFR for purpose of stepback function
+ foreach addr [array names sfr] {
+ stepback_reg_change S $addr
+ }
+
+ # Set port states
+ set ports_previous_state {255 255 255 255 255}
+
+ # Set SFR to defaults
+ foreach reg $reset_reg_values {
+ set sfr($symbol([lindex $reg 0])) [lindex $reg 1]
+ }
+ foreach item $reset_reg_values_1 {
+ set reg [lindex $item 0]
+ switch -- $reg {
+ {T2CON} {if {!$feature_avaliable(t2)} {continue}}
+ {RCAP2L} {if {!$feature_avaliable(t2)} {continue}}
+ {RCAP2H} {if {!$feature_avaliable(t2)} {continue}}
+ {TL2} {if {!$feature_avaliable(t2)} {continue}}
+ {TH2} {if {!$feature_avaliable(t2)} {continue}}
+ {T2MOD} {if {!$feature_avaliable(t2mod)} {continue}}
+ {AUXR} {if {!$feature_avaliable(auxr)} {continue}}
+ {SCON} {if {!$feature_avaliable(uart)} {continue}}
+ {P0} {if {!$feature_avaliable(p0)} {continue}}
+ {P1} {if {!$feature_avaliable(p1)} {continue}}
+ {P2} {if {!$feature_avaliable(p2)} {continue}}
+ {P3} {if {!$feature_avaliable(p3)} {continue}}
+ {P4} {if {!$feature_avaliable(p4)} {continue}}
+ {ACSR} {if {!$feature_avaliable(acomparator)} {continue}}
+ {SADEN} {if {!$feature_avaliable(euart)} {continue}}
+ {SADDR} {if {!$feature_avaliable(euart)} {continue}}
+ {IPH} {if {!$feature_avaliable(iph)} {continue}}
+ {WDTCON} {if {!$feature_avaliable(wdtcon)} {continue}}
+ {EECON} {if {!$eeprom_size} {continue}}
+ {SPCR} {if {!$feature_avaliable(spi)} {continue}}
+ {SPSR} {if {!$feature_avaliable(spi)} {continue}}
+ {DP1H} {
+ if {!$feature_avaliable(ddp) || $feature_avaliable(hddptr)} {
+ continue
+ }
+ }
+ {DP1L} {
+ if {!$feature_avaliable(ddp) || $feature_avaliable(hddptr)} {
+ continue
+ }
+ }
+ {CLKREG} {
+ if {!$feature_avaliable(clkreg) && !$feature_avaliable(ckcon)} {
+ continue
+ }
+ }
+ {AUXR1} {
+ if {!$feature_avaliable(ddp) || $feature_avaliable(wdtcon)} {
+ continue
+ }
+ }
+
+ default {continue}
+ }
+ set sfr($symbol($reg)) [lindex $item 1]
+ }
+
+ # Restore bits which are not affected by reset
+ if {$feature_avaliable(pof) && $controllers_conf(POF)} {
+ set sfr($symbol(PCON)) [expr {$sfr($symbol(PCON)) | 16}]
+ }
+ if {$feature_avaliable(x2reset) && $controllers_conf(X2)} {
+ set sfr($symbol(CLKREG)) [expr {$sfr($symbol(CLKREG)) | 1}]
+ }
+
+ # Reevaluate internal configuration flags
+ set sync_ena 0
+ foreach addr [array names sfr] {
+ evaluate_sfr $addr
+ }
+
+ # Reset program run statistics
+ for {set i 0} {$i < 10} {incr i} {
+ set run_statistics($i) 0
+ }
+
+ # Synchronize with special GUI controls
+ $this simulator_GUI_cancel_write_to_eeprom ;# Abort data EEPROM write cycle
+ $this interrupt_monitor_reset ;# Reset interrupt monitor
+ $this subprograms_clear ;# Clear list subprograms
+ $this stopwatch_refresh ;# Stopwatch
+ $this stack_monitor_reset ;# clear stack monitor
+
+ # Reset PALE (Peripheral Astraction Layer Engine)
+ $this pale_reset
+ for {set i 0} {$i < 5} {incr i} {
+ set j 0
+ foreach bit [split $feature_avaliable(port$i) {}] {
+ if {$bit == 0} {
+ $this pale_SLSF [list $i $j] 6
+ }
+ incr j
+ }
+ }
+
+ # Allow engagement
+ set break 0
+}
+
+## Step program back
+ # @return Bool - false if no more backward steps can be done
+public method stepback {} {
+ if {!${::Simulator::reverse_run_steps} || !$stepback_length} {
+ return 0
+ }
+ set sync_ena 1
+ incr stepback_length -1
+
+ set lst [lindex $stepback_normal $stepback_length]
+ set max [llength $lst]
+ incr max -1
+
+ for {set i $max} {$i >= 0} {incr i -1} {
+ set item [lindex $lst $i]
+ set addr [lindex $item 1]
+ set val [lindex $item 2]
+
+ switch -- [lindex $item 0] {
+ {I} {
+ set ram($addr) $val
+ $this Simulator_sync_reg $addr
+ }
+ {E} {
+ set eram($addr) $val
+ $this Simulator_XDATA_sync $addr
+ }
+ {P} {
+ set eeprom($addr) $val
+ ::X::sync_eeprom_mem_window [format %X $addr] 0 $this
+ }
+ {X} {
+ set xram($addr) $val
+ $this Simulator_XDATA_sync $addr
+ }
+ {S} {
+ set sfr($addr) $val
+ evaluate_sfr $addr
+ }
+ }
+ }
+
+ set overall_instructions_org $overall_instructions
+ set overall_time_org $overall_time
+ simulator_set_special [lindex $stepback_spec $stepback_length]
+
+ set opcode [getCode $pc]
+ if {[lsearch ${CompilerConsts::defined_OPCODE} $opcode] == -1} {
+ incr run_statistics(4) -1
+ } {
+ incr run_statistics(4) -[lindex $CompilerConsts::Opcode($opcode) 2]
+ }
+
+ incr run_statistics(0) [expr {int(($overall_time - $overall_time_org) * (12000000.0 / $clock_kHz))}]
+ incr run_statistics(1) [expr {int($overall_time - $overall_time_org) * 12}]
+ incr run_statistics(2) [expr {int($overall_instructions - $overall_instructions_org)}]
+ incr run_statistics(3) -1
+
+ switch -- [lindex $stepback_spec [list $stepback_length 0]] {
+ 6 { ;# Instruction POP peformed
+ $this stack_monitor_push $sfr(129) $ram($sfr(129))
+ $this stack_monitor_set_last_values_as 0 1
+ }
+ 5 { ;# Instruction PUSH peformed
+ $this stack_monitor_pop
+ }
+ 4 { ;# Invocaton of subprogram
+ incr run_statistics(7) -1
+ $this subprograms_call 3 [expr {($ram([expr {$sfr(129) - 1}]) << 8) + $ram($sfr(129))}] -1
+
+ $this stack_monitor_push [expr {$sfr(129) - 1}] $ram([expr {$sfr(129) - 1}])
+ $this stack_monitor_push $sfr(129) $ram($sfr(129))
+ $this stack_monitor_set_last_values_as 1 2
+ }
+ 3 { ;# Invocaton from interrupt routine
+ incr run_statistics(8) -1
+ $this subprograms_call 2 [expr {($ram([expr {$sfr(129) - 1}]) << 8) + $ram($sfr(129))}] -1
+
+ $this stack_monitor_push [expr {$sfr(129) - 1}] $ram([expr {$sfr(129) - 1}])
+ $this stack_monitor_push $sfr(129) $ram($sfr(129))
+ $this stack_monitor_set_last_values_as 2 2
+ }
+ 2 { ;# Return from subprogram
+ incr run_statistics(6) -1
+ $this subprograms_return 0
+
+ $this stack_monitor_pop
+ $this stack_monitor_pop
+ }
+ 1 { ;# Return from an interrupt
+ incr run_statistics(5) -1
+ $this subprograms_return 1
+
+ $this stack_monitor_pop
+ $this stack_monitor_pop
+ }
+ }
+ if {[llength $interrupts_in_progress]} {
+ simulator_Sbar [mc "Interrupt at vector 0x%s " [format %X [intr2vector [lindex $interrupts_in_progress end]]]] 1 $this
+ } {
+ simulator_Sbar {} 0 $this
+ }
+ $this graph_stepback [expr {int(($overall_time_org - $overall_time) * 2)}]
+ $this interrupt_monitor_reevaluate
+ $this stopwatch_refresh
+ if {$eeprom_size} {
+ for {set i 0} {$i < 32} {incr i} {
+ ::X::sync_eeprom_write_buffer $i $this
+ }
+ ::X::eeprom_write_buffer_set_offset $eeprom_WR_ofs $this
+ }
+
+ if {$eeprom_WR} {
+ eeprom_controller [expr {int(($overall_time_org - $overall_time) * (-2))}]
+ } {
+ foreach reg $eeprom_prev {
+ ::X::sync_eeprom_clear_bg_hg [lindex $reg 0] $this
+ }
+ $this simulator_GUI_cancel_write_to_eeprom
+ }
+
+ $this Simulator_sync_PC_etc
+
+ set stepback_spec [lreplace $stepback_spec end end]
+ set stepback_normal [lreplace $stepback_normal end end]
+
+ $this Simulator_GUI_sync S 224
+ if {!$stepback_length} {
+ return 0
+ } {
+ return 1
+ }
+}
+
+## Engage mode "Step"
+ # @return Int - line in source code
+public method step {} {
+ set address_error 0
+
+ # Valid OP code
+ if {[check_address_validity C $pc]} {return {}}
+ if {$code($pc) != {}} {
+ set sync_ena 1 ;# Enable synchronization
+ instruction_cycle ;# Execute instruction
+
+ # Synchronize
+ $this Simulator_GUI_sync S 208
+ # Return line number
+ update
+ return $Line($pc)
+
+ # Invalid OP code
+ } {
+ bell
+ $this sim_txt_output [mc "No instruction found at 0x%s" [NumSystem::dec2hex $pc]]
+ incr_pc 1
+ return {}
+ }
+}
+
+## Engage/Disengage mode "Step over"
+ # @return Int - line in source code
+public method sim_stepover {} {
+ set address_error 0
+
+ # Disengage
+ if {$simulation_in_progress} {
+ set break 1
+ set simulation_in_progress 0
+ set stepover_in_progress 0
+
+ # Engage
+ } {
+ # Local variables
+ set current_line 0 ;# Current line in source code
+ set stepover_in_progress 1 ;# Bool: "Step over" mode flag
+ set simulation_in_progress 1 ;# Bool: Simulator engaged
+ set ::X::critical_procedure_in_progress 0
+
+ # Valid OP code
+ set tmp_pc 0
+ if {[check_address_validity C $pc]} {
+ set simulation_in_progress 0
+ set stepover_in_progress 0
+ return {}
+ }
+ if {$code($pc) != {}} {
+ set sync_ena 1 ;# Enable synchronization
+
+ while 1 {
+ # Conditionaly abort simulation
+ if {$break} {
+ set break 0
+ set ::X::critical_procedure_in_progress 0
+ set simulation_in_progress 0
+ set stepover_in_progress 0
+ break
+ }
+
+ # Abort simulation on invalid OP code
+ if {[check_address_validity C $pc]} {
+ set simulation_in_progress 0
+ set stepover_in_progress 0
+ break
+ }
+ if {$code($pc) == {}} {
+ incr_pc 1
+ bell
+ $this sim_txt_output [mc "No instruction found at 0x%s" [NumSystem::dec2hex $pc]]
+ set simulation_in_progress 0
+ set stepover_in_progress 0
+ break
+ }
+
+ # Execute instruction
+ set current_line [lindex $Line($pc) 0]
+ instruction_cycle
+ if {[lindex $Line($pc) 0] != {} && [lindex $Line($pc) 0] != $current_line} {
+ break
+ }
+
+ # Synchronize and update GUI
+ $this Simulator_sync_PC_etc
+ update
+ }
+
+ if {$break} {
+ set break 0
+ set ::X::critical_procedure_in_progress 0
+ }
+
+ # Reset flags
+ set simulation_in_progress 0 ;# Simulator engaged
+ set stepover_in_progress 0 ;# Mode "Step over" engaged
+
+ # Return line
+ return $Line($pc)
+
+ # No OP code
+ } {
+ incr_pc 1
+ bell
+ $this sim_txt_output [mc "No instruction found at 0x%s" [NumSystem::dec2hex $pc]]
+ set simulation_in_progress 0
+ set stepover_in_progress 0
+ return {}
+ }
+ }
+}
+
+## Engage/Disengage mode "Run"
+ # @return Int - line in source code
+public method sim_run {} {
+ set address_error 0
+
+ # Local variables
+ set last_line [lindex $Line($pc) 0] ;# Line of the last instruction (line in source code)
+
+ # Disengage
+ if {$simulation_in_progress} {
+ set break 1 ;# Terminate running program
+ set simulation_in_progress 0 ;# Bool: Simulator engaged
+ set run_in_progress 0 ;# Bool: "Run" mode flag
+
+ # Engage
+ } {
+ set sync_ena 0 ;# Disabled synchronizations
+
+ # Local variables
+ set run_in_progress 1 ;# Bool: "Run" mode flag
+ set simulation_in_progress 1 ;# Bool: Simulator engaged
+ set idx 0 ;# Instruction index (GUI is updated after each 1000)
+ set ::X::critical_procedure_in_progress 0
+
+ # Infinitely execute program instructions until break
+ while 1 {
+ incr idx
+ # Conditionaly abort simulation
+ if {$break} {
+ set simulation_in_progress 0
+ set run_in_progress 0
+ set break 0
+ set ::X::critical_procedure_in_progress 0
+ break
+ }
+
+ # Empty OP code -> abort simulation
+ if {[check_address_validity C $pc]} {
+ set simulation_in_progress 0
+ set run_in_progress 0
+ break
+ }
+ if {$code($pc) == {}} {
+ set simulation_in_progress 0
+ set run_in_progress 0
+ bell
+ $this sim_txt_output [mc "No instruction found at 0x%s" [NumSystem::dec2hex $pc]]
+ break
+ }
+
+ # Execute instruction
+ instruction_cycle
+
+ # Run update command after each 25 instructions
+ if {!($idx % 25)} {
+ update
+ }
+ # Update GUI after each 100 instructions
+ if {$idx >= 100} {
+ set idx 0
+ $this Simulator_sync_PC_etc
+ update
+ }
+
+ # Handle breakpoints
+ if {[lindex $Line($pc) 0] != {}} {
+ set last_line [lindex $Line($pc) 0]
+ if {[lsearch $breakpoints([lindex $Line($pc) 1]) [lindex $last_line 0]] != -1} {
+ incr run_statistics(9)
+ if {$::CONFIG(BREAKPOINTS_ALLOWED)} {
+ set simulation_in_progress 0
+ set run_in_progress 0
+ Sbar [mc "Breakpoint reached at 0x%s" [NumSystem::dec2hex $pc]]
+ break
+ }
+ }
+ }
+ }
+
+ if {$break} {
+ set break 0
+ set ::X::critical_procedure_in_progress 0
+ }
+
+ # Return last line (line in source code)
+ return $Line($pc)
+ }
+}
+
+## Engage/Disengage mode "Animation"
+ # @return Int - line in source code
+public method sim_animate {} {
+ set address_error 0
+
+ # Disengage
+ if {$simulation_in_progress} {
+ set break 1 ;# Terminate running program
+ set simulation_in_progress 0 ;# Bool: Simulator engaged
+ set animation_in_progress 0 ;# Bool: "Animation" mode flag
+
+ # Engage
+ } {
+ set animation_in_progress 1 ;# Bool: "Animation" mode flag
+ set simulation_in_progress 1 ;# Bool: Simulator engaged
+ set ::X::critical_procedure_in_progress 0
+
+ # Infinitely execute program instructions until break
+ while 1 {
+ # Conditionaly abort simulation
+ if {$break} {
+ set simulation_in_progress 0
+ set animation_in_progress 0
+ set break 0
+ set ::X::critical_procedure_in_progress 0
+ break
+ }
+
+ # Perform program step
+ set lineNum [step]
+
+ if {$lineNum == {}} {
+ set simulation_in_progress 0
+ set animation_in_progress 0
+ break
+ }
+
+ # Move simulator line in the editor
+ $this move_simulator_line $lineNum
+ $this Simulator_sync_PC_etc
+
+ # Handle breakpoints
+ if {[string length [lindex $lineNum 0]] && [string length [lindex $lineNum 1]]} {
+ if {[lsearch $breakpoints([lindex $lineNum 1]) [lindex $lineNum 0]] != -1} {
+ incr run_statistics(9)
+ if {$::CONFIG(BREAKPOINTS_ALLOWED)} {
+ set simulation_in_progress 0
+ set animation_in_progress 0
+ Sbar [mc "Breakpoint reached at 0x%s" [NumSystem::dec2hex $pc]]
+ break
+ }
+ }
+ }
+
+ # Update GUI
+ update
+ }
+
+ if {$break} {
+ set break 0
+ set ::X::critical_procedure_in_progress 0
+ }
+ }
+}
+
+## Return true if the engine is engaged
+ # @return Bool - engaged flag
+public method sim_is_busy {} {
+ return $simulation_in_progress
+}
+
+## Return true if the engine is in mode "Step over"
+ # @return Bool - "Step over" flag
+public method sim_stepover_in_progress {} {
+ return $stepover_in_progress
+}
+
+## Return true if the engine is in mode "Run"
+ # @return Bool - "Run" flag
+public method sim_run_in_progress {} {
+ return $run_in_progress
+}
+
+## Return true if the engine is in mode "Animation"
+ # @return Bool - "Animation" flag
+public method sim_anim_in_progress {} {
+ return $animation_in_progress
+}
+
+## Disengage simulator (Power off the MCU)
+ # @return void
+public method Simulator_shutdown {} {
+ # Clear content of IDATA memory
+ for {set i 0} {$i < $iram_size} {incr i} {
+ set ram($i) 0
+ }
+
+ # Cancel EEPROM write process
+ if {$eeprom_WR} {
+ simulator_cancel_write_to_eeprom
+ }
+
+ # Discard stepback stack
+ stepback_discard_stack
+
+ set break 1
+}
+
+## Engage simulator (Power on the MCU)
+ # @return void
+public method Simulator_initiate {} {
+ set sync_ena 1
+ simulator_system_power_on
+ master_reset -
+
+ # Reset watchdog
+ set watchdog_value 0
+ set wdt_prescaler_val 0
+
+ set break 0
+}
diff --git a/lib/simulator/engine/engine_core.tcl b/lib/simulator/engine/engine_core.tcl
new file mode 100755
index 0000000..e974656
--- /dev/null
+++ b/lib/simulator/engine/engine_core.tcl
@@ -0,0 +1,274 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements virtual 8051 processor. This class is a part 8051 simulator.
+# But this file contains only simulator engine core.
+#
+# Class consist of the groups of procedures:
+# - Initialization & cleanup related procedures
+# - Control procedures
+# - External interface management procedures
+# - Virtual HW controller procedures
+# - Instruction procedures
+# - Opcode procedures
+# - Mcu configuration related procedures
+# - Auxiliary alo functions
+# - Memory management related procedures
+# - Backward stepping related procedures
+# --------------------------------------------------------------------------
+
+# --------------------------------------------------------------------------
+# Somilator engine was modified & fixed by Kostya V. Ivanov <kostya@istcom.spb.ru>
+#
+# Special thanks to Kostya V. Ivanov !
+# --------------------------------------------------------------------------
+
+# Load hibernation facility
+source "${::LIB_DIRNAME}/simulator/hibernate.tcl"
+
+class Simulator_ENGINE {
+
+ inherit Hibernate ;# Import hibernation facility
+
+ ## COMMON
+ common symbol ;# Array of SFR symbolic names (eg. $symbol(P0) == "80")
+ common DEBUG 1 ;# Turn on debugging
+ common PIN ;# Array describing pins with some special function
+ common PORT_LATCHES ;# List: Port latch registers
+
+ # Default values for SFR (values to set after reset)
+ common reset_reg_values {
+ {A 0} {B 0} {DP0L 0} {DP0H 0}
+ {IE 0} {IP 0} {PSW 0} {TCON 0}
+ {TMOD 0} {TH0 0} {TH1 0} {TL0 0}
+ {TL1 0} {PCON 0} {SP 7}
+ }
+ # Default values for special (uC dependend) SFR (values to set after reset)
+ common reset_reg_values_1 {
+ {T2CON 0} {T2MOD 0} {RCAP2L 0} {RCAP2H 0}
+ {TL2 0} {TH2 0} {AUXR1 0} {ACSR 0}
+ {AUXR 0} {P0 255} {P1 255} {P2 255}
+ {P3 255} {P4 255} {SCON 0} {DP1L 0}
+ {DP1H 0} {SADEN 0} {SADDR 0} {IPH 0}
+ {CLKREG 0} {WDTCON 0} {EECON 3} {SPCR 4}
+ {SPSR 0}
+ }
+
+ ## PUBLIC
+ public variable programming_language 0 ;# Int: ID of used programing language (0 == Assembler; 1 == C language)
+
+ ## PRIVATE
+ private variable breakpoints ;# Array of Lists of breakpoints (by line numbers) -- (eg '{1 45 399}')
+
+ private variable ram ;# Array of internal RAM; addr: 0..255; val: 0..255
+ private variable eram ;# Array of expanded RAM; addr: 0..4096; val: 0..255
+ private variable sfr ;# Array of SFR; addr: 128..255; val: 0..255
+ private variable xram ;# Array of external RAM; addr: 0..65535; val: 0..255
+ private variable code ;# Array of program memory; addr: 0..65535; val: 0..255
+ private variable eeprom ;# Array of data EEPROM; addr: 0..65535; val: 0..255
+ private variable iram_size ;# Capacity of internal data memory
+ private variable eram_size ;# Capacity of expanded data memory
+ private variable xram_size ;# Capacity of external data memory
+ private variable code_size ;# Capacity of program memory
+ private variable eeprom_size ;# Capacity of data EEPROM
+
+ private variable eeprom_prev {} ;# List: Previous values of EEPROM registers before write cycle ({{addr val} ...})
+ private variable eeprom_WR_ofs {} ;# Int: EEPROM write buffer offset (for EEPROM WB window only)
+ private variable eeprom_WR_buff ;# List: Data EEPROM write buffer for page mode; addr: 0..31; val: 0..255
+ private variable eeprom_WR 0 ;# Bool: Data EEPROM write cycle in progress
+ private variable eeprom_WR_time 0 ;# Float: Time of EEPROM write cycle (micro-seconds)
+
+ private variable Line ;# $Line($PC) == {line in source code} {filenumber} {level} {block}
+ private variable list_of_filenames ;# List of filenames for [lindex $Line($pc) 1]
+ private variable line2PC ;# $line2PC($line) == PC
+ private variable bank 0 ;# Current register bank (0..3)
+ private variable pc 0 ;# Program counter
+ private variable clock_kHz 0 ;# MCU clock in kHz
+ private variable time 0 ;# Number of instruction cycles consumed by current instruction
+ private variable sync_ena 0 ;# Bool: Enabled synchronization with an external interface
+ private variable address_error 0 ;# Bool: Addressing error occured
+
+ private variable break 0 ;# Bool: Immediately terminate the loaded program
+ private variable simulation_in_progress 0 ;# Bool: Engine is running
+ private variable run_in_progress 0 ;# Bool: Mode "Run" engaged
+ private variable animation_in_progress 0 ;# Bool: Mode "Animation" engaged
+ private variable stepover_in_progress 0 ;# Bool: Mode "Stepover" engaged
+ private variable ports_previous_state {} ;# List: {P0_hex P1_hex P2_hex P3_hex P4_hex}
+ private variable rmw_instruction 0 ;# Bool: This instruction is one of READ-MODIFY-WRITE ones
+
+ private variable avaliable_sfr {} ;# List: Addresses of implemented SFR
+ private variable feature_avaliable ;# Array: Avaliable features
+ private variable restricted_bits {} ;# List: Decimal addresses of unimplemented bits
+ private variable write_only_regs {} ;# List: Decimal addresses of write only registers
+ private variable incomplite_regs {} ;# List: Decimal addresses of not fully implemented registers
+ private variable incomplite_regs_mask ;# Array: key == dec. addr.; val == mask of implemented bits
+
+ private variable DPL {DP0L} ;# Address of current DPL register (DTPR)
+ private variable DPH {DP0H} ;# Address of current DPH register (DTPR)
+ private variable hidden_DPTR0 {0 0} ;# Value of DPTR0 (if dual DPTR is hidden)
+ private variable hidden_DPTR1 {0 0} ;# Value of DPTR1 (if dual DPTR is hidden)
+
+ private variable watchdog_value 0 ;# Int: Current value of watchdog timer (if avaliable)
+ private variable wdtrst_prev_val 0 ;# Int: Previous value of register WDTRST
+ private variable wdt_prescaler_val 0 ;# Int: Watchdog prescaler value (content)
+
+ private variable stepback_spec {} ;# List: List of special values (for function stepback)
+ private variable stepback_local {} ;# List: The same as stepback_normal but only for 1 instruction
+ private variable stepback_local_regs {} ;# List: Register addresses recorded in stepback_local
+ private variable stepback_ena 0 ;# Bool: Enable stepback
+ private variable stepback_length 0 ;# Int: Length of stepback stack
+ ## List: List of changed memory registers (for function stepback)
+ # Format: {{{MEM_TYPE ADDRESS VALUE} ...} ...}
+ # MEM_TYPE == E (Eram), X (XRAM), I (IRAM), S (SFR)
+ # ADDRESS == Decimal address
+ # VALUE == Decimal value
+ private variable stepback_normal {}
+
+ private variable interrupts_in_progress {} ;# List: Priority flags of interrupts which are in progress
+ private variable inter_in_p_flags {} ;# List: Interrupt flags of interrupts which are in progress
+ private variable interrupt_on_next 0 ;# Bool: Engage interrupt routine on the next instruction cycle
+ private variable skip_interrupt 0 ;# Bool: Last instruction was RETI or any access to the IE or IP
+ private variable interrupt_pri_flg {} ;# List: Interrupt flags in order of their priorities
+ private variable interrupt_pri_num {} ;# List: Interrup priorities levels in decremental order (by intr flags)
+
+ private variable timer_0_running 0 ;# Bool: Timer/Counter 0 engaged
+ private variable timer_1_running 0 ;# Bool: Timer/Counter 1 engaged
+ private variable timer_2_running 0 ;# Bool: Timer/Counter 2 engaged
+ private variable pwm_running 0 ;# Bool: PWM controller engaged (uses Timer/Counter 0 & 1)
+ private variable pwm_OCR 0 ;# Int: Content of OCR (8-bit data register)
+
+ private variable anlcmp_running 0 ;# Bool: Analog comparator is engaged
+ private variable anlcmp_output 0 ;# Bool: Output from Analog comparator
+ private variable anlcpm_db_timer 0 ;# Int: Analog comparator debounce timer
+
+ private variable uart_clock_prescaler 0 ;# Int: UART clock prescaler
+ private variable timer1_overflow 0 ;# Bool: Timer 1 overflow detected
+ private variable timer2_overflow 0 ;# Bool: Timer 2 overflow detected
+ private variable uart_RX_clock 0 ;# Int: UART 16-bit RX clock prescaler
+ private variable uart_TX_clock 0 ;# Int: UART 16-bit TX clock prescaler
+ private variable uart_RX_in_progress 0 ;# Bool: UART reception in progress
+ private variable uart_TX_in_progress 0 ;# Bool: UART transmission in progress
+ private variable uart_RX_shift_reg 0 ;# Int: UART reception receive register
+ private variable uart_TX_shift_reg 0 ;# Int: UART transmission receive register
+
+ private variable controllers_conf ;# Array of various internal configuration flags
+ private variable overall_time 0 ;# Overall program time in 1/CLOCK seconds
+ private variable overall_instructions 0 ;# Counter of instruction cycles
+
+ ## Array of Int: Program run statistics
+ # IDX - Meaning
+ # ---------------------------------
+ # 0 - Nano-seconds
+ # 1 - Clock cycles
+ # 2 - Instruction cycles
+ # 3 - Instructions passed
+ # 4 - Program bytes passed
+ # 5 - Interrupts invoked
+ # 6 - Subprogram calls
+ # 7 - Returns from subprogram
+ # 8 - Returns from interrupt
+ # 9 - Breakpoints reached
+ private variable run_statistics
+
+ # ----------------------------------------------------------------
+ # INITIALIZATION & CLEANUP RELATED PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_initialization_cleanup.tcl"
+
+
+ # ----------------------------------------------------------------
+ # CONTROL PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_control.tcl"
+
+
+ # ----------------------------------------------------------------
+ # EXTERNAL INTERFACE MANAGEMENT PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_external_interface_management.tcl"
+
+
+ # ----------------------------------------------------------------
+ # VIRTUAL HW CONTROLLER PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_virtual_hw_controller.tcl"
+
+
+ # ----------------------------------------------------------------
+ # INSTRUCTION PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_instructions.tcl"
+
+
+ # ----------------------------------------------------------------
+ # OPCODE PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_opcodes.tcl"
+
+
+ # ----------------------------------------------------------------
+ # MCU CONFIGURATION RELATED PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_mcu_configuration.tcl"
+
+
+ # ----------------------------------------------------------------
+ # AUXILIARY ALO FUNCTIONS
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_auxiliary_alo_functions.tcl"
+
+
+ # ----------------------------------------------------------------
+ # MEMORY MANAGEMENT RELATED PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_memory_management.tcl"
+
+
+ # ----------------------------------------------------------------
+ # BACKWARD STEPPING RELATED PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_backward_stepping.tcl"
+
+
+ # ----------------------------------------------------------------
+ # HIBERNATION RELATED PROCEDURES
+ # ----------------------------------------------------------------
+
+ source "${::LIB_DIRNAME}/simulator/engine/engine_hibernation.tcl"
+
+}
+
+# Initialize NS variables
+Simulator_ENGINE::InitializeNS
diff --git a/lib/simulator/engine/engine_external_interface_management.tcl b/lib/simulator/engine/engine_external_interface_management.tcl
new file mode 100755
index 0000000..30a5aed
--- /dev/null
+++ b/lib/simulator/engine/engine_external_interface_management.tcl
@@ -0,0 +1,1115 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# EXTERNAL INTERFACE MANAGEMENT PROCEDURES
+# --------------------------------------------------------------------------
+
+
+## Get value of bit SMOD0 in PCON if avaliable
+ # @return Bool - SMOD0 value (if unavaliable then 0)
+public method get_SMOD0 {} {
+ return $controllers_conf(SMOD0)
+}
+
+## Set value of bit FE in SCON if avaliable
+ # @param Bool value - New value for SCON.FE (or SCON.SM0 if FE is not avaliable)
+ # @return void
+public method sim_engine_set_FE {value} {
+ if {$feature_avaliable(smod0)} {
+ set controllers_conf(FE) $value
+ } {
+ sim_engine_set_SM0 $value
+ }
+}
+
+## Set value of bit SM0 in SCON
+ # @param Bool value - New value for PCON.SM0
+ # @return void
+public method sim_engine_set_SM0 {value} {
+ set controllers_conf(SM0) $value
+}
+
+## Get value of bit FE in SCON if avaliable
+ # @return Bool - FE value (if unavaliable then {})
+public method sim_engine_get_FE {} {
+ if {!$feature_avaliable(smod0)} {
+ return {}
+ } {
+ return $controllers_conf(FE)
+ }
+}
+
+## Get value of bit SM0 in SCON
+ # @return Bool - SM0 value
+public method sim_engine_get_SM0 {} {
+ return $controllers_conf(SM0)
+}
+
+## Get program run statistics
+ # @return List - Array run_statistics converted to list
+public method get_run_statistics {} {
+ return [array get run_statistics]
+}
+
+## Retrieve filename from list of files from which this program has been compiled
+ # @return String - Resulting relative filename or {}
+public method simulator_get_filename {filenumber} {
+ return [lindex $list_of_filenames $filenumber]
+}
+
+## Get list of files defined in debug file
+ # @return List - List of files
+public method simulator_get_list_of_filenames {} {
+ return $list_of_filenames
+}
+
+## Retrieve file number from list of files from which this program has been compiled
+ # @return Int - Resulting file number or -1
+public method simulator_get_filenumber {filename} {
+ return [lsearch -exact -ascii $list_of_filenames $filename]
+}
+
+## Get maximum valid interrupt priority level
+ # @return Int - 0..3
+public method simulator_get_max_intr_priority {} {
+ if {$feature_avaliable(iph)} {
+ return 3
+ } {
+ return 1
+ }
+}
+
+## Get current interrupt priority for certain interrupt
+ # @parm String flag - Interrupt flag (e.g. TF2)
+ # @return Int - 0..3
+public method simulator_get_interrupt_priority {flag} {
+ return [lindex $interrupt_pri_num [lsearch $interrupt_pri_flg $flag]]
+}
+
+## Invoke certain interrupt (from user interface)
+ # @parm String flag - Interrupt flag (e.g. CF)
+ # @return void
+public method simulator_invoke_interrupt {flag} {
+ if {[lsearch $inter_in_p_flags $flag] != -1} {
+ return
+ }
+
+ switch -- $flag {
+ {IE0} {set name PX0}
+ {TF0} {set name PT0}
+ {IE1} {set name PX1}
+ {TF1} {set name PT1}
+ {TF2} {set name PT2}
+ {EXF2} {set name PT2}
+ {SPIF} {set name PS}
+ {TI} {set name PS}
+ {RI} {set name PS}
+ {CF} {set name PC}
+ }
+ interrupt_handler $name [intr2vector $name] $flag 1
+ $this interrupt_monitor_intr $flag
+}
+
+## Increment interrupt priority for certain interrupt
+ # @parm String flag - Interrupt flag (e.g. CF)
+ # @return void
+public method simulator_incr_intr_priority {flag} {
+ set level [simulator_get_interrupt_priority $flag]
+ if {[simulator_get_max_intr_priority] <= $level} {
+ return
+ }
+ incr level
+ set_interrupt_priority_flag $flag $level
+}
+
+## Decrement interrupt priority for certain interrupt
+ # @parm String flag - Interrupt flag (e.g. IE0)
+ # @return void
+public method simulator_decr_intr_priority {flag} {
+ set level [simulator_get_interrupt_priority $flag]
+ if {!$level} {
+ return
+ }
+ incr level -1
+ set_interrupt_priority_flag $flag $level
+}
+
+## Set interrupt priority for certain interrupt
+ # Auxiliary procedure for procedures:
+ # "simulator_incr_intr_priority"
+ # "simulator_decr_intr_priority"
+ # @parm String flag - Interrupt flag (e.g. RI)
+ # @parm Int level - New priority level (0..3)
+ # @return void
+private method set_interrupt_priority_flag {flag level} {
+ # IP: - PC PT2 PS | PT1 PX1 PT0 PX0
+ switch -- $flag {
+ IE0 {set bit_mask 1}
+ TF0 {set bit_mask 2}
+ IE1 {set bit_mask 4}
+ TF1 {set bit_mask 8}
+ TI {set bit_mask 16}
+ RI {set bit_mask 16}
+ SPIF {set bit_mask 16}
+ TF2 {set bit_mask 32}
+ EXF2 {set bit_mask 32}
+ CF {set bit_mask 64}
+ default {
+ return
+ }
+ }
+
+ # Adjust register IPH
+ if {$feature_avaliable(iph)} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(IPH)
+ }
+
+ # Set priority bit
+ if {$level / 2} {
+ set sfr($symbol(IPH)) [expr $sfr($symbol(IPH)) | $bit_mask]
+ # Clear priority bit
+ } {
+ set sfr($symbol(IPH)) [expr $sfr($symbol(IPH)) & ($bit_mask ^ 255)]
+ }
+
+ # Adjust internal engine configuration
+ evaluate_sfr $symbol(IPH)
+ }
+
+ ## Adjust register IP
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(IP)
+ }
+ # Set priority bit
+ if {$level % 2} {
+ set sfr($symbol(IP)) [expr $sfr($symbol(IP)) | $bit_mask]
+ # Clear priority bit
+ } {
+ set sfr($symbol(IP)) [expr $sfr($symbol(IP)) & ($bit_mask ^ 255)]
+ }
+ # Adjust internal engine configuration
+ evaluate_sfr $symbol(IP)
+}
+
+## Clear certain interrupt flag
+ # @parm String flag - Interrupt flag (e.g. RI)
+ # @return void
+public method simulator_clear_intr_flag {flag} {
+ # Determinate register address and mask
+ switch -- $flag {
+ IE0 {
+ set addr 0x88 ;# TCON
+ set mask 0xFD ;# 0x02
+ }
+ IE1 {
+ set addr 0x88 ;# TCON
+ set mask 0xF7 ;# 0x20
+ }
+ TF0 {
+ set addr 0x88 ;# TCON
+ set mask 0xDF ;# 0x08
+ }
+ TF1 {
+ set addr 0x88 ;# TCON
+ set mask 0x7F ;# 0x80
+ }
+ TI {
+ set addr 0x98 ;# SCON
+ set mask 0xFD ;# 0x02
+ }
+ RI {
+ set addr 0x98 ;# SCON
+ set mask 0xFE ;# 0x01
+ }
+ SPIF {
+ set addr 0xAA ;# SPCR
+ set mask 0x7F ;# 0x80
+ }
+ TF2 {
+ set addr 0xC8 ;# T2CON
+ set mask 0x7F ;# 0x8F
+ }
+ EXF2 {
+ set addr 0xC8 ;# T2CON
+ set mask 0xBF ;# 0x40
+ }
+ CF {
+ set addr 0x97 ;# ACSR
+ set mask 0xEF ;# 0x10
+ }
+ default {
+ return
+ }
+ }
+
+ # Adjust register which contains the specified flag
+ set addr [expr "$addr"]
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $addr
+ }
+ set sfr($addr) [expr {$sfr($addr) & $mask}]
+
+ # Adjust internal engine configuration
+ evaluate_sfr $addr
+ $this interrupt_monitor_intr_flags [simulator_get_active_intr_flags]
+}
+
+## Force return from certain interrupt
+ # @parm String flag - Interrupt flag (e.g. RI)
+ # @return void
+public method simulator_cancel_interrupt {flag} {
+ set index [lsearch $inter_in_p_flags $flag]
+ if {$index == -1} {
+ return
+ }
+ set last [llength $inter_in_p_flags]
+ incr last -1
+
+ $this interrupt_monitor_reti [lindex $inter_in_p_flags $index]
+ set interrupts_in_progress [lreplace $interrupts_in_progress $index $index]
+ set inter_in_p_flags [lreplace $inter_in_p_flags $index $index]
+
+ if {$last != $index} {return}
+
+ incr run_statistics(8)
+ $this subprograms_return 1
+ if {[llength $interrupts_in_progress]} {
+ set vector [format %X [intr2vector [lindex $interrupts_in_progress end]]]
+ simulator_Sbar [mc "Interrupt at vector 0x%s " $vector] 1 $this
+ } {
+ simulator_Sbar {} 0 $this
+ }
+
+ set pch [stack_pop]
+ set pcl [stack_pop]
+
+ set pc [expr {($pch << 8) + $pcl}]
+ $this move_simulator_line $Line($pc)
+}
+
+## Get list of interrupt flags which are set
+ # @return List - List of active interrupt flags (e.g. {TF0 CF})
+public method simulator_get_active_intr_flags {} {
+ set result {}
+ foreach flag {IE0 TF0 IE1 TF1 TI RI SPIF TF2 EXF2 CF} {
+ if {$controllers_conf($flag)} {
+ lappend result $flag
+ }
+ }
+ return $result
+}
+
+## Get arguments for function "interrupt_monitor_intr_prior"
+ # Get list of possible interrupt flags in order of their priorities
+ # @return List - Interrupt flags in order of their priorities (decremental)
+public method simulator_get_intr_flags_with_priorities {} {
+ return $interrupt_pri_flg
+}
+
+## Get list of interrupt flags of interrupts which are in progress
+ # @return List - Interrupt flags
+public method simulator_get_interrupts_in_progress {} {
+ return $inter_in_p_flags
+}
+
+## Return list of interrupt priority bits of these intrerrupts which are currently in progress
+ # @return List - Priority bits
+public method simulator_get_interrupts_in_progress_pb {} {
+ return $interrupts_in_progress
+}
+
+## Get list of possible interrupt flags on this MCU
+ # @return List - Something like {IE0 TF0 IE1 TF1 RI TI CF}
+public method simulator_get_intr_flags {} {
+ set result {IE0 TF0 IE1 TF1}
+ if {$feature_avaliable(uart)} {lappend result RI TI}
+ if {$feature_avaliable(spi)} {lappend result SPIF}
+ if {$feature_avaliable(t2)} {lappend result TF2 EXF2}
+ if {$feature_avaliable(acomparator)} {lappend result CF}
+ return $result
+}
+
+## Get list of addresses in data EEPROM which are beeing written
+ # @return List - {dec_addr0 dec_addr1 ...}
+public method simulator_get_eeprom_beeing_written {} {
+ set result {}
+ foreach reg $eeprom_prev {
+ lappend result [lindex $reg 0]
+ }
+ return $result
+}
+
+## Cancel data EEPROM write cycle
+ # @return void
+public method simulator_cancel_write_to_eeprom {} {
+ if {!$eeprom_size || !$eeprom_WR} {return}
+
+ foreach reg $eeprom_prev {
+ set addr [lindex $reg 0]
+ stepback_reg_change P $addr
+ set eeprom($addr) [lindex $reg 1]
+ ::X::sync_eeprom_mem_window [format %X $addr] 0 $this
+ }
+ simulator_finalize_write_to_eeprom
+}
+
+## Finalize EEPROM write cycle
+ # @return void
+public method simulator_finalize_write_to_eeprom {} {
+ if {!$eeprom_size || !$eeprom_WR} {return}
+
+ # Clear background highlight in EEPROM hexeditor
+ foreach reg $eeprom_prev {
+ ::X::sync_eeprom_clear_bg_hg [lindex $reg 0] $this
+ }
+
+ # Adjust engine configuration
+ $this simulator_GUI_cancel_write_to_eeprom
+ set eeprom_WR 0
+ set eeprom_WR_time 0
+ set eeprom_WR_ofs {}
+ set eeprom_prev {}
+
+ # Set flag EECON.RDYBSY (EEPROM is ready)
+ $this sim_GUI_bit_set_clear 1 EECON RDYBSY
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 150
+ }
+ set sfr(150) [expr {$sfr(150) | 2}]
+ set controllers_conf(RDYBSY) 1
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S 150
+ }
+}
+
+## Try to translate line number to address in CODE
+ # @parm Int line - Line number (in source code)
+ # @parm Int file - File number
+ # @return Int - Address in program memory or {} on fail
+public method simulator_line2address {line file} {
+ if {$line == {}} {
+ return {}
+ }
+ set line [expr $line]
+ if {[llength [array names line2PC -exact "$line,$file"]]} {
+ return $line2PC($line,$file)
+ } {
+ return {}
+ }
+}
+
+## Set watchdog timer value
+ # This procedure does nothing on MCUs without watchdog timer
+ # @parm Int value - new value (0..8192)
+ # @return void
+public method simulator_setWatchDogTimer {value} {
+ if {!$feature_avaliable(wtd)} {return}
+ set watchdog_value $value
+}
+
+## Get value of watchdog timer
+ # @return Int - Current value of watchdog timer 0..8192
+public method simulator_getWatchDogTimerValue {} {
+ return $watchdog_value
+}
+
+ ## Get size of watch dog prescaler (0 - 128)
+ # @return Int - Maximum value - 1
+public method simulator_getWatchDogPrescalerSize {} {
+ return $controllers_conf(WatchDogPrescaler)
+}
+
+## Get current value of watchdog prescaler
+ # @return Int - Prescaler content
+public method simulator_getWatchDogPrescalerValue {} {
+ return $wdt_prescaler_val
+}
+
+## Set value of watchdog prescaler
+ # @parm Int value - New prescaler value
+ # @return void
+public method simulator_setWatchDogPrescalerValue {value} {
+ set wdt_prescaler_val $value
+}
+
+## Start/Stop watchdog timer
+ # This procedure does nothing on MCUs without watchdog timer
+ # @parm Bool bool - 0 == STOP; 1 == START
+ # @return void
+public method simulator_startStopWatchDogTimer {bool} {
+ if {!$feature_avaliable(wtd)} {return}
+ set controllers_conf(WatchDogTimer) $bool
+}
+
+## Determinate wheather watchdog timer is running or not
+ # @return Bool - 1 == RUNNING; 0 == STOPPED
+public method simulator_isWatchDogTimerRuning {} {
+ return $controllers_conf(WatchDogTimer)
+}
+
+## Perform subprogram call
+ # @parm Int value - Subprogram vector
+ # @return void
+public method simulator_subprog_call {value} {
+ stack_push [expr {$value & 0xFF}]
+ stack_push [expr {($value & 0xFF00) >> 8}]
+ incr run_statistics(6)
+ $this subprograms_call 3 $pc $value
+ $this stack_monitor_set_last_values_as 1 2
+ $this stopwatch_refresh
+ set pc $value
+}
+
+## Set value of Program Couter (PC)
+ # @parm Int value - new value
+ # @return void
+public method setPC {value} {
+ set pc $value
+}
+
+## Get current value of Program Couter (PC)
+ # @return Int - PC value
+public method getPC {} {
+ return $pc
+}
+
+## Get information about current line
+ # @return List - {line_number file_number level block}
+public method simulator_getCurrentLine {} {
+ return $Line($pc)
+}
+
+## Get current line number only
+ # @return Int - Line number
+public method simulator_get_line_number {} {
+ return [lindex $Line($pc) 0]
+}
+
+## Translate adress in program memory to line info
+ # @parm Int addr - Address to translate
+ # @return List - Line information list
+public method simulator_address2line {addr} {
+ return $Line($addr)
+}
+
+## Change content of internal data memory
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (hexadecimal) or {} (means '0')
+ # @return void
+public method setData {addr val} {
+ if {$val == {}} {
+ set val 0
+ }
+ set ram($addr) [expr "0x$val"]
+}
+
+## Change content of internal data memory
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (decimal) or {} (means '0')
+ # @return void
+public method setDataDEC {addr val} {
+ if {$val == {}} {
+ set val 0
+ }
+ set ram($addr) $val
+}
+
+## Change content of register in SFR area
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (hexadecimal) or {} (means '0')
+ # @return void
+public method setSfr {addr val} {
+ # Empty value == zero
+ if {$val == {}} {
+ set val 0
+ }
+
+ # Set value
+ set foo $stepback_ena
+ set stepback_ena 0
+ switch -- $addr {
+ 153 { ;# SBUF R
+ set sfr(153) [expr "0x$val"]
+ }
+ default {
+ write_sfr $addr [expr "0x$val"]
+ }
+ }
+
+ # Take care of read-only bits
+ switch -- $addr {
+ {150} { ;# EECON
+ if {$sfr(150) & 1} {
+ set controllers_conf(WRTINH) 1
+ } {
+ set controllers_conf(WRTINH) 0
+ }
+ }
+ }
+
+ # Adjust internal engine configuration
+ evaluate_sfr $addr 0
+ set stepback_ena $foo
+
+ # If adress points to Primary Accumulator (Acc) -> reevaluate PSW
+ if {$addr == 224} {
+ $this Simulator_GUI_sync S 208
+ }
+}
+
+## Change content of register in SFR area directly
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (decimal)
+ # @return void
+public method setSfr_directly {addr val} {
+ set sfr($addr) $val
+}
+
+## Change content of external data memory
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (hexadecimal) or {} (means '0')
+ # @return void
+public method setXdata {addr val} {
+ if {$val == {}} {
+ set val 0
+ }
+ set xram($addr) [expr "0x$val"]
+}
+
+## Change content of expanded data memory
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (hexadecimal) or {} (means '0')
+ # @return void
+public method setEram {addr val} {
+ if {$val == {}} {
+ set val 0
+ }
+ set eram($addr) [expr "0x$val"]
+}
+
+## Change content of external data memory
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (decimal) or {} (means '0')
+ # @return void
+public method setXdataDEC {addr val} {
+ if {$val == {}} {
+ set val 0
+ }
+ set xram($addr) $val
+}
+
+## Change content of expanded data memory
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (decimal) or {} (means '0')
+ # @return void
+public method setEramDEC {addr val} {
+ if {$val == {}} {
+ set val 0
+ }
+ set eram($addr) $val
+}
+
+## Change content of the program memory
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (hexadecimal) or {}
+ # @return void
+public method setCode {addr val} {
+ set code($addr) [expr "0x$val"]
+}
+
+## Change content of the program memory
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (decimal) or {}
+ # @return void
+public method setCodeDEC {addr val} {
+ set code($addr) $val
+}
+
+## Get value (DEC) of some register in expanded data memory
+ # @parm Int addr - register address
+ # @return Int - register value
+public method getEramDEC {addr} {
+ return $eram($addr)
+}
+
+## Get value (HEX) of some register in expanded data memory
+ # @parm Int addr - register address
+ # @return String - register value (2 hexadecimal digits)
+public method getEram {addr} {
+ # Get hexadecimal value
+ set result [format "%X" $eram($addr)]
+ # Adjust the value
+ if {[string length $result] == 1} {
+ set result "0$result"
+ }
+ # Return the value
+ return $result
+}
+
+## Get value (HEX) of some register in internal data memory
+ # @parm Int addr - register address
+ # @return String - register value (2 hexadecimal digits)
+public method getData {addr} {
+ # Get hexadecimal value
+ set result [format "%X" $ram($addr)]
+ # Adjust the value
+ if {[string length $result] == 1} {
+ set result "0$result"
+ }
+ # Return the value
+ return $result
+}
+
+## Get value (HEX) of some register in SFR area
+ # @parm Int addr - register address
+ # @return String - register value (2 hexadecimal digits)
+public method getSfr {addr} {
+ # Get hexadecimal value
+ set result [format "%X" $sfr($addr)]
+ # Adjust the value
+ if {[string length $result] == 1} {
+ set result "0$result"
+ }
+ # Return the value
+ return $result
+}
+
+## Get value (DEC) of some register in SFR area
+ # @parm Int addr - register address
+ # @return Int - register value
+public method getSfrDEC {addr} {
+ return $sfr($addr)
+}
+
+## Get value (DEC) of some register in SFR area
+ # @parm Int addr - register address
+ # @return Int - register value
+public method getDataDEC {addr} {
+ return $ram($addr)
+}
+
+## Get value (DEC) of some register in data EEPROM
+ # @parm Int addr - register address
+ # @return Int - register value
+public method getEepromDEC {addr} {
+ return $eeprom($addr)
+}
+
+## Get value (HEX) of some register in data EEPROM
+ # @parm Int addr - register address
+ # @return String - register value (2 hexadecimal digits)
+public method getEeprom {addr} {
+ # Get hexadecimal value
+ set result [format "%X" $eeprom($addr)]
+ # Adjust the value
+ if {[string length $result] == 1} {
+ set result "0$result"
+ }
+ # Return the value
+ return $result
+}
+
+## Change content of external data memory
+ # @parm Int addr - Register address (decimal)
+ # @parm String val - New value (decimal) or {} (means '0')
+ # @return void
+public method setEepromDEC {addr val} {
+ if {$val == {}} {
+ set val 0
+ }
+ set eeprom($addr) $val
+}
+
+## Get value (HEX) of some register in external data memory
+ # @parm Int addr - register address
+ # @return String - register value (2 hexadecimal digits)
+public method getXdata {addr} {
+ # Get hexadecimal value
+ set result [format "%X" $xram($addr)]
+ # Adjust the value
+ if {[string length $result] == 1} {
+ set result "0$result"
+ }
+ # Return the value
+ return $result
+}
+
+## Get value (DEC) of some register in external data memory
+ # @parm Int addr - register address
+ # @return Int - register value
+public method getXdataDEC {addr} {
+ return $xram($addr)
+}
+
+## Get value (HEX) of some register in the program memory
+ # @parm Int addr - register address
+ # @return String - register value (2 hexadecimal digits) or {}
+public method getCode {addr} {
+ # Get value (and return {} if it's {})
+ if {![simulator_address_range C $addr] || $code($addr) == {}} {return {}}
+ set result [format "%X" $code($addr)]
+ # Normalize the value
+ if {[string length $result] == 1} {
+ set result "0$result"
+ }
+ # Return the value
+ return $result
+}
+
+## Get value (DEC) of certain register in program memory
+ # @parm Int addr - Register address
+ # @return Int - Register value
+public method getCodeDEC {addr} {
+ if {![simulator_address_range C $addr]} {
+ return {}
+ }
+ return $code($addr)
+}
+
+## Get value (DEC) of certain cell in data EEPROM write buffer
+ # @parm Int addr - Cell address
+ # @return Int - Register value
+public method getEepromWrBufDEC {addr} {
+ return $eeprom_WR_buff($addr)
+}
+
+## Set value (DEC) of certain cell in data EEPROM write buffer
+ # @parm Int addr - Cell address
+ # @parm Int val - New cell value
+ # @return void
+public method setEepromWrBufDEC {addr val} {
+ set eeprom_WR_buff($addr) $val
+}
+
+## Set value (DEC) of EEPROM write buffer offset
+ # @return Int - Offset (0..65535)
+public method getEepromWrOffsetDEC {} {
+ return $eeprom_WR_ofs
+}
+
+## Load program to virtual processor from ADF file (Assembler Debug File)
+ # @parm File adf_file - ADF file ID (content of *.adf file)
+ # @return void
+public method load_program_from_adf {adf_file} {
+ unload_program ;# Clear current content of the program memory
+
+ set programming_language 0
+
+ set firts_line 1
+ set list_of_filenames [list]
+
+ # Parse the program data
+ while {![eof $adf_file]} {
+ set line [gets $adf_file]
+
+ # Skip empty lines and comments
+ if {$line == {} || [regexp {^\s*#} $line]} {continue}
+
+ # Take first line
+ if {$firts_line} {
+ set firts_line 0
+ set project_dir [$this cget -projectPath]
+ set len [llength $line]
+ for {set i 1} {$i < $len} {incr i 2} {
+ lappend list_of_filenames \
+ [file join $project_dir [lindex $line $i]]
+ }
+ continue
+ }
+
+ # Local variables
+ set fileNum [lindex $line 0] ;# File number
+ set lineNum [lindex $line 1] ;# Number of line in source code
+ set addr [lindex $line 2] ;# Code address
+ set line [lreplace $line 0 2] ;# List of codes (DEC)
+
+ # Set address for translating from line number
+ set line2PC($lineNum,$fileNum) $addr
+
+ # Iterate over codes and save them
+ foreach num $line {
+ # Check for allowed address range
+ if {$addr >= $code_size} {
+ tk_messageBox \
+ -parent . \
+ -icon warning \
+ -type ok \
+ -title [mc "Out of memory"] \
+ -message [mc "%s has not enought program memory to load this program. Simulator will work but the loaded code is incomplite" [$this cget -P_option_mcu_type]]
+ return 0
+ }
+ set Line($addr) [list $lineNum $fileNum 0 0] ;# Set line number
+ set code($addr) $num ;# Set program code
+ incr addr ;# Increment address
+ }
+ }
+}
+
+## Load program to virtual processor from CDB file
+ # @parm File filename - Full name of source file from which SIM file was generaded
+ # @parm File cdb_file - CDB file ID (content of *.cdb file)
+ # @parm File ihx_file - HEX file ID (content of *.ihx or *.hex file)
+ # @return void
+public method load_program_from_cdb {filename cdb_file ihx_file} {
+ unload_program ;# Clear current content of the program memory
+
+ set programming_language 1
+
+ set lineNum 0
+ set highest_addr 0
+ set eof 0
+
+ # Iterate over HEX records
+ while {![eof $ihx_file]} {
+ set line [gets $ihx_file]
+ incr lineNum ;# Increment line number
+
+ # Skip comments
+ if {[string index $line 0] != {:}} {continue}
+
+ # Check for valid charters
+ if {![regexp {^:[0-9A-Fa-f]+$} $line]} {
+ return 0
+ }
+ # Check for odd lenght
+ set len [string length $line]
+ if {[expr {$len % 2}] != 1} {
+ return 0
+ }
+
+ # Analize HEX record
+ set len [ string range $line 1 2 ] ;# Lenght field
+ set addr [ string range $line 3 6 ] ;# Address field
+ set type [ string range $line 7 8 ] ;# Type field
+ set data [ string range $line 9 {end-2} ] ;# Data field
+ set check [ string range $line {end-1} end ] ;# Checksum field
+ set line [ string range $line 1 {end-2} ] ;# Record without ':' and checksum
+
+ # Handle record type (01 == EOF; 00 == normal record)
+ if {$type == {01}} {
+ set eof 1
+ break
+ } elseif {$type != {00}} {
+ return 0
+ }
+
+ # Check for valid checksum
+ set new_check [::IHexTools::getCheckSum $line]
+ if {$new_check != $check} {
+ return 0
+ }
+
+ # Check for correct value of the length field
+ set len [expr "0x$len"]
+ if {([string length $data] / 2) != $len} {
+ return 0
+ }
+
+ # Parse and load data field
+ set addr [expr "0x$addr"]
+ for {set i 0; set j 1} {$i < ($len * 2)} {incr i 2; incr j 2} {
+ set code($addr) [expr "0x[string range $data $i $j]"]
+ incr addr
+ }
+
+ # Store highest address
+ if {$addr > $highest_addr} {
+ set highest_addr $addr
+ }
+ }
+
+ # If there is no EOF then report that as an error
+ if {!$eof} {return 0}
+
+ # Parse CDB file
+ set list_of_filenames [list $filename]
+ set filenumber 0
+ set filename {}
+ set level {}
+ set block {}
+ while {![eof $cdb_file]} {
+ set line [split [gets $cdb_file] {:$}]
+
+ if {[lindex $line 0] != {L}} {continue}
+ if {[lindex $line 1] != {C}} {continue}
+
+ set filename [lindex $line 2]
+ set linenumber [lindex $line 3]
+ set level [lindex $line 4]
+ set block [lindex $line 5]
+ scan [lindex $line 6] {%x} address
+
+ set filename [file normalize [file join [$this cget -projectPath] $filename]]
+ set filenumber [lsearch -exact -ascii $list_of_filenames $filename]
+ if {$filenumber == -1} {
+ set filenumber [llength $list_of_filenames]
+ lappend list_of_filenames $filename
+ }
+ set Line($address) [list $linenumber $filenumber $level $block]
+ set line2PC($linenumber,$filenumber) $address
+ }
+ return 1
+}
+
+## Get name of loaded CDB file (C language DeBug file) generated by SDCC
+ # @return String - full filename
+public method simulator_get_cdb_filename {} {
+ set filename [lindex $list_of_filenames 0]
+ set filename [file rootname $filename]
+ return $filename.cdb
+}
+
+## Clear current content of the program memory
+ # @return void
+public method unload_program {} {
+ array unset line2PC
+ array unset breakpoints
+
+ for {set i 0} {$i < $code_size} {incr i} {
+ set code($i) {}
+ set Line($i) {{} {} {} {}}
+ }
+ for {set i $code_size} {$i <= 0xFFFF} {incr i} {
+ set Line($i) {}
+ }
+}
+
+## Import list of breakpoints (e.g. '{0 0 0 1 0 0 1 1 0}')
+ # @parm String full_filename - Name of source code file
+ # @parm List breakpoints_list - list of breakpoints
+ # @return void
+public method Simulator_import_breakpoints {full_filename breakpoints_list} {
+ set file_number [lsearch -exact -ascii $list_of_filenames $full_filename]
+ set breakpoints($file_number) {}
+ set line 0
+ foreach bool $breakpoints_list {
+ if {$bool == 1} {
+ lappend breakpoints($file_number) $line
+ }
+ incr line
+ }
+}
+
+## Set MCU clock
+ # @parm Int clockkHz - clock frequency in kHz
+ # @return void
+public method setEngineClock {clockkHz} {
+ set clock_kHz $clockkHz
+}
+
+## Get program uptime as human readable string
+ # @return String - the time (eg. '2 s 42 ms 987 us')
+public method getTime {} {
+ # Initial computations
+ if {!$clock_kHz} {
+ set s 0
+ set ms 0
+ set ns 0
+ } {
+ set s [expr {int($overall_time * (0.012 / $clock_kHz))}]
+ set ms [expr {int($overall_time * (12000.0 / $clock_kHz)) % 1000000}]
+ set ns [expr {int($overall_time * (12000000.0 / $clock_kHz)) % 1000}]
+ }
+
+ # Local variables
+ set us [expr {($ms % 1000)}] ;# Number of micro seconds
+ set ms [expr {$ms / 1000}] ;# Number of mili seconds
+ set s [expr {int($s)}] ;# Number of seconds
+ set h [expr {$s / 3600}] ;# Number of hours
+ set s [expr {$s % 3600}]
+ set m [expr {$s / 60}] ;# Number of minutes
+ set s [expr {$s % 60}]
+
+ # Adjust length of nano-seconds string
+ set len [string length $ns]
+ if {$len < 3} {
+ set ns_s "[string repeat { } [expr {3 - $len}]]$ns"
+ } {
+ set ns_s $ns
+ }
+
+ # Adjust length of micro-seconds string
+ set len [string length $us]
+ if {$len < 3} {
+ set us_s "[string repeat { } [expr {3 - $len}]]$us"
+ } {
+ set us_s $us
+ }
+
+ # Adjust length of mili-seconds string
+ set len [string length $ms]
+ if {$len < 3} {
+ set ms_s "[string repeat { } [expr {3 - $len}]]$ms"
+ } {
+ set ms_s $ms
+ }
+
+ # Adjust seconds and minutes strings
+ if {[string length $s] == 1} {
+ set s_s " $s"
+ } {
+ set s_s $s
+ }
+ if {[string length $m] == 1} {
+ set m_s " $m"
+ } {
+ set m_s $m
+ }
+
+ # Initialize resulting string
+ set result {}
+
+ # Append hours
+ if {$h > 0} {
+ append result
+ }
+ # Append minutes
+ if {$m > 0 || $result != {}} {
+ append result " ${m_s}m"
+ }
+ # Append seconds
+ if {$s > 0 || $result != {}} {
+ append result " ${s_s}s"
+ }
+ # Append mili-seconds
+ if {$ms > 0 || $result != {}} {
+ append result " ${ms_s}ms"
+ }
+ # Append micro-seconds
+ if {$us > 0 || $result != {}} {
+ append result " ${us_s}us"
+ }
+ # Append nano-seconds
+ if {$ns > 0 || $result != {}} {
+ append result " ${ns_s}ns"
+ }
+
+ # Done ...
+ return [string trim $result]
+}
diff --git a/lib/simulator/engine/engine_hibernation.tcl b/lib/simulator/engine/engine_hibernation.tcl
new file mode 100755
index 0000000..24d3adf
--- /dev/null
+++ b/lib/simulator/engine/engine_hibernation.tcl
@@ -0,0 +1,205 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# HIBERNATION RELATED PROCEDURES
+# --------------------------------------------------------------------------
+
+## Get special engine configuration list (for stepback and hibernation)
+ # @return List - Special configuration list
+public method simulator_get_special {} {
+ set result 0
+ lappend result \
+ $ports_previous_state $pc $bank \
+ $interrupts_in_progress $interrupt_on_next $skip_interrupt \
+ $timer_0_running $timer_1_running $overall_time \
+ $overall_instructions $inter_in_p_flags $timer1_overflow
+
+ if {$feature_avaliable(t2)} {
+ lappend result $timer_2_running $timer2_overflow
+ }
+ if {$feature_avaliable(wtd)} {
+ lappend result $watchdog_value $wdtrst_prev_val
+ }
+ if {$feature_avaliable(wdtcon)} {
+ lappend result $wdt_prescaler_val $controllers_conf(WatchDogPrescaler)
+ }
+ if {$feature_avaliable(pwm)} {
+ lappend result $pwm_running $pwm_OCR
+ }
+ if {$eeprom_size} {
+ lappend result \
+ $eeprom_WR_time \
+ $eeprom_WR \
+ $eeprom_prev \
+ $eeprom_WR_ofs \
+ $controllers_conf(RDYBSY) \
+ $controllers_conf(WRTINH)
+
+ for {set i 0} {$i < 32} {incr i} {
+ lappend result $eeprom_WR_buff($i)
+ }
+ }
+ if {$feature_avaliable(hddptr)} {
+ lappend result $hidden_DPTR0 $hidden_DPTR1
+ }
+ if {$feature_avaliable(acomparator)} {
+ lappend result $anlcmp_running $anlcmp_output $anlcpm_db_timer
+ }
+ if {$feature_avaliable(uart)} {
+ lappend result \
+ $uart_clock_prescaler \
+ $uart_RX_clock \
+ $uart_TX_clock \
+ $uart_RX_in_progress \
+ $uart_TX_in_progress \
+ $uart_RX_shift_reg \
+ $uart_TX_shift_reg
+ }
+
+ lappend result $time
+ return $result
+}
+
+## Set special engine configuration list (for stepback and hibernation)
+ # @parm List list - list to set
+ # @return void
+public method simulator_set_special {list} {
+ set i 1
+ foreach var {
+ ports_previous_state pc bank
+ interrupts_in_progress interrupt_on_next skip_interrupt
+ timer_0_running timer_1_running overall_time
+ overall_instructions inter_in_p_flags timer1_overflow
+ } {
+ set $var [lindex $list $i]
+ incr i
+ }
+
+ if {$feature_avaliable(t2)} {
+ set timer_2_running [lindex $list $i]
+ incr i
+ set timer2_overflow [lindex $list $i]
+ incr i
+ }
+ if {$feature_avaliable(wtd)} {
+ set watchdog_value [lindex $list $i]
+ incr i
+ set wdtrst_prev_val [lindex $list $i]
+ incr i
+ }
+ if {$feature_avaliable(wdtcon)} {
+ set wdt_prescaler_val [lindex $list $i]
+ incr i
+ set controllers_conf(WatchDogPrescaler) [lindex $list $i]
+ incr i
+ }
+ if {$feature_avaliable(pwm)} {
+ set pwm_running [lindex $list $i]
+ incr i
+ set pwm_OCR [lindex $list $i]
+ incr i
+ }
+ if {$eeprom_size} {
+ set eeprom_WR_time [lindex $list $i]
+ incr i
+ set eeprom_WR [lindex $list $i]
+ incr i
+ set eeprom_prev [lindex $list $i]
+ incr i
+ set eeprom_WR_ofs [lindex $list $i]
+ incr i
+ set controllers_conf(RDYBSY) [lindex $list $i] ;# Read only bit
+ incr i
+ set controllers_conf(WRTINH) [lindex $list $i] ;# Read only bit
+ incr i
+
+ for {set j 0} {$j < 32} {incr j; incr i} {
+ set eeprom_WR_buff($j) [lindex $list $i]
+ }
+ }
+ if {$feature_avaliable(hddptr)} {
+ set hidden_DPTR0 [lindex $list $i]
+ incr i
+ set hidden_DPTR1 [lindex $list $i]
+ incr i
+ }
+ if {$feature_avaliable(acomparator)} {
+ set anlcmp_running [lindex $list $i]
+ incr i
+ set anlcmp_output [lindex $list $i]
+ incr i
+ set anlcpm_db_timer [lindex $list $i]
+ incr i
+ }
+ if {$feature_avaliable(uart)} {
+ set uart_clock_prescaler [lindex $list $i]
+ incr i
+ set uart_RX_clock [lindex $list $i]
+ incr i
+ set uart_TX_clock [lindex $list $i]
+ incr i
+ set uart_RX_in_progress [lindex $list $i]
+ incr i
+ set uart_TX_in_progress [lindex $list $i]
+ incr i
+ set uart_RX_shift_reg [lindex $list $i]
+ incr i
+ set uart_TX_shift_reg [lindex $list $i]
+ incr i
+ }
+
+ set time [lindex $list $i]
+}
+
+## Get special engine configuration list from stepback stack
+ # @parm Int i - Depth
+ # @return List - Config list
+public method simulator_hib_get_SB_spec {i} {
+ return [lindex $stepback_spec $i]
+}
+
+## Get stepback stack for ordinary registes
+ # @parm Int i - Depth
+ # @return List - Part of stepback stack
+public method simulator_hib_get_SB_norm {i} {
+ return [lindex $stepback_normal $i]
+}
+
+## Append special engine configuration list onto stepback stack
+ # @parm List list - Config list
+ # @return void
+public method simulator_hib_append_SB_spec {list} {
+ lappend stepback_spec $list
+}
+
+## Append special engine configuration list onto stepback stack
+ # @parm List list - List of registers and their values
+ # @return void
+public method simulator_hib_append_SB_norm {list} {
+ lappend stepback_normal $list
+}
diff --git a/lib/simulator/engine/engine_initialization_cleanup.tcl b/lib/simulator/engine/engine_initialization_cleanup.tcl
new file mode 100755
index 0000000..e8a1ffa
--- /dev/null
+++ b/lib/simulator/engine/engine_initialization_cleanup.tcl
@@ -0,0 +1,340 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# INITIALIZATION & CLEANUP RELATED PROCEDURES
+# --------------------------------------------------------------------------
+
+
+## Object constructor
+constructor {} {
+ # Initialize array of program run statistics
+ for {set i 0} {$i < 10} {incr i} {
+ set run_statistics($i) 0
+ }
+
+ # Initialize program memory debugging map
+ for {set i 0} {$i <= 0xFFFF} {incr i} {
+ set Line($i) {}
+ }
+}
+
+## Object destructor
+destructor {
+ set break 1
+}
+
+## This procedure sets these SFR which are not affected by reset
+ # This function is called after each simulator start
+ # @return void
+private method simulator_system_power_on {} {
+ if {$feature_avaliable(wtd)} {
+ set sfr($symbol(WDTRST)) [undefined_octet]
+ set wdtrst_prev_val $sfr($symbol(WDTRST))
+ if {$sync_ena} {
+ catch {$this Simulator_GUI_sync S 166}
+ }
+ }
+
+ if {$feature_avaliable(uart)} {
+ set sfr($symbol(SBUFR)) [undefined_octet]
+ set sfr($symbol(SBUFT)) [undefined_octet]
+ set controllers_conf(UART_M) 0
+ if {$sync_ena} {
+ catch {$this Simulator_GUI_sync S 153}
+ catch {$this Simulator_GUI_sync S 409}
+ }
+ }
+
+ if {$feature_avaliable(pof)} {
+ set controllers_conf(POF) 1
+ set sfr($symbol(PCON)) 16
+ if {$sync_ena} {
+ catch {$this Simulator_GUI_sync S 135}
+ }
+ }
+
+ if {$feature_avaliable(spi)} {
+ set sfr($symbol(SPDR)) 0
+ if {$sync_ena} {
+ catch {$this Simulator_GUI_sync S $symbol(SPDR)}
+ }
+ }
+}
+
+## Initialize memory (this function must be called before using this class)
+ # This function is called after constructor
+ # @return void
+public method simulator_initialize_mcu {} {
+ # Get processor definition
+ set proc_data [$this cget -procData]
+
+ # Determinate capacities of uC memories
+ set iram_size [lindex $proc_data 3]
+ set eram_size [lindex $proc_data 8]
+ set eeprom_size [lindex $proc_data 32]
+ set xram_size [expr {int([$this cget -P_option_mcu_xdata])}]
+ set code_size [expr {
+ int(([lindex $proc_data 2] * 1024)
+ +
+ [$this cget -P_option_mcu_xcode])}]
+
+ # Parse processor definition and set array feature_avaliable
+ foreach index {
+ 5 6 7 9 10 11 17
+ 20 21 22 23 24 25 26
+ 27 28 29 30 31 33 34
+ 35 36 37 38 39 40
+ 41 42 0 1
+ } name {
+ uart t2 wtd ddp auxr t2mod pof
+ gf1 gf0 pd idl smod0 iph acomparator
+ euart clkreg pwdex spi wdtcon intelpe pwm
+ x2reset ckcon auxr1gf3 ao wdtprg hddptr
+ auxrwdidle auxrdisrto xram xcode
+ } {
+ if {[lindex $proc_data $index] == {yes}} {
+ set feature_avaliable($name) 1
+ } {
+ set feature_avaliable($name) 0
+ }
+ }
+ for {set i 12; set j 0} {$i < 17} {incr i; incr j} {
+ set port_mask [lindex $proc_data $i]
+ if {$port_mask != {} && $port_mask != {00000000}} {
+ set feature_avaliable(p$j) 1
+ set feature_avaliable(port$j) $port_mask
+ } {
+ set feature_avaliable(p$j) 0
+ set feature_avaliable(port$j) {00000000}
+ }
+ }
+
+ # Set incomplite_regs_mask, restricted_bits and incomplite_regs
+ array unset incomplite_regs_mask
+ set restricted_bits {}
+ foreach reg_mask [lindex $proc_data 18] {
+ set addr [string range $reg_mask 0 1]
+ set mask [string range $reg_mask 2 3]
+ set addr [expr "0x$addr"]
+ set mask [expr "0x$mask"]
+
+ set incomplite_regs_mask($addr) $mask
+
+ if {$addr > 127 && !($addr % 8)} {
+ for {set i 1} {$i <= 128} {set i [expr {$i * 2}]; incr addr} {
+ if {![expr $mask & $i]} {
+ lappend restricted_bits $addr
+ }
+ }
+ }
+ }
+ set incomplite_regs [array names incomplite_regs_mask]
+
+ # Determiate list of write-only registers
+ set write_only_regs {}
+ foreach reg [lindex $proc_data 19] {
+ lappend write_only_regs [expr "0x$reg"]
+ }
+
+ # (Re)initialize uC memories and configuration
+ array unset sfr
+ array unset ram
+ array unset eram
+ array unset xram
+ array unset code
+ array unset eeprom
+ array unset eeprom_WR_buff
+ array unset controllers_conf
+
+ # Set critical MCU configuration
+ set controllers_conf(WatchDogPrescaler) 0
+ set controllers_conf(RDYBSY) 1
+ set controllers_conf(WRTINH) 1
+ foreach key {
+ X2 HWDT WDTEN WSWRST IE0 TF0 IE1 TF1 TI RI SPIF TF2
+ EXF2 CF DPS DCEN T2OE T0_MOD T1_MOD UART_M SMOD0 FE
+ CEN INT0 INT1 TCLK RCLK SMOD T2EX T2 T1 T0 T2_out
+ } {
+ set controllers_conf($key) 0
+ }
+
+ # Power on virtual uC and derminate list of implemented SFR
+ simulator_system_power_on
+ master_reset 0
+ set avaliable_sfr [array names sfr]
+
+ # Initialize/Clear code memory and data EEPROM
+ simulator_clear_memory code
+ simulator_clear_memory eeprom
+}
+
+## Clear memory content
+ # @parm String mem_type - Type of memory to clear
+ # code - Program memory
+ # xdata - External data memory
+ # eram - Expanded data memory
+ # eeprom - Data EEPROM
+ # @return void
+public method simulator_clear_memory {mem_type} {
+ switch -- $mem_type {
+ {code} { ;# Program memory
+ for {set i 0} {$i < $code_size} {incr i} {
+ set code($i) {}
+ }
+ }
+ {xdata} { ;# External data memory
+ for {set i 0} {$i < $xdata_size} {incr i} {
+ set xdata($i) {}
+ }
+ }
+ {eram} { ;# Expanded data memory
+ for {set i 0} {$i < $eram_size} {incr i} {
+ set eram($i) {}
+ }
+ }
+ {eeprom} { ;# Data EEPROM
+ for {set i 0} {$i < $eeprom_size} {incr i} {
+ set eeprom($i) 0
+ }
+ if {$eeprom_size} {
+ for {set i 0} {$i < 32} {incr i} {
+ set eeprom_WR_buff($i) {}
+ }
+ }
+ }
+ }
+}
+
+## Inicliaze array 'symbol' -- this function must be called after definition of this class
+ # @return void
+proc InitializeNS {} {
+ variable symbol ;# Array of SFR symbolic names (eg. $symbol(P0) == "80")
+
+ foreach symb_name {
+ {P0 80} {SP 81} {DP0L 82} {DP0H 83}
+ {DP1L 84} {DP1H 85} {IPH B7} {SADDR A9}
+ {PCON 87} {TCON 88} {TMOD 89} {TL0 8A}
+ {TL1 8B} {TH0 8C} {TH1 8D} {AUXR 8E}
+ {P1 90} {SCON 98} {SBUFR 99} {P2 A0}
+ {AUXR1 A2} {WDTRST A6} {IE A8} {P3 B0}
+ {IP B8} {P4 C0} {T2CON C8} {T2MOD C9}
+ {RCAP2L CA} {RCAP2H CB} {TL2 CC} {TH2 CD}
+ {PSW D0} {A E0} {B F0} {SPDR 86}
+ {WDTCON A7} {EECON 96} {CLKREG 8F} {ACSR 97}
+ {SADEN B9} {SPCR D5} {SPSR AA} {SBUFT 199}
+
+ {IT0 88} {IE0 89} {IT1 8A} {IE1 8B}
+ {TR0 8C} {TF0 8D} {TR1 8E} {TF1 8F}
+
+ {RI 98} {TI 99} {RB8 9A} {TB8 9B}
+ {REN 9C} {SM2 9D} {SM1 9E} {SM0 9F}
+
+ {EX0 A8} {ET0 A9} {EX1 AA} {ET1 AB}
+ {ES AC} {ET2 AD} {EC AE} {EA AF}
+
+ {RXD B0} {TXD B1} {INT0 B2} {INT1 B3}
+ {T0 B4} {T1 B5} {WR B6} {RD B7}
+
+ {PX0 B8} {PT0 B9} {PX1 BA} {PT1 BB}
+ {PS BC} {PT2 BD} {PC BE}
+
+ {TF2 CF} {EXF2 CE} {RCLK CD} {TCLK CC}
+ {EXEN2 CB} {TR2 CA} {CT2 C9} {CPRL2 C8}
+
+ {P D0} {OV D2} {RS0 D3}
+ {RS1 D4} {F0 D5} {AC D6} {C D7}
+ } {
+ set symbol([lindex $symb_name 0]) [expr "0x[lindex $symb_name 1]"]
+ }
+
+ array set ::Simulator_ENGINE::PIN {
+ AD0 {0 0}
+ AD1 {0 1}
+ AD2 {0 2}
+ AD3 {0 3}
+ AD4 {0 4}
+ AD5 {0 5}
+ AD6 {0 6}
+ AD7 {0 7}
+
+ T2 {1 0}
+ ANL1 {1 0}
+ ANL0 {1 1}
+ T2EX {1 1}
+ MOSI {1 5}
+ MISO {1 6}
+ SCK {1 7}
+
+ A15 {2 7}
+ A14 {2 6}
+ A13 {2 5}
+ A12 {2 4}
+ A11 {2 3}
+ A10 {2 2}
+ A9 {2 1}
+ A8 {2 0}
+
+ RXD {3 0}
+ TXD {3 1}
+ INT0 {3 2}
+ INT1 {3 3}
+ T0 {3 4}
+ T1 {3 5}
+ WR {3 6}
+ RD {3 7}
+ }
+
+ set PORT_LATCHES [list $symbol(P0) $symbol(P1) $symbol(P2) $symbol(P3) $symbol(P4)]
+}
+
+## Shutdown simulator engine
+ # @return void
+private method internal_shutdown {} {
+ set break 1
+ $this Simulator_sync_clock
+}
+
+## Determinate if the specified feature is avaliable on this MCU
+ # @parm String key - feature name (e.g. 'p0')
+ # @return Bool - result (1 == yes; 0 == no)
+public method get_feature_avaliable {key} {
+ return $feature_avaliable($key)
+}
+
+## Get number of implemented ports and list of port indexes
+ # @return List - {number_of_ports {idx0 idx1...}} (e.g. {4 {0 1 2 3}})
+public method get_ports_info {} {
+ set sum 0
+ for {set i 0} {$i < 5} {incr i} {
+ if {$feature_avaliable(p$i)} {
+ incr sum
+ lappend lst $i
+ }
+ }
+ return [list $sum $lst]
+}
diff --git a/lib/simulator/engine/engine_instructions.tcl b/lib/simulator/engine/engine_instructions.tcl
new file mode 100755
index 0000000..d732414
--- /dev/null
+++ b/lib/simulator/engine/engine_instructions.tcl
@@ -0,0 +1,1596 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# INSTRUCTION PROCEDURES
+# --------------------------------------------------------------------------
+
+
+## Instruction: ACALL
+ # @parm Int haddr - High part of the target address
+ # @parm Int laddr - Low part of the target address
+ # @return void
+private method ins_acall {haddr laddr} {
+ set time 2
+ stepback_save_spec_subprog 2
+
+ stack_push [expr {($pc & 255)}]
+ stack_push [expr {($pc & 0xFF00) >> 8}]
+
+ incr laddr [expr {$haddr << 8}]
+ incr run_statistics(6)
+ $this subprograms_call 1 $pc $laddr
+ $this stack_monitor_set_last_values_as 1 2
+ set pc $laddr
+}
+
+## Instruction: ADD
+ # @parm Int val - Value to add to Acc
+ # @return void
+private method ins_add {val} {
+ set time 1
+
+ alo_add $val
+ incr_pc 1
+
+ evaluate_sfr 224
+}
+
+## Instruction: ADD A, addr
+ # @parm Int addr - Direct address
+ # @return void
+private method ins_add_D {addr} {
+ if {[check_address_validity D $addr]} {
+ ins_add [undefined_octet]
+ return
+ }
+ if {$addr < 128} {
+ ins_add $ram($addr)
+ } {
+ ins_add [read_sfr $addr]
+ }
+}
+
+## Instruction: ADD A, @Ri
+ # @parm Int addr - Indirect address
+ # @return void
+private method ins_add_ID {addr} {
+ set time 1
+ incr_pc 1
+ if {[check_address_validity I $addr]} {
+ alo_add [undefined_octet]
+ } {
+ alo_add $ram($addr)
+ }
+ evaluate_sfr 224
+}
+
+## Instruction: ADDC
+ # @parm Int val - Value to add to Acc
+ # @return void
+private method ins_addc {val} {
+ set time 1
+
+ alo_addc $val
+ incr_pc 1
+
+ evaluate_sfr 224
+}
+
+## Instruction: ADDC A, addr
+ # @parm Int addr - Value to add to Acc
+ # @return void
+private method ins_addc_D {addr} {
+ if {[check_address_validity D $addr]} {
+ ins_addc [undefined_octet]
+ return
+ }
+ if {$addr < 128} {
+ ins_addc $ram($addr)
+ } {
+ ins_addc [read_sfr $addr]
+ }
+}
+
+## Instruction: ADDC A, @Ri
+ # @parm Int addr - Indirect address
+ # @return void
+private method ins_addc_ID {addr} {
+ set time 1
+ incr_pc 1
+ if {[check_address_validity I $addr]} {
+ alo_addc [undefined_octet]
+ return
+ } {
+ alo_addc $ram($addr)
+ }
+}
+
+## Instruction: AJMP
+ # @parm Int haddr - High part of the target address
+ # @parm Int laddr - Low part of the target address
+ # @return void
+private method ins_ajmp {haddr laddr} {
+ set time 2
+ incr laddr [expr {$haddr << 8}]
+ set pc $laddr
+}
+
+## Instruction: ANL
+ # @parm Int addr - Register address
+ # @parm Int val - Operation arument
+ # @return void
+private method ins_anl {addr val} {
+ set time 2
+ if {[check_address_validity D $addr]} {return}
+ if {$addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set ram($addr) [expr {$ram($addr) & $val}]
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ set rmw_instruction 1
+ write_sfr $addr [expr {[read_sfr $addr] & $val}]
+ evaluate_sfr $addr
+ }
+}
+
+## Instruction: ANL A
+ # @parm Int val - Operation arument
+ # @return void
+private method ins_anl_A {val} {
+ set time 1
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ set sfr(224) [expr {$sfr(224) & $val}]
+ incr_pc 1
+ evaluate_sfr 224
+}
+
+## Instruction: ANL A, addr
+ # @parm Int addr - Address of register containing value to add
+ # @return void
+private method ins_anl_A_D {addr} {
+ if {[check_address_validity D $addr]} {return}
+ if {$addr < 128} {
+ ins_anl_A $ram($addr)
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ ins_anl_A [read_sfr $addr]
+ evaluate_sfr $addr
+ }
+}
+
+## Instruction: ANL A, @Ri
+ # @parm Int addr - Indirect address
+ # @return void
+private method ins_anl_A_ID {addr} {
+ set time 1
+ incr_pc 1
+ if {[check_address_validity I $addr]} {return}
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ set sfr(224) [expr {$sfr(224) & $ram($addr)}]
+ evaluate_sfr 224
+}
+
+## Instruction: ANL C, bit
+ # @parm Int addr - Bit address
+ # @return void
+private method ins_anl_C {addr} {
+ set time 2
+ if {[check_address_validity B $addr]} {return}
+ if {![getBit $addr]} {setBit $symbol(C) 0}
+ evaluate_bit $symbol(C)
+}
+
+## Instruction: ANL C, /bit
+ # @parm Int addr - Bit address
+ # @return void
+private method ins_anl_C_N {addr} {
+ set time 2
+ if {[check_address_validity B $addr]} {
+ setBit $symbol(C) [expr {rand() > 0.5}]
+ } {
+ if {[getBit $addr]} {setBit $symbol(C) 0}
+ }
+ evaluate_bit $symbol(C)
+}
+
+## Instruction: CJNE A, addr ...
+ # @parm Int addr - 2nd value to compare
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_cjne_AD {addr roff} {
+ if {[check_address_validity D $addr]} {
+ set val [undefined_octet]
+ } {
+ if {$addr < 128} {
+ set val $ram($addr)
+ } {
+ set val $sfr($addr)
+ }
+ }
+ ins_cjne $sfr(224) $val $roff
+}
+
+## Instruction: CJNE
+ # @parm Int val0 - 1st value to compare
+ # @parm Int val1 - 2nd value to compare
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_cjne {val0 val1 roff} {
+ set time 2
+
+ if {$val0 != $val1} {
+ if {$val0 < $val1} {
+ setBit $symbol(C) 1
+ } {
+ setBit $symbol(C) 0
+ }
+
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+ }
+}
+
+## Instruction: CJNE @Ri, ...
+ # @parm Int addr - Indirect address
+ # @parm Int val1 - 2nd value to compare
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_cjne_ID {addr val1 roff} {
+ set time 2
+
+ if {[check_address_validity I $addr]} {
+ set val0 [undefined_octet]
+ } {
+ set val0 $ram($addr)
+ }
+ if {$val0 != $val1} {
+ if {$val0 < $val1} {
+ setBit $symbol(C) 1
+ } {
+ setBit $symbol(C) 0
+ }
+
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+ }
+}
+
+## Instruction: CLR
+ # @parm String opr - Register name or bit address
+ # @return void
+private method ins_clr {opr} {
+ set time 1
+ incr_pc 1
+
+ # Primary accumulator (Acc)
+ if {$opr == {A}} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ set sfr(224) 0
+ evaluate_sfr 224
+ # Bit PSW.C
+ } elseif {$opr == {C}} {
+ setBit $symbol(C) 0
+ evaluate_bit $symbol(C)
+ # Some bit
+ } {
+ if {[check_address_validity B $opr]} {return}
+ set rmw_instruction 1
+ setBit $opr 0
+ evaluate_bit $opr
+ }
+}
+
+## Instruction: CPL
+ # @parm String opr - Register name or bit address
+ # @return void
+private method ins_cpl {opr} {
+ set time 1
+ incr_pc 1
+
+ # Primary accumulator (Acc)
+ if {$opr == {A}} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ set sfr(224) [expr {$sfr(224) ^ 255}]
+ evaluate_sfr 224
+ # Bit PSW.C
+ } elseif {$opr == {C}} {
+ if {[getBit $symbol(C)]} {
+ setBit $symbol(C) 0
+ } {
+ setBit $symbol(C) 1
+ }
+ evaluate_bit $symbol(C)
+ # Some bit
+ } {
+ if {[check_address_validity B $opr]} {return}
+ set rmw_instruction 1
+ if {[getBit $opr]} {
+ setBit $opr 0
+ } {
+ setBit $opr 1
+ }
+ evaluate_bit $opr
+ }
+}
+
+## Instruction: DA
+ # @return void
+private method ins_da {} {
+ set time 1
+ incr_pc 1
+
+ set hi [expr {($sfr(224) & 240) >> 4}]
+ set lo [expr {$sfr(224) & 15}]
+
+ if {($lo > 9) || [getBit $symbol(AC)]} {
+ incr lo 6
+ if { $lo > 15 } {
+ incr lo -16
+ incr hi 1
+ if { $hi > 15 } {
+ incr hi -16
+ setBit $symbol(C) 1
+ }
+ }
+ }
+ setBit $symbol(AC) 0
+
+ if {($hi > 9) || [getBit $symbol(C)]} {
+ incr hi 6
+ if { $hi > 15 } {
+ incr hi -16
+ setBit $symbol(C) 1
+ }
+ }
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ set sfr(224) [expr {($hi << 4) + $lo}]
+ evaluate_sfr 224
+}
+## Instruction: DEC
+ # @parm Int addr - Register to decrement
+ # @return void
+private method ins_dec {addr} {
+ set rmw_instruction 1
+ set time 1
+ incr_pc 1
+ incr_8b D $addr -1
+}
+
+## Instruction: DEC @Ri
+ # @parm Int addr - Register to decrement (indirect address)
+ # @return void
+private method ins_dec_ID {addr} {
+ set time 1
+ incr_pc 1
+ incr_8b I $addr -1
+}
+
+## Instruction: DIV
+ # @return void
+private method ins_div {} {
+ set time 4
+ incr_pc 1
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(A)
+ stepback_reg_change S $symbol(B)
+ }
+
+ setBit $symbol(C) 0
+ if {$sfr($symbol(B)) == 0} {
+ setBit $symbol(OV) 1
+ set sfr(224) 0
+ set sfr($symbol(B)) 0
+ } {
+ setBit $symbol(OV) 0
+ set A $sfr(224)
+ set sfr(224) [expr {$A / $sfr($symbol(B))}]
+ set sfr($symbol(B)) [expr {$A % $sfr($symbol(B))}]
+ }
+
+ evaluate_sfr 224
+ evaluate_sfr 240
+}
+
+## Instruction: DJNZ
+ # @parm Int addr - Register to decrement
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_djnz {addr roff} {
+ set rmw_instruction 1
+ set time 2
+
+ if {[incr_8b D $addr -1]} {return}
+ if {$addr > 127} {
+ if {[read_sfr $addr] != 0} {
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+ }
+ evaluate_sfr $addr
+ } {
+ if {$ram($addr) != 0} {
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+ }
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ }
+}
+
+## Instruction: INC
+ # @parm Int addr - Register to increment
+ # @return void
+private method ins_inc {addr} {
+ set rmw_instruction 1
+ set time 1
+ incr_pc 1
+ if {[incr_8b D $addr 1]} {return}
+ if {$addr > 127} {
+ evaluate_sfr $addr
+ } elseif {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+}
+
+## Instruction: INC @Ri
+ # @parm Int addr - Register to increment (indirect address)
+ # @return void
+private method ins_inc_ID {addr} {
+ set time 1
+ incr_pc 1
+ incr_8b I $addr 1
+}
+
+## Instruction: INC DPTR
+ # @return void
+private method ins_inc_DPTR {} {
+ set time 2
+ incr_pc 1
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol($DPL)
+ stepback_reg_change S $symbol($DPH)
+ }
+
+ incr sfr($symbol($DPL))
+ if {$sfr($symbol($DPL)) > 255} {
+ set sfr($symbol($DPL)) 0
+ incr sfr($symbol($DPH))
+ }
+
+ if {$sfr($symbol($DPH)) > 255} {
+ set sfr($symbol($DPH)) 0
+ }
+
+ evaluate_sfr $symbol($DPH)
+ evaluate_sfr $symbol($DPL)
+}
+
+## Instruction: JB
+ # @parm Int addr - Bit to test
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_jb {addr roff} {
+ set time 2
+ if {[check_address_validity B $addr]} {
+ set val [expr {rand() > 0.5}]
+ } {
+ set val [getBit $addr]
+ }
+ if {$val} {
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+ }
+}
+
+## Instruction: JNB
+ # @parm Int addr - Bit to test
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_jnb {addr roff} {
+ set time 2
+ if {[check_address_validity B $addr]} {
+ set val [expr {rand() > 0.5}]
+ } {
+ set val [getBit $addr]
+ }
+ if {!$val} {
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+ }
+}
+
+## Instruction: JBC
+ # @parm Int addr -
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_jbc {addr roff} {
+ set rmw_instruction 1
+ set time 2
+ if {[check_address_validity B $addr]} {
+ set val [expr {rand() > 0.5}]
+ } {
+ set val [getBit $addr]
+ }
+ if {$val} {
+ setBit $addr 0
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+ }
+}
+
+## Instruction: JC
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_jc {roff} {
+ ins_jb $symbol(C) $roff
+}
+
+## Instruction: JNC
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_jnc {roff} {
+ ins_jnb $symbol(C) $roff
+}
+
+## Instruction: JZ
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_jz {roff} {
+ set time 2
+ if {$sfr(224) == 0} {
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+ }
+}
+
+## Instruction: JNZ
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_jnz {roff} {
+ set time 2
+
+ if {$sfr(224) != 0} {
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+ }
+}
+
+## Instruction: JMP
+ # @return void
+private method ins_jmp {} {
+ set time 2
+ set pc [expr {($sfr(224) + $sfr($symbol($DPL))) + ($sfr($symbol($DPH)) << 8)}]
+ if {$pc > 65535} {
+ incr pc -65536
+ }
+}
+
+## Instruction: LCALL
+ # @parm Int haddr - High part of the target address
+ # @parm Int laddr - Low part of the target address
+ # @return void
+private method ins_lcall {haddr laddr} {
+ set time 2
+ stepback_save_spec_subprog 2
+
+ stack_push [expr {$pc & 255}]
+ stack_push [expr {($pc & 0xFF00) >> 8}]
+
+ set target [expr {($haddr << 8) + $laddr}]
+ incr run_statistics(6)
+ $this subprograms_call 0 $pc $target
+ $this stack_monitor_set_last_values_as 1 2
+ set pc $target
+}
+
+## Instruction: LJMP
+ # @parm Int haddr - High part of the target address
+ # @parm Int laddr - Low part of the target address
+ # @return void
+private method ins_ljmp {haddr laddr} {
+ set time 2
+ set pc [expr {($haddr << 8) + $laddr}]
+}
+
+## Instruction: MOV
+ # @parm Int addr - Register to set
+ # @parm Int val - New value
+ # @return void
+private method ins_mov {addr val} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity D $addr]} {return}
+ if {$addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set ram($addr) $val
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ write_sfr $addr $val
+ evaluate_sfr $addr
+ }
+}
+
+## Instruction: MOV
+ # @parm Int addr1 - Source register
+ # @parm Int addr0 - Target register
+ # @return void
+private method ins_mov_D {addr1 addr0} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity D $addr0]} {return}
+ if {[check_address_validity D $addr1]} {
+ set val [undefined_octet]
+ } {
+ if {$addr1 < 128} {
+ set val $ram($addr1)
+ } {
+ set val [read_sfr $addr1]
+ }
+ }
+
+ if {$addr0 < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr0
+ }
+ set ram($addr0) $val
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr0
+ }
+ } {
+ write_sfr $addr0 $val
+ evaluate_sfr $addr0
+ }
+}
+
+## Instruction: MOV @Ri, addr
+ # @parm Int addr0 - Register to set (indirect addresing)
+ # @parm Int addr1 - Source register
+ # @return void
+private method ins_mov_ID2 {addr0 addr1} {
+ if {[check_address_validity D $addr1]} {
+ ins_mov_ID0 $addr0 [undefined_octet]
+ } {
+ if {$addr1 < 128} {
+ ins_mov_ID0 $addr0 $ram($addr1)
+ } {
+ ins_mov_ID0 $addr0 [read_sfr $addr1]
+ }
+ }
+ set time 2
+}
+
+## Instruction: MOV
+ # @parm Int addr - Register to set
+ # @parm Int addr_id - Address of new value (indirect addresing)
+ # @return void
+private method ins_mov_ID1 {addr addr_id} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity D $addr]} {return}
+ if {[check_address_validity I $addr_id]} {
+ set val [undefined_octet]
+ } {
+ set val $ram($addr_id)
+ }
+ if {$addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set ram($addr) $val
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ write_sfr $addr $val
+ evaluate_sfr $addr
+ }
+}
+
+## Instruction: MOV @Ri, ..
+ # @parm Int addr - Register to set (indirect addresing)
+ # @parm Int val - New value
+ # @return void
+private method ins_mov_ID0 {addr val} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity I $addr]} {return}
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set ram($addr) $val
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+}
+
+## Instruction: MOV DPTR
+ # @parm Int haddr - High part of the new value
+ # @parm Int laddr - Low part of the new value
+ # @return void
+private method ins_mov_DPTR {hval lval} {
+ set time 2
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol($DPL)
+ stepback_reg_change S $symbol($DPH)
+ }
+ set sfr($symbol($DPL)) $lval
+ set sfr($symbol($DPH)) $hval
+
+ evaluate_sfr $symbol($DPH)
+ evaluate_sfr $symbol($DPL)
+}
+
+## Instruction: MOV Rx
+ # @parm Int idx - Register index (0..7) (target)
+ # @parm Int addr - Register address (source)
+ # @return void
+private method ins_mov_Rx_ADDR {idx addr} {
+ set time 2
+
+ set t_addr [R $idx]
+ if {[check_address_validity D $addr]} {return}
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $t_addr
+ }
+ if {$addr < 128} {
+ set ram($t_addr) $ram($addr)
+ } {
+ set ram($t_addr) [read_sfr $addr]
+ }
+
+ if {$sync_ena} {
+ $this Simulator_sync_reg $t_addr
+ }
+}
+
+## Instruction: MOV bit
+ # @parm String dest - Destination bit or 'C'
+ # @parm String source - Source bit or 'C'
+ # @return void
+private method ins_mov_bit {dest source} {
+ set time 1
+ if {$dest == {C}} {
+ if {[check_address_validity B $source]} {
+ set val [expr {rand() < 0.5}]
+ } {
+ set val [getBit $source]
+ }
+ if {$val} {
+ setBit $symbol(C) 1
+ } {
+ setBit $symbol(C) 0
+ }
+ } {
+ set rmw_instruction 1
+ incr time
+ if {[check_address_validity B $dest]} {return}
+ if {[getBit $symbol(C)]} {
+ setBit $dest 1
+ } {
+ setBit $dest 0
+ }
+ }
+}
+
+## Instruction: MOVC
+ # @parm String arg - Offset register (one of {DPTR PC})
+ # @return void
+private method ins_movc {arg} {
+ set time 2
+ incr_pc 1
+
+ # MOVC A, @A+DPTR
+ if {$arg == {DPTR}} {
+ set addr [expr {($sfr(224) + $sfr($symbol($DPL))) + ($sfr($symbol($DPH)) << 8)}]
+ # MOVC A, @A+PC
+ } {
+ set addr $pc
+ incr addr $sfr(224)
+ }
+
+ if {$addr > 65535} {
+ incr addr -65356
+ }
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ if {[check_address_validity C $addr]} {
+ set sfr(224) [undefined_octet]
+ } elseif {$code($addr) != {}} {
+ set sfr(224) $code($addr)
+ } {
+ set sfr(224) [undefined_octet]
+ }
+
+ evaluate_sfr 224
+}
+
+## Instruction: MOVX
+ # @parm String opr0 - Register name (one of {A R0 R1 DPTR})
+ # @parm String opr1 - Register name (one of {A R0 R1 DPTR})
+ # @return void
+private method ins_movx {opr0 opr1} {
+ set time 2
+ incr_pc 1
+
+ if {$opr1 == {R0}} {
+ set Saddr $ram([R 0])
+ } elseif {$opr1 == {R1}} {
+ set Saddr $ram([R 1])
+ } elseif {$opr1 == {DPTR}} {
+ set Saddr [expr {($sfr($symbol($DPH)) << 8) + $sfr($symbol($DPL))}]
+ }
+
+ if {$opr0 == {A}} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+
+ # Read from expanded data memory
+ if {$Saddr < $eram_size && !$controllers_conf(EXTRAM)} {
+ if {[check_address_validity E $Saddr]} {
+ set sfr(224) [undefined_octet]
+ } {
+ set sfr(224) $eram($Saddr)
+ }
+ # Read from data EEPROM
+ } elseif {$Saddr < $eeprom_size && $controllers_conf(EEMEN)} {
+ if {[check_address_validity P $Saddr]} {
+ set sfr(224) [undefined_octet]
+ } {
+ set complement_MSB 0
+ foreach reg $eeprom_prev {
+ if {$Saddr == [lindex $reg 0]} {
+ set complement_MSB 1
+ break
+ }
+ }
+ if {$complement_MSB} {
+ set sfr(224) [expr {$eeprom($Saddr) ^ 0x80}]
+ } {
+ set sfr(224) $eeprom($Saddr)
+ }
+ }
+ # Read from external data memory
+ } else {
+ if {$feature_avaliable(xram) && [$this pale_is_enabled]} {
+ for {set i -3} {$i < 0} {incr i} {
+ if {!$controllers_conf(X2)} {
+ $this pale_WPBBL $PIN(RD) {X} $i
+ $this pale_WPBL 0 X $i
+ $this pale_WPBL 2 X $i
+ incr i
+ $this pale_WPBBL $PIN(RD) {X} $i
+ $this pale_WPBL 0 X $i
+ $this pale_WPBL 2 X $i
+ } {
+ incr i
+ $this pale_WPBL 0 X [expr {int($i / 2)}]
+ $this pale_WPBL 2 X [expr {int($i / 2)}]
+ $this pale_WPBBL $PIN(RD) {X} [expr {int($i / 2)}]
+ }
+ }
+ }
+ if {[check_address_validity X $Saddr]} {
+ set sfr(224) [undefined_octet]
+ } {
+ set sfr(224) $xram($Saddr)
+ }
+ }
+
+ evaluate_sfr 224
+ return
+ } elseif {$opr0 == {R0}} {
+ set Daddr $ram([R 0])
+ } elseif {$opr0 == {R1}} {
+ set Daddr $ram([R 1])
+ } elseif {$opr0 == {DPTR}} {
+ set Daddr [expr {($sfr($symbol($DPH)) << 8) + $sfr($symbol($DPL))}]
+ }
+
+ # Write to expanded data memory
+ if {$Daddr < $eram_size && !$controllers_conf(EXTRAM)} {
+ if {[check_address_validity E $Daddr]} {return}
+ set eram($Daddr) $sfr(224)
+
+ # Write to data EEPROM
+ } elseif {$Daddr < $eeprom_size && $controllers_conf(EEMEN)} {
+ # Check if this operation is valid
+ if {[check_address_validity P $Daddr]} {return}
+ if {
+ !$controllers_conf(EEMWE) ||
+ !$controllers_conf(RDYBSY) ||
+ !$controllers_conf(WRTINH)
+ } then {
+ if {!${::Simulator::ignore_EEPROM_WR_fail}} {
+ $this simulator_EEPROM_WR_fail $pc $Line($pc)
+ internal_shutdown
+ }
+ return
+ }
+
+ # Append value to the buffer
+ set low_addr [expr {$Daddr & 0x1F}]
+ set eeprom_WR_buff($low_addr) $sfr(224)
+
+ # Synchronize with write buffer window
+ ::X::sync_eeprom_write_buffer $low_addr $this
+ set offset [format %X [expr {$Daddr & 0xFFE0}]]
+ set len [string length $offset]
+ if {$len < 4} {
+ set offset "[string repeat 0 [expr {4 - $len}]]$offset"
+ }
+ set eeprom_WR_ofs "0x$offset"
+ ::X::eeprom_write_buffer_set_offset $eeprom_WR_ofs $this
+
+ # Start EEPROM programing cycle
+ if {!$controllers_conf(EELD)} {
+ # Write data to data EEPROM
+ set eeprom_prev {}
+ set addr [expr {$Daddr & 0xFFE0}]
+ for {set i 0} {$i < 32} {incr i; incr addr} {
+ if {$eeprom_WR_buff($i) != {}} {
+ lappend eeprom_prev [list $addr $eeprom($addr)]
+ stepback_reg_change P $addr
+ set eeprom($addr) $eeprom_WR_buff($i)
+ ::X::sync_eeprom_mem_window [format %X $addr] 1 $this
+ }
+ set eeprom_WR_buff($i) {}
+ }
+
+ # Clear write buffer hexeditor
+ ::X::eeprom_write_buffer_set_offset {} $this
+ ::X::clear_eeprom_write_buffer $this
+
+ # Clear flag EECON.RDYBSY (EEPROM is busy)
+ $this sim_GUI_bit_set_clear 0 EECON RDYBSY
+ set sfr(150) [expr {$sfr(150) & 0xFD}]
+ set controllers_conf(RDYBSY) 0
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 150
+ }
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S 150
+ }
+
+ # Adjust engine configuration
+ set eeprom_WR_time 1
+ set eeprom_WR 1
+ $this simulator_GUI_invoke_write_to_eeprom
+ }
+ return
+
+ # Write to external data memory
+ } else {
+ if {$feature_avaliable(xram) && [$this pale_is_enabled]} {
+ for {set i -3} {$i < 0} {incr i} {
+ if {!$controllers_conf(X2)} {
+ $this pale_WPBBL $PIN(WR) {X} $i
+ $this pale_WPBL 0 X $i
+ $this pale_WPBL 2 X $i
+ incr i
+ $this pale_WPBBL $PIN(WR) {X} $i
+ $this pale_WPBL 0 X $i
+ $this pale_WPBL 2 X $i
+ } {
+ incr i
+ $this pale_WPBL 0 X [expr {int($i / 2)}]
+ $this pale_WPBL 2 X [expr {int($i / 2)}]
+ $this pale_WPBBL $PIN(WR) {X} [expr {int($i / 2)}]
+ }
+ }
+ }
+
+ if {[check_address_validity X $Daddr]} {return}
+ set xram($Daddr) $sfr(224)
+ }
+
+ if {$sync_ena} {
+ $this Simulator_XDATA_sync $Daddr
+ }
+}
+
+## Instruction: MUL
+ # @return void
+private method ins_mul {} {
+ set time 4
+ incr_pc 1
+
+ setBit $symbol(C) 0
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ stepback_reg_change S 240
+ }
+
+ set result [expr {$sfr(224) * $sfr(240)}]
+ if {$result > 255} {
+ set sfr(240) [expr {($result & 0xFF00) >> 8}]
+ setBit $symbol(OV) 1
+ } {
+ set sfr(240) 0
+ setBit $symbol(OV) 0
+ }
+ set sfr(224) [expr {$result & 255}]
+
+ evaluate_sfr 224
+ evaluate_sfr 240
+}
+
+## Instruction: NOP
+ # @return void
+private method ins_nop {} {
+ set time 1
+ incr_pc 1
+}
+
+## Instruction: ORL
+ # @parm Int addr - Register addres
+ # @parm Int val - Operation argument
+ # @return void
+private method ins_orl {addr val} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity D $addr]} {return}
+ if {$addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set ram($addr) [expr {$ram($addr) | $val}]
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ set rmw_instruction 1
+ write_sfr $addr [expr {[read_sfr $addr] | $val}]
+ evaluate_sfr $addr
+ }
+}
+
+## Instruction: ORL Addr0, Addr1
+ # 1st operand must be 224 !
+ # @parm Int addr0 - Register addres
+ # @parm Int addr1 - Operation argument
+ # @return void
+private method ins_orl_D {addr0 addr1} {
+ if {[check_address_validity D $addr1]} {
+ ins_orl $addr0 [undefined_octet]
+ } elseif {$addr1 < 128} {
+ ins_orl $addr0 $ram($addr1)
+ } {
+ ins_orl $addr0 [read_sfr $addr1]
+ }
+}
+
+## Instruction: ORL .., @Ri
+ # @parm Int addr - Target addres
+ # @parm Int addr_id - Source address (indirect)
+ # @return void
+private method ins_orl_ID {addr addr_id} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity D $addr]} {return}
+ if {[check_address_validity I $addr_id]} {
+ set val [undefined_octet]
+ } {
+ set val $ram($addr_id)
+ }
+ if {$addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set ram($addr) [expr {$ram($addr) | $val}]
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ set rmw_instruction 1
+ write_sfr $addr [expr {[read_sfr $addr] | $val}]
+ evaluate_sfr $addr
+ }
+}
+
+## Instruction: ORL C, /bit
+ # @parm Int addr - Bit address
+ # @return void
+private method ins_orl_not_bit {addr} {
+ set time 2
+
+ if {[check_address_validity B $addr]} {
+ setBit $symbol(C) [expr {rand() < 0.5}]
+ } elseif {[getBit $symbol(C)] || ![getBit $addr]} {
+ setBit $symbol(C) 1
+ } {
+ setBit $symbol(C) 0
+ }
+}
+
+## Instruction: ORL C, bit
+ # @parm Int addr - Bit address
+ # @return void
+private method ins_orl_bit {addr} {
+ set time 2
+
+ if {[check_address_validity B $addr]} {
+ setBit $symbol(C) [expr {rand() < 0.5}]
+ } elseif {[getBit $symbol(C)] || [getBit $addr]} {
+ setBit $symbol(C) 1
+ } {
+ setBit $symbol(C) 0
+ }
+}
+
+## Instruction: POP
+ # @parm Int addr - Register address (target)
+ # @return void
+private method ins_pop {addr} {
+ set time 2
+ stepback_save_spec_subprog 6
+
+ if {[check_address_validity D $addr]} {return}
+ if {$addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set ram($addr) [stack_pop]
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ write_sfr $addr [stack_pop]
+ evaluate_sfr $addr
+ }
+}
+
+## Instruction: PUSH
+ # @parm Int addr - Register address (source)
+ # @return void
+private method ins_push {addr} {
+ set time 2
+ stepback_save_spec_subprog 5
+
+ if {[check_address_validity D $addr]} {
+ stack_push [undefined_octet]
+ } elseif {$addr < 128} {
+ stack_push $ram($addr)
+ } else {
+ stack_push $sfr($addr)
+ }
+
+ $this stack_monitor_set_last_values_as 0 1
+}
+
+## Instruction: RET
+ # @return void
+private method ins_ret {} {
+ set time 2
+ stepback_save_spec_subprog 4
+
+ set pch [stack_pop]
+ set pcl [stack_pop]
+
+ set pc [expr {($pch << 8) + $pcl}]
+ incr run_statistics(7)
+ $this subprograms_return 0
+}
+
+## Instruction: RETI
+ # @return void
+private method ins_reti {} {
+ set time 2
+
+ if {[llength $inter_in_p_flags]} {
+ stepback_save_spec_subprog 3
+ set skip_interrupt 1
+ set interrupt_on_next 0
+ $this interrupt_monitor_reti [lindex $inter_in_p_flags end]
+ set interrupts_in_progress [lreplace $interrupts_in_progress end end]
+ set inter_in_p_flags [lreplace $inter_in_p_flags end end]
+ if {[llength $interrupts_in_progress]} {
+ set vector [format %X [intr2vector [lindex $interrupts_in_progress end]]]
+ simulator_Sbar [mc "Interrupt at vector 0x%s " $vector] 1 $this
+ } {
+ simulator_Sbar {} 0 $this
+ }
+ } {
+ $this simulator_invalid_reti_dlg $pc $Line($pc)
+ }
+
+ set pch [stack_pop]
+ set pcl [stack_pop]
+
+ set pc [expr {($pch << 8) + $pcl}]
+ incr run_statistics(8)
+ $this subprograms_return 1
+}
+
+## Instruction: RL
+ # @return void
+private method ins_rl {} {
+ set time 1
+ incr_pc 1
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ set sfr(224) [expr {$sfr(224) << 1}]
+ if {$sfr(224) > 255} {
+ incr sfr(224) -255
+ }
+
+ evaluate_sfr 224
+}
+
+## Instruction: RLC
+ # @return void
+private method ins_rlc {} {
+ set time 1
+ incr_pc 1
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ set sfr(224) [expr {$sfr(224) << 1}]
+
+ if {[getBit $symbol(C)]} {
+ incr sfr(224)
+ }
+ if {$sfr(224) > 255} {
+ incr sfr(224) -256
+ setBit $symbol(C) 1
+ } {
+ setBit $symbol(C) 0
+ }
+
+ evaluate_sfr 224
+}
+
+## Instruction: RR
+ # @return void
+private method ins_rr {} {
+ set time 1
+ incr_pc 1
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ if {[expr {$sfr(224) % 2}]} {
+ set C 1
+ } {
+ set C 0
+ }
+
+ set sfr(224) [expr {$sfr(224) / 2}]
+
+ if {$C} {incr sfr(224) 128}
+
+ evaluate_sfr 224
+}
+
+## Instruction: RRC
+ # @return void
+private method ins_rrc {} {
+ set time 1
+ incr_pc 1
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ if {[expr {$sfr(224) % 2}]} {
+ set C 1
+ } {
+ set C 0
+ }
+
+ set sfr(224) [expr {$sfr(224) / 2}]
+
+ if {[getBit $symbol(C)]} {
+ incr sfr(224) 128
+ }
+
+ if {$C} {
+ setBit $symbol(C) 1
+ } {
+ setBit $symbol(C) 0
+ }
+
+ evaluate_sfr 224
+}
+
+## Instruction: SETB
+ # @parm String opr - Bit address or 'C'
+ # @return void
+private method ins_setb {opr} {
+ set time 1
+ incr_pc 1
+
+ if {$opr == {C}} {
+ setBit $symbol(C) 1
+ } {
+ if {[check_address_validity B $opr]} {return}
+ set rmw_instruction 1
+ setBit $opr 1
+ }
+}
+
+## Instruction: SJMP
+ # @parm Int roff - Relative offset for jump
+ # @return void
+private method ins_sjmp {roff} {
+ set time 2
+
+ if {$roff > 127} {incr roff -256}
+ incr_pc $roff
+}
+
+## Instruction: SUBB A, ...
+ # @parm Int val - Value
+ # @return void
+private method ins_subb {val} {
+ set time 1
+ incr_pc 1
+ alo_subb $val
+
+ evaluate_sfr 224
+}
+
+## Instruction: SUBB A, Addr
+ # @parm Int addr - Value
+ # @return void
+private method ins_subb_D {addr} {
+ if {[check_address_validity D $addr]} {
+ ins_subb [undefined_octet]
+ } elseif {$addr < 128} {
+ ins_subb $ram($addr)
+ } {
+ ins_subb $sfr($addr)
+ }
+}
+
+## Instruction: SUBB A, @Ri
+ # @parm Int addr - Indirect address
+ # @return void
+private method ins_subb_ID {addr} {
+ set time 1
+ incr_pc 1
+ if {[check_address_validity I $addr]} {
+ ins_subb [undefined_octet]
+ } {
+ alo_subb $ram($addr)
+ }
+ evaluate_sfr 224
+}
+
+## Instruction: SWAP
+ # @return void
+private method ins_swap {} {
+ set time 1
+ incr_pc 1
+
+ set lo [expr {$sfr(224) & 15}]
+ set hi [expr {($sfr(224) & 240) >> 4}]
+
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+ set sfr(224) [expr {($lo << 4) + $hi}]
+
+ evaluate_sfr 224
+}
+
+## Instruction: XCH
+ # @parm Int addr - Register address
+ # @return void
+private method ins_xch {addr} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity D $addr]} {return}
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ }
+
+ set A $sfr(224)
+ if {$addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set sfr(224) $ram($addr)
+ set ram($addr) $A
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ set sfr(224) [read_sfr $addr]
+ write_sfr $addr $A
+ evaluate_sfr $addr
+ }
+ evaluate_sfr 224
+}
+
+## Instruction: XCH @Ri
+ # @parm Int addr - Register address (indirect addressing)
+ # @return void
+private method ins_xch_ID {addr} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity I $addr]} {return}
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ stepback_reg_change I $addr
+ }
+
+ set A $sfr(224)
+ set sfr(224) $ram($addr)
+ set ram($addr) $A
+
+ evaluate_sfr 224
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+}
+
+## Instruction: XCHD
+ # @parm Int addr - Register address
+ # @return void
+private method ins_xchd {addr} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity I $addr]} {
+ set val [undefined_octet]
+ } elseif {$addr < 128} {
+ set val $ram($addr)
+ } {
+ set val $sfr($addr)
+ }
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 224
+ if {$addr < 128} {
+ stepback_reg_change I $addr
+ } {
+ stepback_reg_change S $addr
+ }
+ }
+
+ set nibble0 [expr {$sfr(224) & 15}]
+ set nibble1 [expr {$val & 15}]
+
+ set sfr(224) [expr {($sfr(224) & 240) + $nibble1}]
+ set val [expr {($val & 240) + $nibble0}]
+ if {$addr < 128} {
+ set ram($addr) $val
+ } {
+ set sfr($addr) $val
+ }
+
+ evaluate_sfr 224
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+}
+
+## Instruction: XRL
+ # @parm Int addr - Register address
+ # @parm Int val - Operation argument
+ # @return void
+private method ins_xrl {addr val} {
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity D $addr]} {return}
+ if {$addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set ram($addr) [expr {$ram($addr) ^ $val}]
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ set rmw_instruction 1
+ write_sfr $addr [expr {[read_sfr $addr] ^ $val}]
+ evaluate_sfr $addr
+ }
+}
+
+## Instruction: XRL ..., addr
+ # @parm Int addr0 - Target register
+ # @parm Int addr1 - Source register
+ # @return void
+private method ins_xrl_D {addr0 addr1} {
+ if {[check_address_validity D $addr1]} {
+ ins_xrl $addr0 [undefined_octet]
+ } elseif {$addr1 < 128} {
+ ins_xrl $addr0 $ram($addr1)
+ } {
+ ins_xrl $addr0 [read_sfr $addr1]
+ }
+}
+
+## Instruction: XRL .., @Ri
+ # @parm Int addr - Register address
+ # @parm Int addr_id - Indirect address
+ # @return void
+private method ins_xrl_ID {addr addr_id} {
+ set rmw_instruction 1
+ set time 1
+ incr_pc 1
+
+ if {[check_address_validity I $addr_id]} {
+ set val [undefined_octet]
+ } {
+ set val $ram($addr_id)
+ }
+ if {$addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+ set ram($addr) [expr {$ram($addr) ^ $val}]
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+ } {
+ set rmw_instruction 1
+ write_sfr $addr [expr {[read_sfr $addr] ^ $val}]
+ evaluate_sfr $addr
+ }
+}
diff --git a/lib/simulator/engine/engine_mcu_configuration.tcl b/lib/simulator/engine/engine_mcu_configuration.tcl
new file mode 100755
index 0000000..7701583
--- /dev/null
+++ b/lib/simulator/engine/engine_mcu_configuration.tcl
@@ -0,0 +1,555 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# MCU CONFIGURATION RELATED PROCEDURES
+# --------------------------------------------------------------------------
+
+
+## Increment program overall time
+ # This function also manages watchdog and data EEPROM
+ # @parm Int num - Number of instruction cycles
+ # @return Bool - 1 == device reseted; 0 == normal
+private method increment_program_time {num} {
+ # Increment counter of instruction cycles
+ incr overall_instructions $num
+ incr run_statistics(2) $num
+
+ # Increment overall time
+ if {$controllers_conf(X2)} {
+ set num [expr {$num / 2.0}]
+ }
+ set overall_time [expr {$overall_time + $num}]
+ incr run_statistics(1) [expr {int($num * 12)}]
+ if {$clock_kHz != 0 && $clock_kHz != {}} {
+ incr run_statistics(0) [expr {int($num * (12000000.0 / $clock_kHz))}]
+ }
+
+ eeprom_controller $num
+ return [watchdog_controller]
+}
+
+## Adjust configuration acording to new value of the given bit
+ # @parm Int addr - Bit address
+ # @return void
+private method evaluate_bit {addr} {
+ if {$addr < 128} {
+ if {$sync_ena} {
+ $this Simulator_sync_reg [getRegOfBit $addr]
+ }
+ } {
+ evaluate_sfr [getRegOfBit $addr]
+ }
+}
+
+## Evaluate list of interrupt priorities acording to values of IP and IPH
+ # @return void
+private method evaluate_interrupt_priorities {} {
+ # Determinate value of Interrupt Priority High register
+ if {$feature_avaliable(iph)} {
+ set iph $sfr(183)
+ } {
+ set iph 0
+ }
+
+ # Lists of priority flags
+ set ip_0 {}
+ set ip_1 {}
+ set ip_2 {}
+ set ip_3 {}
+
+ # Lists of priority levels
+ set pl_0 {}
+ set pl_1 {}
+ set pl_2 {}
+ set pl_3 {}
+ set ip 0
+
+ # Determinate list of priority flags and priority levels in decremental order
+ foreach key {PX0 PT0 PX1 PT1 PS PT2 PC} mask {1 2 4 8 16 32 64} {
+ set ip 0
+ if {[expr {$sfr(184) & $mask}]} {
+ incr ip
+ }
+ if {[expr {$iph & $mask}]} {
+ incr ip 2
+ }
+ switch -- $ip {
+ 0 {lappend ip_0 $key}
+ 1 {lappend ip_1 $key}
+ 2 {lappend ip_2 $key}
+ 3 {lappend ip_3 $key}
+ }
+ lappend pl_${ip} $ip
+ }
+ set controllers_conf(IP) [concat $ip_3 $ip_2 $ip_1 $ip_0]
+ set controllers_conf(IP_level) [concat $pl_3 $pl_2 $pl_1 $pl_0]
+
+ # Determinate list of interrupts flags and priority levels in decremental order
+ set interrupt_pri_flg {}
+ set interrupt_pri_num {}
+ foreach flag $controllers_conf(IP) ip $controllers_conf(IP_level) {
+ switch -- $flag {
+ PS {
+ if {$feature_avaliable(uart)} {
+ lappend interrupt_pri_flg RI TI
+ lappend interrupt_pri_num $ip $ip
+ }
+ if {$feature_avaliable(spi)} {
+ lappend interrupt_pri_flg SPIF
+ lappend interrupt_pri_num $ip
+ }
+ }
+ PT2 {
+ if {!$feature_avaliable(t2)} {continue}
+ lappend interrupt_pri_flg EXF2 TF2
+ lappend interrupt_pri_num $ip $ip
+ }
+ PX0 {
+ lappend interrupt_pri_flg IE0
+ lappend interrupt_pri_num $ip
+ }
+ PT0 {
+ lappend interrupt_pri_flg TF0
+ lappend interrupt_pri_num $ip
+ }
+ PX1 {
+ lappend interrupt_pri_flg IE1
+ lappend interrupt_pri_num $ip
+ }
+ PT1 {
+ lappend interrupt_pri_flg TF1
+ lappend interrupt_pri_num $ip
+ }
+ PC {
+ if {!$feature_avaliable(acomparator)} {continue}
+ lappend interrupt_pri_flg CF
+ lappend interrupt_pri_num $ip
+ }
+ }
+ }
+
+ # Adjust interrup monitor
+ $this interrupt_monitor_intr_prior $interrupt_pri_flg
+}
+
+## Adjust configuration acording to new value of the given SFR
+ # @parm Int - Register address
+ # @parm Bool = 1 - Synchronize this SFR with external interface
+ # @return void
+private method evaluate_sfr args {
+ set addr [lindex $args 0]
+ set sync [lindex $args 1]
+
+ switch -- $addr {
+ 135 { ;# PCON 0x87
+ set SMOD0_prev $controllers_conf(SMOD0)
+
+ write_conf 135 {SMOD1 SMOD0 PWMEN POF GF1 GF0 PD IDL}
+
+ if {$SMOD0_prev != $controllers_conf(SMOD0)} {
+ $this simulator_gui_SMOD0_changed
+ }
+ }
+ 168 { ;# IE 0xA8
+ write_conf 168 {EA EC ET2 ES ET1 EX1 ET0 EX0}
+
+ # Inform interrupt monitor
+ $this interrupt_monitor_intr_ena_dis
+ }
+ 184 { ;# IP 0xB8
+ evaluate_interrupt_priorities
+ }
+ 152 { ;# SCON 0x98
+ write_conf 152 {- SM1 SM2 REN TB8 RB8 TI RI}
+
+ # Determinate SM0 and FE
+ if {$controllers_conf(SMOD0)} {
+ set controllers_conf(FE) [expr {($sfr(152) & 0x80) ? 1 : 0}]
+ } {
+ set controllers_conf(SM0) [expr {($sfr(152) & 0x80) ? 1 : 0}]
+ }
+
+ # Determinate UART operating mode
+ set UART_M_prev $controllers_conf(UART_M)
+ set controllers_conf(UART_M) [expr {$controllers_conf(SM0) * 2 + $controllers_conf(SM1)}]
+ if {$timer_0_running && $UART_M_prev != $controllers_conf(UART_M)} {
+ $this simulator_invalid_uart_mode_change $pc $Line($pc)
+ internal_shutdown
+ }
+
+ # Inform interrupt monitor
+ $this interrupt_monitor_intr_flags [simulator_get_active_intr_flags]
+ }
+ 136 { ;# TCON 0x88
+ write_conf 136 {TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0}
+
+ # Inform interrupt monitor
+ $this interrupt_monitor_intr_flags [simulator_get_active_intr_flags]
+ }
+ 137 { ;# TMOD 0x89
+ write_conf 137 {GATE1 CT1 M11 M01 GATE0 CT0 M10 M00}
+
+ set T0_MOD_prev $controllers_conf(T0_MOD)
+ set T1_MOD_prev $controllers_conf(T1_MOD)
+
+ set controllers_conf(T0_MOD) [expr {$controllers_conf(M10) * 2 + $controllers_conf(M00)}]
+ set controllers_conf(T1_MOD) [expr {$controllers_conf(M11) * 2 + $controllers_conf(M01)}]
+
+ # Manual: It is important to stop timer/counter before changing modes
+ if {$timer_0_running && $T0_MOD_prev != $controllers_conf(T0_MOD)} {
+ $this simulator_invalid_timer_mode_change 0 $pc $Line($pc)
+ internal_shutdown
+ }
+ if {$timer_1_running && $T1_MOD_prev != $controllers_conf(T1_MOD)} {
+ $this simulator_invalid_timer_mode_change 1 $pc $Line($pc)
+ internal_shutdown
+ }
+ }
+ 208 { ;# PSW 0xD0
+ set bank [expr {($sfr(208) & 24) >> 3}]
+ }
+ 224 { ;# A 0xE0
+ set A 0
+ set count 0
+ set mask 1
+ for {set i 0} {$i < 8} {incr i} {
+ if {[expr {$sfr(224) & $mask}] > 0} {
+ incr count
+ }
+ set mask [expr {$mask << 1}]
+ }
+
+ if {[expr {$count % 2}] == 1} {
+ setBit $symbol(P) 1
+ } {
+ setBit $symbol(P) 0
+ }
+ }
+
+ 162 { ;# AUXR1 0xA2
+ set DPS_org $controllers_conf(DPS)
+ write_conf 162 {- - - - - - - DPS}
+
+ # Switch visible dual DPTR
+ if {!$feature_avaliable(hddptr)} {
+ if {$controllers_conf(DPS)} {
+ set DPL {DP1L}
+ set DPH {DP1H}
+ } {
+ set DPL {DP0L}
+ set DPH {DP0H}
+ }
+
+ # Switch hidden dual DPTR
+ } elseif {$DPS_org != $controllers_conf(DPS)} {
+ if {$DPS_org} {
+ set hidden_DPTR1 [list $sfr($symbol(DP0L)) $sfr($symbol(DP0H))]
+ } {
+ set hidden_DPTR0 [list $sfr($symbol(DP0L)) $sfr($symbol(DP0H))]
+ }
+ if {$controllers_conf(DPS)} {
+ set sfr($symbol(DP0L)) [lindex $hidden_DPTR1 0]
+ set sfr($symbol(DP0H)) [lindex $hidden_DPTR1 1]
+ } {
+ set sfr($symbol(DP0L)) [lindex $hidden_DPTR0 0]
+ set sfr($symbol(DP0H)) [lindex $hidden_DPTR0 1]
+ }
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(DP0L)
+ $this Simulator_GUI_sync S $symbol(DP0H)
+ }
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(DP0L)
+ stepback_reg_change S $symbol(DP0H)
+ }
+ }
+ }
+ 142 { ;# AUXR 0x8E
+ if {$feature_avaliable(wdtcon)} {
+ if {$feature_avaliable(intelpe)} {
+ write_conf 142 {- - - - - - IPE DISALE}
+ } {
+ write_conf 142 {- - - - - - EXTRAM DISALE}
+ }
+ } {
+ write_conf 142 {- - - WDIDLE DISRTO - EXTRAM DISALE}
+ }
+ }
+ 166 { ;# WDTRST 0xA6
+ if {$controllers_conf(HWDT)} {
+ if {$sfr(166) == 225 && $wdtrst_prev_val == 30} {
+ set controllers_conf(WatchDogTimer) 1
+ set watchdog_value -$time
+
+ if {$feature_avaliable(wdtcon)} {
+ set controllers_conf(WDTEN) 1
+ set sfr(167) [expr {$sfr(167) | 1}]
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 167
+ }
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S 167
+ }
+ }
+ }
+ set wdtrst_prev_val $sfr(166)
+ }
+ }
+ 200 { ;# T2CON 0xC8
+ write_conf 200 {TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2}
+
+ # Inform interrupt monitor
+ $this interrupt_monitor_intr_flags [simulator_get_active_intr_flags]
+ }
+ 201 { ;# T2MOD 0xC9
+ write_conf 201 {- - - - - - T2OE DCEN}
+ }
+ 143 { ;# CLKREG/CKCON 0x8F
+ write_conf 143 {- - - - - - PWDEX X2}
+ }
+ 151 { ;# ACSR 0x97
+ write_conf 151 {- - - CF CEN CM2 CM1 CM0}
+
+ set controllers_conf(AC_MOD) [expr {
+ $controllers_conf(CM0) * 1 +
+ $controllers_conf(CM1) * 2 +
+ $controllers_conf(CM2) * 4
+ }]
+
+ # Inform interrupt monitor
+ $this interrupt_monitor_intr_flags [simulator_get_active_intr_flags]
+ }
+ 183 { ;# IPH 0xB7
+ evaluate_interrupt_priorities
+ }
+ 213 { ;# SPCR 0xD5
+ write_conf 213 {SPIE SPE DORD MSTR CPOL CPHA SPR1 SPR0}
+ }
+ 170 { ;# SPSR 0xAA
+ write_conf 170 {SPIF WCOL LDEN - - - DISSO ENH}
+
+ # Inform interrupt monitor
+ $this interrupt_monitor_intr_flags [simulator_get_active_intr_flags]
+ }
+ 167 { ;# WDTCON/WDTPRG 0xA7
+ if {$feature_avaliable(wdtprg)} {
+ write_conf 167 {- - - - - PS2 PS1 PS0}
+ } {
+ write_conf 167 {PS2 PS1 PS0 WDIDLE DISRTO HWDT WSWRST WDTEN}
+ }
+ set controllers_conf(WatchDogPrescaler) 0
+ if {$controllers_conf(PS2)} {
+ incr controllers_conf(WatchDogPrescaler) 4
+ }
+ if {$controllers_conf(PS1)} {
+ incr controllers_conf(WatchDogPrescaler) 2
+ }
+ if {$controllers_conf(PS0)} {
+ incr controllers_conf(WatchDogPrescaler) 1
+ }
+ set controllers_conf(WatchDogPrescaler) \
+ [expr {int(pow(2,$controllers_conf(WatchDogPrescaler)))}]
+ }
+ 150 { ;# EECON 0x96
+ set bit_RDYBSY $controllers_conf(RDYBSY)
+ set bit_WRTINH $controllers_conf(WRTINH)
+
+ write_conf 150 {- - EELD EEMWE EEMEN DPS RDYBSY WRTINH}
+
+ # Bits RDYBSY and WRTINH are READ-ONLY
+ if {
+ $controllers_conf(RDYBSY) != $bit_RDYBSY
+ ||
+ $controllers_conf(WRTINH) != $bit_WRTINH
+ } then {
+ set sfr(150) [expr {(($sfr(150) & 0xFC) | $bit_RDYBSY * 2) | $bit_WRTINH}]
+ }
+ set controllers_conf(RDYBSY) $bit_RDYBSY
+ set controllers_conf(WRTINH) $bit_WRTINH
+
+ if {$controllers_conf(DPS)} {
+ set DPL {DP1L}
+ set DPH {DP1H}
+ } {
+ set DPL {DP0L}
+ set DPH {DP0H}
+ }
+ }
+ default { ;# Nothing to do ...
+ }
+ }
+
+ # Synchronize with an external interface
+ if {$sync_ena && $sync != {0}} {
+ $this Simulator_GUI_sync S $addr
+ }
+}
+
+## Modify configuration
+ # @parm Int addr - Source register
+ # @parm List key_list - List of keys for array controllers_conf
+ # @return void
+private method write_conf {addr key_list} {
+ set mask 256
+ foreach key $key_list {
+
+ set mask [expr {$mask >> 1}]
+ if {$key == {-}} {continue}
+
+ if {[expr {$sfr($addr) & $mask}] == 0} {
+ set controllers_conf($key) 0
+ } {
+ set controllers_conf($key) 1
+ }
+ }
+}
+
+## Increment program counter
+ # @parm Int val - Value to increment by
+ # @return void
+private method incr_pc {val} {
+ set pc [incr_16b $pc $val]
+}
+
+## Increment 16 bit value
+ # @parm Int val - Value to increment
+ # @parm Int byVal - Value to increment by
+ # @return Int - 16 bit result
+private method incr_16b {val byVal} {
+ incr val $byVal
+ if {$val > 65535} {
+ incr val -65536
+ } elseif {$val < 0} {
+ incr val 65536
+ }
+ return $val
+}
+
+## Increment 8 bit value
+ # @parm Char type - D == Direct addressing; I == Indirect addressing
+ # @parm Int addr - Register to increment
+ # @parm Int val - Value to increment by
+ # @return Bool - 0 == successful; 1 == failed
+private method incr_8b {type addr val} {
+ if {[check_address_validity $type $addr]} {return 1}
+
+ # Indirect addressing
+ if {$type == {I} || $addr < 128} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $addr
+ }
+
+ incr ram($addr) $val
+ if {$ram($addr) > 255} {
+ incr ram($addr) -256
+ } elseif {$ram($addr) < 0} {
+ incr ram($addr) 256
+ }
+ if {$sync_ena} {
+ $this Simulator_sync_reg $addr
+ }
+
+ # Direct addressing
+ } else {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $addr
+ }
+
+ incr sfr($addr) $val
+ set val [read_sfr $addr]
+ if {$val > 255} {
+ incr sfr($addr) -256
+ } elseif {$val < 0} {
+ incr sfr($addr) 256
+ }
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $addr
+ }
+ }
+ return 0
+}
+
+## Pop value from stack
+ # @return Int - result
+private method stack_pop {} {
+ if {[check_address_validity I $sfr(129)]} {
+ set result [undefined_octet]
+ } {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $sfr(129)
+ }
+ set result $ram($sfr(129)) ;# 129d == 0x81 == SP
+ }
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 129
+ }
+ incr sfr(129) -1
+ if {$sfr(129) < 0} {
+ set sfr(129) 255
+ if {!${::Simulator::ignore_stack_underflow}} {
+ $this simulator_stack_warning under $pc [lindex $Line($pc) 0]
+ internal_shutdown
+ }
+ }
+
+ evaluate_sfr 129
+ $this stack_monitor_pop
+
+ return $result
+}
+
+## Push value onto stack
+ # @parm Int - Value to push onto stack
+ # @return void
+public method stack_push {val} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 129
+ }
+ incr sfr(129) ;# 129d == 0x81 == SP
+ if {$sfr(129) > 255} {
+ set sfr(129) 0
+ if {!${::Simulator::ignore_stack_overflow}} {
+ $this simulator_stack_warning over $pc [lindex $Line($pc) 0]
+ internal_shutdown
+ }
+ }
+ if {[check_address_validity I $sfr(129)]} {
+ return
+ } {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change I $sfr(129)
+ }
+ set ram($sfr(129)) $val
+ if {$sync_ena} {
+ $this Simulator_sync_reg $sfr(129)
+ }
+ }
+
+ evaluate_sfr 129
+ $this stack_monitor_push $sfr(129) $val
+}
diff --git a/lib/simulator/engine/engine_memory_management.tcl b/lib/simulator/engine/engine_memory_management.tcl
new file mode 100755
index 0000000..acf2978
--- /dev/null
+++ b/lib/simulator/engine/engine_memory_management.tcl
@@ -0,0 +1,387 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# MEMORY MANAGEMENT RELATED PROCEDURES
+# --------------------------------------------------------------------------
+
+## Get value of the next operand
+ # @return Int - OP code
+private method getNextOperand {} {
+ incr_pc 1
+ incr run_statistics(4)
+ if {[check_address_validity C $pc]} {
+ set result [undefined_octet]
+
+ bell
+ $this sim_txt_output [mc "Incomplete instruction (undefined operand/value missing in memory) at 0x%s" [NumSystem::dec2hex $pc]]
+ return [undefined_octet]
+ } {
+ if {$code($pc) == {}} {
+ $this sim_txt_output [mc "Incomplete instruction (undefined operand/value missing in memory) at 0x%s. Using 0FFh as operand !" [NumSystem::dec2hex $pc]]
+ return 255
+ } {
+ return $code($pc)
+ }
+ }
+}
+
+## Get value of the last operand
+ # @return Int - OP code
+private method getLastOperand {} {
+ incr_pc 1
+ incr run_statistics(4)
+ if {[check_address_validity C $pc]} {
+ bell
+ $this sim_txt_output [mc "Incomplete instruction (undefined operand/value missing in memory) at 0x%s" [NumSystem::dec2hex $pc]]
+ set result [undefined_octet]
+ } {
+ if {$code($pc) == {}} {
+ $this sim_txt_output [mc "Incomplete instruction (undefined operand/value missing in memory) at 0x%s. Using 0FFh as operand !" [NumSystem::dec2hex $pc]]
+ set result 255
+ } {
+ set result $code($pc)
+ }
+ }
+
+ incr_pc 1
+ return $result
+}
+
+## Get address of Rx register of current bank
+ # @parm int idx - number of register [0;7]
+ # @return int - address (decimal)
+private method R {idx} {
+ incr idx [expr {$bank * 8}]
+ return $idx
+}
+
+## Set bit at address $addr to value of $value
+ # @parm int addr - bit address (decimal)
+ # @parm bool value - bit value
+ # @return bool - 1: bit value changed; 0: nothing happened
+public method setBit {addr value} {
+
+ set regAddr [getRegOfBit $addr]
+ set bitNumber [expr {$addr % 8}]
+
+ if {${::Simulator::reverse_run_steps}} {
+ if {$regAddr < 128} {
+ stepback_reg_change I $regAddr
+ } {
+ stepback_reg_change S $regAddr
+ }
+ }
+
+ switch -- $bitNumber {
+ 7 {set mask 128}
+ 6 {set mask 64}
+ 5 {set mask 32}
+ 4 {set mask 16}
+ 3 {set mask 8}
+ 2 {set mask 4}
+ 1 {set mask 2}
+ 0 {set mask 1}
+ }
+
+ if {$regAddr < 0x80} {
+ if {([expr {$ram($regAddr) & $mask}] > 0) && !$value} {
+ set ram($regAddr) [expr {$ram($regAddr) ^ $mask}]
+ } elseif {([expr {$ram($regAddr) & $mask}] == 0) && $value} {
+ set ram($regAddr) [expr {$ram($regAddr) ^ $mask}]
+ }
+ } {
+ set sfr_val [read_sfr $regAddr]
+ if {([expr {$sfr_val & $mask}] > 0) && !$value} {
+ write_sfr $regAddr [expr {$sfr_val ^ $mask}]
+ } elseif {([expr {$sfr_val & $mask}] == 0) && $value} {
+ write_sfr $regAddr [expr {$sfr_val ^ $mask}]
+ }
+ }
+
+ if {$regAddr > 127} {
+ evaluate_sfr $regAddr
+ } {
+ if {$sync_ena} {
+ $this Simulator_sync_reg $regAddr
+ }
+ }
+}
+
+## Get bit value by bit address
+ # @parm int addr - bit address (decimal)
+ # @return bool
+public method getBit {addr} {
+ set regAddr [getRegOfBit $addr]
+ set bitNumber [expr {$addr % 8}]
+
+ return [getBitByReg $regAddr $bitNumber]
+}
+
+## Get bit value by register address and bit number
+ # @attribite int regAddr - register address (decimal)
+ # @attrinte int bitNumber - bit number (eg. 5)
+ # @return bool
+public method getBitByReg {regAddr bitNumber} {
+ switch -- $bitNumber {
+ 7 {set mask 128}
+ 6 {set mask 64}
+ 5 {set mask 32}
+ 4 {set mask 16}
+ 3 {set mask 8}
+ 2 {set mask 4}
+ 1 {set mask 2}
+ 0 {set mask 1}
+ }
+
+ if {$regAddr < 0x80} {
+ if {[expr {$ram($regAddr) & $mask}] == 0} {
+ return 0
+ } {
+ return 1
+ }
+ } {
+ if {[lsearch -ascii -exact $PORT_LATCHES $regAddr] != -1} {
+ set byte [read_sfr $regAddr]
+ } {
+ set byte $sfr($regAddr)
+ }
+
+ if {[expr {$byte & $mask}] == 0} {
+ return 0
+ } {
+ return 1
+ }
+ }
+}
+
+## Get address of register containing bit specified by argument
+ # @parm int addr - bit address (decimal)
+ # @return int - register address
+public method getRegOfBit {addr} {
+ set reg [expr {$addr / 8}]
+
+ if {$addr > 127} {
+ set reg [expr {$reg * 8}]
+ } {
+ incr reg 32
+ }
+
+ return $reg
+}
+
+## Get current register bank
+ # Thank you Kostya V. Ivanov !
+ # @return Int - Bank (0..3)
+public method getBank {} {
+ return $bank
+}
+
+## Check if the specified address at the given location is implemented in this MCU
+ # If check fail, this procedure will invoke error message and stop simulator
+ # @parm Char location - Memory type
+ # D == IDATA direct addressing
+ # I == IDATA indirect addressing (or operations on stack)
+ # X == XDATA
+ # B == Bit area
+ # C == CODE
+ # @parm Int address - Memory address (0..65536)
+ # @return Bool - result (false == memory implemented; true == invalid access)
+private method check_address_validity {location address} {
+ if {$address_error} {return 1}
+
+ if {[simulator_address_range $location $address]} {
+ return 0
+ }
+
+ switch -- $location {
+ {D} { ;# IDATA direct addressing
+ if {${::Simulator::ignore_invalid_IDATA}} {
+ return 1
+ }
+ }
+ {I} { ;# IDATA indirect addressing (or operations with stack)
+ if {${::Simulator::ignore_invalid_IDATA}} {
+ return 1
+ }
+ }
+ {X} { ;# XDATA
+ if {${::Simulator::ignore_invalid_XDATA}} {
+ return 1
+ }
+ }
+ {B} { ;# Bit area
+ if {${::Simulator::ignore_invalid_BIT}} {
+ return 1
+ }
+ }
+ {C} { ;# CODE
+ if {${::Simulator::ignore_invalid_CODE}} {
+ return 1
+ }
+ }
+ }
+
+ internal_shutdown
+ $this invalid_addressing_dialog $location $address
+ set address_error 1
+ return 1
+}
+
+## Check if the specified address at the given location is implemented in this MCU
+ # @parm Char location - Memory type
+ # D == IDATA direct addressing or SFR
+ # I == IDATA indirect addressing (or operations on stack)
+ # B == Bit area
+ # X == XDATA
+ # C == CODE
+ # E == ERAM
+ # P == Data EEPROM
+ # @parm Int address - Memory address (0..65536)
+ # @return Bool - result (true == memory implemented; false == invalid access)
+public method simulator_address_range {location address} {
+ switch -- $location {
+ {D} { ;# IDATA direct addressing or SFR
+ if {$address < 128 && $address < $iram_size} {
+ return 1
+ }
+ if {[lsearch $avaliable_sfr $address] != -1} {
+ return 1
+ }
+ }
+ {I} { ;# IDATA indirect addressing (or operations with stack)
+ if {$address < $iram_size} {
+ return 1
+ }
+ }
+ {B} { ;# Bit area
+ if {[lsearch $restricted_bits $address] != -1} {
+ return 0
+ }
+ set reg_addr [getRegOfBit $address]
+ if {$reg_addr < 128 && $reg_addr < $iram_size} {
+ return 1
+ }
+ if {[lsearch $avaliable_sfr $reg_addr] != -1} {
+ return 1
+ }
+ }
+ {X} { ;# XDATA
+ if {$address < $xram_size} {
+ return 1
+ }
+ }
+ {C} { ;# CODE
+ if {$address < $code_size} {
+ return 1
+ }
+ }
+ {P} { ;# Data EEPROM
+ if {$address < $eeprom_size} {
+ return 1
+ }
+ }
+ {E} { ;# ERAM
+ if {$address < $eram_size} {
+ return 1
+ }
+ }
+ }
+ return 0
+}
+
+## Write value to SFR
+ # - It does not check address validity !
+ # - Purpose is to write zero to unimplemented bits
+ # @parm Int addr - Target address (128..255)
+ # @parm Int value - New value (0.255)
+ # @return void
+private method write_sfr {addr value} {
+ # Write to SBUF -- Set SBUF-T and begin UART transmission
+ if {$addr == $symbol(SBUFR)} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(SBUFT)
+ }
+ set sfr($symbol(SBUFT)) $value
+
+ uart_start_transmission
+
+ return
+ }
+
+ # Make backup for register value
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $addr
+ }
+
+ # Interrupts configuration related SFR -- skip next interrupt
+ if {$addr == $symbol(IP) || $addr == $symbol(IE) || $addr == $symbol(IPH)} {
+ set skip_interrupt 1
+ } {
+ set skip_interrupt 0
+ }
+
+ # Write specified value into the SFR
+ if {[lsearch $incomplite_regs $addr] == -1} {
+ set sfr($addr) $value
+ } {
+ set sfr($addr) [expr {$value & $incomplite_regs_mask($addr)}]
+ }
+}
+
+## Read value from SFR
+ # This function does not check for valid register address !
+ # - Unimplemented bits are set to random values
+ # @parm Int addr - Source address (128..255)
+ # @return Int - Register value
+private method read_sfr {addr} {
+ # Port latch
+ set port_number [lsearch -ascii -exact $PORT_LATCHES $addr]
+ if {!$rmw_instruction && $port_number != -1} {
+ set result [$this pale_RRPV $port_number]
+
+ # Write only register
+ } elseif {[lsearch $write_only_regs $addr] != -1} {
+ if {!${::Simulator::ignore_read_from_wr_only}} {
+ $this simulator_reading_wr_only $addr $pc [lindex $Line($pc) 0]
+ internal_shutdown
+ }
+ return [undefined_octet]
+
+ # Fully implemeneted register
+ } elseif {[lsearch $incomplite_regs $addr] == -1} {
+ return $sfr($addr)
+
+ # Partialy implemented register
+ } {
+ return [expr {
+ ($incomplite_regs_mask($addr) & $sfr($addr))
+ +
+ (($incomplite_regs_mask($addr) ^ 0x0FF) & [undefined_octet])
+ }]
+ }
+}
diff --git a/lib/simulator/engine/engine_opcodes.tcl b/lib/simulator/engine/engine_opcodes.tcl
new file mode 100755
index 0000000..6d43158
--- /dev/null
+++ b/lib/simulator/engine/engine_opcodes.tcl
@@ -0,0 +1,435 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# OPCODE PROCEDURES
+# --------------------------------------------------------------------------
+
+
+## ACALL
+private method 17 {} {ins_acall 0 [getLastOperand]} ;# 0x11 :: acall 0x0__
+private method 49 {} {ins_acall 1 [getLastOperand]} ;# 0x31 :: acall 0x1__
+private method 81 {} {ins_acall 2 [getLastOperand]} ;# 0x51 :: acall 0x2__
+private method 113 {} {ins_acall 3 [getLastOperand]} ;# 0x71 :: acall 0x3__
+private method 145 {} {ins_acall 4 [getLastOperand]} ;# 0x91 :: acall 0x4__
+private method 177 {} {ins_acall 5 [getLastOperand]} ;# 0xB1 :: acall 0x5__
+private method 209 {} {ins_acall 6 [getLastOperand]} ;# 0xD1 :: acall 0x6__
+private method 241 {} {ins_acall 7 [getLastOperand]} ;# 0xF1 :: acall 0x7__
+
+## ADD
+private method 36 {} {ins_add [getNextOperand]} ;# 0x24 :: add A, #imm8
+private method 37 {} {ins_add_D [getNextOperand]} ;# 0x25 :: add A, addr
+private method 38 {} {ins_add_ID $ram([R 0])} ;# 0x26 :: add A, @R0
+private method 39 {} {ins_add_ID $ram([R 1])} ;# 0x27 :: add A, @R1
+private method 40 {} {ins_add $ram([R 0])} ;# 0x28 :: add A, R0
+private method 41 {} {ins_add $ram([R 1])} ;# 0x29 :: add A, R1
+private method 42 {} {ins_add $ram([R 2])} ;# 0x2A :: add A, R2
+private method 43 {} {ins_add $ram([R 3])} ;# 0x2B :: add A, R3
+private method 44 {} {ins_add $ram([R 4])} ;# 0x2C :: add A, R4
+private method 45 {} {ins_add $ram([R 5])} ;# 0x2D :: add A, R5
+private method 46 {} {ins_add $ram([R 6])} ;# 0x2E :: add A, R6
+private method 47 {} {ins_add $ram([R 7])} ;# 0x2F :: add A, R7
+
+## ADDC
+private method 52 {} {ins_addc [getNextOperand]} ;# 0x34 :: addc A, #imm8
+private method 53 {} {ins_addc_D [getNextOperand]} ;# 0x35 :: addc A, addr
+private method 54 {} {ins_addc_ID $ram([R 0])} ;# 0x36 :: addc A, @R0
+private method 55 {} {ins_addc_ID $ram([R 1])} ;# 0x37 :: addc A, @R1
+private method 56 {} {ins_addc $ram([R 0])} ;# 0x38 :: addc A, R0
+private method 57 {} {ins_addc $ram([R 1])} ;# 0x39 :: addc A, R1
+private method 58 {} {ins_addc $ram([R 2])} ;# 0x3A :: addc A, R2
+private method 59 {} {ins_addc $ram([R 3])} ;# 0x3B :: addc A, R3
+private method 60 {} {ins_addc $ram([R 4])} ;# 0x3C :: addc A, R4
+private method 61 {} {ins_addc $ram([R 5])} ;# 0x3D :: addc A, R5
+private method 62 {} {ins_addc $ram([R 6])} ;# 0x3E :: addc A, R6
+private method 63 {} {ins_addc $ram([R 7])} ;# 0x3F :: addc A, R7
+
+## AJMP
+private method 1 {} {ins_ajmp 0 [getNextOperand]} ;# 0x01 :: ajmp 0x0__
+private method 33 {} {ins_ajmp 1 [getNextOperand]} ;# 0x21 :: ajmp 0x1__
+private method 65 {} {ins_ajmp 2 [getNextOperand]} ;# 0x41 :: ajmp 0x2__
+private method 97 {} {ins_ajmp 3 [getNextOperand]} ;# 0x61 :: ajmp 0x3__
+private method 129 {} {ins_ajmp 4 [getNextOperand]} ;# 0x81 :: ajmp 0x4__
+private method 161 {} {ins_ajmp 5 [getNextOperand]} ;# 0xA1 :: ajmp 0x5__
+private method 193 {} {ins_ajmp 6 [getNextOperand]} ;# 0xC1 :: ajmp 0x6__
+private method 225 {} {ins_ajmp 7 [getNextOperand]} ;# 0xE1 :: ajmp 0x7__
+
+## ANL
+private method 82 {} {ins_anl [getLastOperand] $sfr(224); incr time -1} ;# 0x52 :: anl addr, A
+private method 83 {} {ins_anl [getNextOperand] [getLastOperand]} ;# 0x53 :: anl addr, #imm8
+private method 84 {} {ins_anl_A [getNextOperand]} ;# 0x54 :: anl A, #imm8
+private method 85 {} {ins_anl_A_D [getNextOperand]} ;# 0x55 :: anl A, addr
+private method 86 {} {ins_anl_A_ID $ram([R 0])} ;# 0x56 :: anl A, @R0
+private method 87 {} {ins_anl_A_ID $ram([R 1])} ;# 0x57 :: anl A, @R1
+private method 88 {} {ins_anl_A $ram([R 0])} ;# 0x58 :: anl A, R0
+private method 89 {} {ins_anl_A $ram([R 1])} ;# 0x59 :: anl A, R1
+private method 90 {} {ins_anl_A $ram([R 2])} ;# 0x5A :: anl A, R2
+private method 91 {} {ins_anl_A $ram([R 3])} ;# 0x5B :: anl A, R3
+private method 92 {} {ins_anl_A $ram([R 4])} ;# 0x5C :: anl A, R4
+private method 93 {} {ins_anl_A $ram([R 5])} ;# 0x5D :: anl A, R5
+private method 94 {} {ins_anl_A $ram([R 6])} ;# 0x5E :: anl A, R6
+private method 95 {} {ins_anl_A $ram([R 7])} ;# 0x5F :: anl A, R7
+private method 130 {} {ins_anl_C [getLastOperand]} ;# 0x82 :: anl C, Baddr
+private method 176 {} {ins_anl_C_N [getLastOperand]} ;# 0xB0 :: anl C, /Baddr
+
+
+## CJNE
+private method 180 {} { ;# 0xB4 :: cjne A, #imm8, Roff
+ ins_cjne $sfr(224) [getNextOperand] [getLastOperand]
+}
+private method 181 {} { ;# 0xB5 :: cjne A, addr, Roff
+ ins_cjne_AD [getNextOperand] [getLastOperand]
+}
+private method 182 {} { ;# 0xB6 :: cjne @R0, #imm8, Roff
+ ins_cjne_ID $ram([R 0]) [getNextOperand] [getLastOperand]
+}
+private method 183 {} { ;# 0xB7 :: cjne @R1, #imm8, Roff
+ ins_cjne_ID $ram([R 1]) [getNextOperand] [getLastOperand]
+}
+private method 184 {} { ;# 0xB8 :: cjne R0, #imm8, Roff
+ ins_cjne $ram([R 0]) [getNextOperand] [getLastOperand]
+}
+private method 185 {} { ;# 0xB9 :: cjne R1, #imm8, Roff
+ ins_cjne $ram([R 1]) [getNextOperand] [getLastOperand]
+}
+private method 186 {} { ;# 0xBA :: cjne R2, #imm8, Roff
+ ins_cjne $ram([R 2]) [getNextOperand] [getLastOperand]
+}
+private method 187 {} { ;# 0xBB :: cjne R3, #imm8, Roff
+ ins_cjne $ram([R 3]) [getNextOperand] [getLastOperand]
+}
+private method 188 {} { ;# 0xBC :: cjne R4, #imm8, Roff
+ ins_cjne $ram([R 4]) [getNextOperand] [getLastOperand]
+}
+private method 189 {} { ;# 0xBD :: cjne R5, #imm8, Roff
+ ins_cjne $ram([R 5]) [getNextOperand] [getLastOperand]
+}
+private method 190 {} { ;# 0xBE :: cjne R6, #imm8, Roff
+ ins_cjne $ram([R 6]) [getNextOperand] [getLastOperand]
+}
+private method 191 {} { ;# 0xBF :: cjne R7, #imm8, Roff
+ ins_cjne $ram([R 7]) [getNextOperand] [getLastOperand]
+}
+
+## CLR
+private method 228 {} {ins_clr A} ;# 0xE4 :: clr A
+private method 195 {} {ins_clr C} ;# 0xC3 :: clr C
+private method 194 {} {ins_clr [getNextOperand]} ;# 0xC2 :: clr Baddr
+
+## CPL
+private method 244 {} {ins_cpl A} ;# 0xF4 :: cpl A
+private method 179 {} {ins_cpl C} ;# 0xC3 :: cpl C
+private method 178 {} {ins_cpl [getNextOperand]} ;# 0xC2 :: cpl Baddr
+
+## DA
+private method 212 {} {ins_da} ;# 0xD4 :: da A
+
+## DEC
+private method 20 {} {ins_dec 224} ;# 0x14 :: dec A
+private method 21 {} {ins_dec [getNextOperand]} ;# 0x15 :: dec addr
+private method 22 {} {ins_dec_ID $ram([R 0])} ;# 0x16 :: dec @R0
+private method 23 {} {ins_dec_ID $ram([R 1])} ;# 0x17 :: dec @R1
+private method 24 {} {ins_dec [R 0]} ;# 0x18 :: dec R0
+private method 25 {} {ins_dec [R 1]} ;# 0x19 :: dec R1
+private method 26 {} {ins_dec [R 2]} ;# 0x1A :: dec R2
+private method 27 {} {ins_dec [R 3]} ;# 0x1B :: dec R3
+private method 28 {} {ins_dec [R 4]} ;# 0x1C :: dec R4
+private method 29 {} {ins_dec [R 5]} ;# 0x1D :: dec R5
+private method 30 {} {ins_dec [R 6]} ;# 0x1E :: dec R6
+private method 31 {} {ins_dec [R 7]} ;# 0x1F :: dec R7
+
+## DIV
+private method 132 {} {ins_div} ;# 0x84 :: div AB
+
+## DJNZ
+private method 213 {} {ins_djnz [getNextOperand] [getLastOperand]} ;# 0xD5 :: djnz addr, Roff
+private method 216 {} {ins_djnz [R 0] [getLastOperand]} ;# 0xD8 :: djnz R0, Roff
+private method 217 {} {ins_djnz [R 1] [getLastOperand]} ;# 0xD9 :: djnz R1, Roff
+private method 218 {} {ins_djnz [R 2] [getLastOperand]} ;# 0xDA :: djnz R2, Roff
+private method 219 {} {ins_djnz [R 3] [getLastOperand]} ;# 0xDB :: djnz R3, Roff
+private method 220 {} {ins_djnz [R 4] [getLastOperand]} ;# 0xDC :: djnz R4, Roff
+private method 221 {} {ins_djnz [R 5] [getLastOperand]} ;# 0xDD :: djnz R5, Roff
+private method 222 {} {ins_djnz [R 6] [getLastOperand]} ;# 0xDE :: djnz R6, Roff
+private method 223 {} {ins_djnz [R 7] [getLastOperand]} ;# 0xDF :: djnz R7, Roff
+
+## INC
+private method 4 {} {ins_inc 224} ;# 0x04 :: inc A
+private method 5 {} {ins_inc [getNextOperand]} ;# 0x05 :: inc addr
+private method 6 {} {ins_inc_ID $ram([R 0])} ;# 0x06 :: inc @R0
+private method 7 {} {ins_inc_ID $ram([R 1])} ;# 0x07 :: inc @R1
+private method 8 {} {ins_inc [R 0]} ;# 0x08 :: inc R0
+private method 9 {} {ins_inc [R 1]} ;# 0x09 :: inc R1
+private method 10 {} {ins_inc [R 2]} ;# 0x0A :: inc R2
+private method 11 {} {ins_inc [R 3]} ;# 0x0B :: inc R3
+private method 12 {} {ins_inc [R 4]} ;# 0x0C :: inc R4
+private method 13 {} {ins_inc [R 5]} ;# 0x0D :: inc R5
+private method 14 {} {ins_inc [R 6]} ;# 0x0E :: inc R6
+private method 15 {} {ins_inc [R 7]} ;# 0x0F :: inc R7
+private method 163 {} {ins_inc_DPTR} ;# 0xA3 :: inc DPTR
+
+## JB
+private method 32 {} {ins_jb [getNextOperand] [getLastOperand]} ;# 0x20 :: jb Baddr, Roff
+
+## JNB
+private method 48 {} {ins_jnb [getNextOperand] [getLastOperand]} ;# 0x30 :: jnb Baddr, Roff
+
+## JBC
+private method 16 {} {ins_jbc [getNextOperand] [getLastOperand]} ;# 0x10 :: jbc Baddr, Roff
+
+## JC
+private method 64 {} {ins_jc [getLastOperand]} ;# 0x40 :: jc Roff
+
+## JNC
+private method 80 {} {ins_jnc [getLastOperand]} ;# 0x50 :: jnc Roff
+
+## JZ
+private method 96 {} {ins_jz [getLastOperand]} ;# 0x60 :: jz Roff
+
+## JNZ
+private method 112 {} {ins_jnz [getLastOperand]} ;# 0x70 :: jnz Roof
+
+## JMP
+private method 115 {} {ins_jmp} ;# 0x79 :: jmp @A+DPTR
+
+## LCALL
+private method 18 {} {ins_lcall [getNextOperand] [getLastOperand]} ;# 0x12 :: lcall Paddr16
+
+## LJMP
+private method 2 {} {ins_ljmp [getNextOperand] [getNextOperand]} ;# 0x02 :: ljmp Paddr16
+
+## MOV
+private method 116 {} {ins_mov 224 [getNextOperand]} ;# 0x74 :: mov A, #imm8
+private method 229 {} {ins_mov_D [getNextOperand] 224} ;# 0xE5 :: mov A, addr
+private method 230 {} {ins_mov_ID1 224 $ram([R 0])} ;# 0xE6 :: mov A, @R0
+private method 231 {} {ins_mov_ID1 224 $ram([R 1])} ;# 0xE7 :: mov A, @R1
+private method 232 {} {ins_mov 224 $ram([R 0])} ;# 0xE8 :: mov A, R0
+private method 233 {} {ins_mov 224 $ram([R 1])} ;# 0xE9 :: mov A, R1
+private method 234 {} {ins_mov 224 $ram([R 2])} ;# 0xEA :: mov A, R2
+private method 235 {} {ins_mov 224 $ram([R 3])} ;# 0xEB :: mov A, R3
+private method 236 {} {ins_mov 224 $ram([R 4])} ;# 0xEC :: mov A, R4
+private method 237 {} {ins_mov 224 $ram([R 5])} ;# 0xED :: mov A, R5
+private method 238 {} {ins_mov 224 $ram([R 6])} ;# 0xEE :: mov A, R6
+private method 239 {} {ins_mov 224 $ram([R 7])} ;# 0xEF :: mov A, R7
+private method 245 {} {ins_mov [getNextOperand] $sfr(224)} ;# 0xF5 :: mov addr, A
+private method 117 {} { ;# 0x75 :: mov addr, #imm8
+ ins_mov [getNextOperand] [getNextOperand]
+ incr time
+}
+private method 133 {} { ;# 0x85 :: mov addr, addr
+ ins_mov_D [getNextOperand] [getNextOperand]
+ incr time
+}
+private method 134 {} { ;# 0x86 :: mov addr, @R0
+ ins_mov_ID1 [getNextOperand] $ram([R 0])
+ incr time
+}
+private method 135 {} { ;# 0x87 :: mov addr, @R1
+ ins_mov_ID1 [getNextOperand] $ram([R 1])
+ incr time
+}
+private method 136 {} { ;# 0x88 :: mov addr, R0
+ ins_mov [getNextOperand] $ram([R 0])
+ incr time
+}
+private method 137 {} { ;# 0x89 :: mov addr, R1
+ ins_mov [getNextOperand] $ram([R 1])
+ incr time
+}
+private method 138 {} { ;# 0x8A :: mov addr, R2
+ ins_mov [getNextOperand] $ram([R 2])
+ incr time
+}
+private method 139 {} { ;# 0x8B :: mov addr, R3
+ ins_mov [getNextOperand] $ram([R 3])
+ incr time
+}
+private method 140 {} { ;# 0x8C :: mov addr, R4
+ ins_mov [getNextOperand] $ram([R 4])
+ incr time
+}
+private method 141 {} { ;# 0x8D :: mov addr, R5
+ ins_mov [getNextOperand] $ram([R 5])
+ incr time
+}
+private method 142 {} { ;# 0x8E :: mov addr, R6
+ ins_mov [getNextOperand] $ram([R 6])
+ incr time
+}
+private method 143 {} { ;# 0x8F :: mov addr, R7
+ ins_mov [getNextOperand] $ram([R 7])
+ incr time
+}
+private method 246 {} {ins_mov_ID0 $ram([R 0]) $sfr(224)} ;# 0xF6 :: mov @R0, A
+private method 247 {} {ins_mov_ID0 $ram([R 1]) $sfr(224)} ;# 0xF7 :: mov @R1, A
+private method 118 {} {ins_mov_ID0 $ram([R 0]) [getNextOperand]} ;# 0x76 :: mov @R0, #imm8
+private method 119 {} {ins_mov_ID0 $ram([R 1]) [getNextOperand]} ;# 0x77 :: mov @R1, #imm8
+private method 166 {} {ins_mov_ID2 $ram([R 0]) [getNextOperand]} ;# 0xA6 :: mov @R0, addr
+private method 167 {} {ins_mov_ID2 $ram([R 1]) [getNextOperand]} ;# 0xA7 :: mov @R1, addr
+private method 248 {} {ins_mov [R 0] $sfr(224)} ;# 0xF8 :: mov R0, A
+private method 249 {} {ins_mov [R 1] $sfr(224)} ;# 0xF9 :: mov R1, A
+private method 250 {} {ins_mov [R 2] $sfr(224)} ;# 0xFA :: mov R2, A
+private method 251 {} {ins_mov [R 3] $sfr(224)} ;# 0xFB :: mov R3, A
+private method 252 {} {ins_mov [R 4] $sfr(224)} ;# 0xFC :: mov R4, A
+private method 253 {} {ins_mov [R 5] $sfr(224)} ;# 0xFD :: mov R5, A
+private method 254 {} {ins_mov [R 6] $sfr(224)} ;# 0xFE :: mov R6, A
+private method 255 {} {ins_mov [R 7] $sfr(224)} ;# 0xFF :: mov R7, A
+private method 120 {} {ins_mov [R 0] [getNextOperand]} ;# 0x78 :: mov R0, #imm8
+private method 121 {} {ins_mov [R 1] [getNextOperand]} ;# 0x79 :: mov R1, #imm8
+private method 122 {} {ins_mov [R 2] [getNextOperand]} ;# 0x7A :: mov R2, #imm8
+private method 123 {} {ins_mov [R 3] [getNextOperand]} ;# 0x7B :: mov R3, #imm8
+private method 124 {} {ins_mov [R 4] [getNextOperand]} ;# 0x7C :: mov R4, #imm8
+private method 125 {} {ins_mov [R 5] [getNextOperand]} ;# 0x7D :: mov R5, #imm8
+private method 126 {} {ins_mov [R 6] [getNextOperand]} ;# 0x7E :: mov R6, #imm8
+private method 127 {} {ins_mov [R 7] [getNextOperand]} ;# 0x7F :: mov R7, #imm8
+private method 168 {} {ins_mov_Rx_ADDR 0 [getLastOperand]} ;# 0xA8 :: mov R0, addr
+private method 169 {} {ins_mov_Rx_ADDR 1 [getLastOperand]} ;# 0xA9 :: mov R1, addr
+private method 170 {} {ins_mov_Rx_ADDR 2 [getLastOperand]} ;# 0xAA :: mov R2, addr
+private method 171 {} {ins_mov_Rx_ADDR 3 [getLastOperand]} ;# 0xAB :: mov R3, addr
+private method 172 {} {ins_mov_Rx_ADDR 4 [getLastOperand]} ;# 0xAC :: mov R4, addr
+private method 173 {} {ins_mov_Rx_ADDR 5 [getLastOperand]} ;# 0xAD :: mov R5, addr
+private method 174 {} {ins_mov_Rx_ADDR 6 [getLastOperand]} ;# 0xAE :: mov R6, addr
+private method 175 {} {ins_mov_Rx_ADDR 7 [getLastOperand]} ;# 0xAF :: mov R7, addr
+private method 144 {} {ins_mov_DPTR [getNextOperand] [getLastOperand]} ;# 0x90 :: mov DPTR, #imm16
+private method 146 {} {ins_mov_bit [getLastOperand] {C}} ;# 0x92 :: mov Baddr, C
+private method 162 {} {ins_mov_bit {C} [getLastOperand]} ;# 0xA2 :: mov C, Baddr
+
+## MOVC
+private method 147 {} {ins_movc {DPTR}} ;# 0x93 :: movc A, @A+DPTR
+private method 131 {} {ins_movc {PC}} ;# 0x93 :: movc A, @A+PC
+
+## MOVX
+private method 226 {} {ins_movx {A} {R0} } ;# 0xE2 :: movx A, @R0
+private method 227 {} {ins_movx {A} {R1} } ;# 0xE3 :: movx A, @R1
+private method 224 {} {ins_movx {A} {DPTR} } ;# 0xE0 :: movx A, @DPTR
+private method 242 {} {ins_movx {R0} {A} } ;# 0xF2 :: movx @R0, A
+private method 243 {} {ins_movx {R1} {A} } ;# 0xF3 :: movx @R1, A
+private method 240 {} {ins_movx {DPTR} {A} } ;# 0xF0 :: movx @DPTR, A
+
+# MUL
+private method 164 {} {ins_mul} ;# 0xA4 :: mul AB
+
+## NOP
+private method 0 {} {ins_nop} ;# 0x00 :: nop
+
+## ORL
+private method 66 {} {ins_orl [getNextOperand] $sfr(224)} ;# 0x42 :: orl addr, A
+private method 67 {} {ins_orl [getNextOperand] [getNextOperand]; incr time} ;# 0x43 :: orl addr, #imm8
+private method 68 {} {ins_orl 224 [getNextOperand]} ;# 0x44 :: orl A, #imm8
+private method 69 {} {ins_orl_D 224 [getNextOperand]} ;# 0x45 :: orl A, addr
+private method 70 {} {ins_orl_ID 224 $ram([R 0])} ;# 0x46 :: orl A, @R0
+private method 71 {} {ins_orl_ID 224 $ram([R 1])} ;# 0x47 :: orl A, @R1
+private method 72 {} {ins_orl 224 $ram([R 0])} ;# 0x48 :: orl A, R0
+private method 73 {} {ins_orl 224 $ram([R 1])} ;# 0x49 :: orl A, R1
+private method 74 {} {ins_orl 224 $ram([R 2])} ;# 0x4A :: orl A, R2
+private method 75 {} {ins_orl 224 $ram([R 3])} ;# 0x4B :: orl A, R3
+private method 76 {} {ins_orl 224 $ram([R 4])} ;# 0x4C :: orl A, R4
+private method 77 {} {ins_orl 224 $ram([R 5])} ;# 0x4D :: orl A, R5
+private method 78 {} {ins_orl 224 $ram([R 6])} ;# 0x4E :: orl A, R6
+private method 79 {} {ins_orl 224 $ram([R 7])} ;# 0x4F :: orl A, R7
+private method 114 {} {ins_orl_bit [getLastOperand]} ;# 0x72 :: orl C, Baddr
+private method 160 {} {ins_orl_not_bit [getLastOperand]} ;# 0xA0 :: orl C, /Baddr
+
+## POP
+private method 208 {} {ins_pop [getLastOperand]} ;# 0xD0 :: pop addr
+
+## PUSH
+private method 192 {} {ins_push [getLastOperand]} ;# 0xC0 :: push addr
+
+## RET
+private method 34 {} {ins_ret} ;# 0x22 :: ret
+
+## RETI
+private method 50 {} {ins_reti} ;# 0x32 :: reti
+
+## RL
+private method 35 {} {ins_rl} ;# 0x23 :: rl A
+
+## RR
+private method 3 {} {ins_rr} ;# 0x03 :: rr A
+
+## RLC
+private method 51 {} {ins_rlc} ;# 0x33 :: rlc A
+
+## RRC
+private method 19 {} {ins_rrc} ;# 0x13 :: rrc A
+
+## SETB
+private method 211 {} {ins_setb {C}} ;# 0xD3 :: setb C
+private method 210 {} {ins_setb [getNextOperand]} ;# 0xD2 :: setb Baddr
+
+## SJMP
+private method 128 {} {ins_sjmp [getLastOperand]} ;# 0x80 :: sjmp Roff
+
+## SUBB
+private method 148 {} {ins_subb [getNextOperand]} ;# 0x94 :: subb A, #imm8
+private method 149 {} {ins_subb_D [getNextOperand]} ;# 0x95 :: subb A, addr
+private method 150 {} {ins_subb_ID $ram([R 0])} ;# 0x96 :: subb A, @R0
+private method 151 {} {ins_subb_ID $ram([R 1])} ;# 0x97 :: subb A, @R1
+private method 152 {} {ins_subb $ram([R 0])} ;# 0x98 :: subb A, R0
+private method 153 {} {ins_subb $ram([R 1])} ;# 0x99 :: subb A, R1
+private method 154 {} {ins_subb $ram([R 2])} ;# 0x9A :: subb A, R2
+private method 155 {} {ins_subb $ram([R 3])} ;# 0x9B :: subb A, R3
+private method 156 {} {ins_subb $ram([R 4])} ;# 0x9C :: subb A, R4
+private method 157 {} {ins_subb $ram([R 5])} ;# 0x9D :: subb A, R5
+private method 158 {} {ins_subb $ram([R 6])} ;# 0x9E :: subb A, R6
+private method 159 {} {ins_subb $ram([R 7])} ;# 0x9F :: subb A, R7
+
+## SWAP
+private method 196 {} {ins_swap} ;# 0xC4 :: swap A
+
+## XCH
+private method 197 {} {ins_xch [getNextOperand]} ;# 0xC5 :: xch A, addr
+private method 198 {} {ins_xch_ID $ram([R 0])} ;# 0xC6 :: xch A, @R0
+private method 199 {} {ins_xch_ID $ram([R 1])} ;# 0xC7 :: xch A, @R1
+private method 200 {} {ins_xch [R 0]} ;# 0xC8 :: xch A, R0
+private method 201 {} {ins_xch [R 1]} ;# 0xC9 :: xch A, R1
+private method 202 {} {ins_xch [R 2]} ;# 0xCA :: xch A, R2
+private method 203 {} {ins_xch [R 3]} ;# 0xCB :: xch A, R3
+private method 204 {} {ins_xch [R 4]} ;# 0xCC :: xch A, R4
+private method 205 {} {ins_xch [R 5]} ;# 0xCD :: xch A, R5
+private method 206 {} {ins_xch [R 6]} ;# 0xCE :: xch A, R6
+private method 207 {} {ins_xch [R 7]} ;# 0xCF :: xch A, R7
+
+## XCHD
+private method 214 {} {ins_xchd $ram([R 0])} ;# 0xD6 :: xchd A, @R0
+private method 215 {} {ins_xchd $ram([R 1])} ;# 0xD6 :: xchd A, @R1
+
+## XRL
+private method 98 {} {ins_xrl [getNextOperand] $sfr(224)} ;# 0x62 :: xrl addr, A
+private method 99 {} {ins_xrl [getNextOperand] [getNextOperand];incr time};# 0x63 :: xrl addr, #imm8
+private method 100 {} {ins_xrl 224 [getNextOperand]} ;# 0x64 :: xrl A, #imm8
+private method 101 {} {ins_xrl_D 224 [getNextOperand]} ;# 0x64 :: xrl A, addr
+private method 102 {} {ins_xrl_ID 224 $ram([R 0])} ;# 0x66 :: xrl A, @R1
+private method 103 {} {ins_xrl_ID 224 $ram([R 1])} ;# 0x67 :: xrl A, @R1
+private method 104 {} {ins_xrl 224 $ram([R 0])} ;# 0x68 :: xrl A, R0
+private method 105 {} {ins_xrl 224 $ram([R 1])} ;# 0x69 :: xrl A, R1
+private method 106 {} {ins_xrl 224 $ram([R 2])} ;# 0x6A :: xrl A, R2
+private method 107 {} {ins_xrl 224 $ram([R 3])} ;# 0x6B :: xrl A, R3
+private method 108 {} {ins_xrl 224 $ram([R 4])} ;# 0x6C :: xrl A, R4
+private method 109 {} {ins_xrl 224 $ram([R 5])} ;# 0x6D :: xrl A, R5
+private method 110 {} {ins_xrl 224 $ram([R 6])} ;# 0x6E :: xrl A, R6
+private method 111 {} {ins_xrl 224 $ram([R 7])} ;# 0x6F :: xrl A, R7
diff --git a/lib/simulator/engine/engine_virtual_hw_controller.tcl b/lib/simulator/engine/engine_virtual_hw_controller.tcl
new file mode 100755
index 0000000..a597e27
--- /dev/null
+++ b/lib/simulator/engine/engine_virtual_hw_controller.tcl
@@ -0,0 +1,1413 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Part of simulator engine functionality.
+#
+# --------------------------------------------------------------------------
+# VIRTUAL HW CONTROLLER PROCEDURES
+# --------------------------------------------------------------------------
+
+
+## Perform one instruction cycle
+ # @return void
+private method instruction_cycle {} {
+ set rmw_instruction 0
+ set stepback_ena 1
+
+ stepback_save_spec
+
+ # Execute instruction
+ if {$DEBUG} {
+ $code($pc)
+ } {
+ if {[catch {
+ $code($pc)
+ } result]} then {
+ if {!${::Simulator::ignore_invalid_ins}} {
+ $this simulator_invalid_instruction $pc $Line($pc)
+ internal_shutdown
+ incr_pc 1
+ }
+ puts stderr $result
+ }
+ }
+
+ # Adjust simulator action history
+ stepback_save_spec_time
+
+ # Increment program time
+ set wtd_rst_flag [increment_program_time $time]
+
+ # Interrupts control
+ if {$controllers_conf(EA)} {
+ # Determinate minimum interrupt priority
+ set min_priority -1
+ foreach int $interrupts_in_progress {
+ set p [interrupt_priority $int]
+ if {$p > $min_priority} {
+ set min_priority $p
+ }
+ }
+
+ # Iterate over list of interrupt priorities
+ foreach IntName $controllers_conf(IP) {
+
+ # Skip requests with insufficient priority
+ if {[interrupt_priority $IntName] <= $min_priority} {
+ continue
+ }
+
+ # Test iterrupt flag
+ set vector__flag [isInterruptActive $IntName]
+ # Handle the interrupt
+ if {$vector__flag != 0} {
+ interrupt_handler $IntName [lindex $vector__flag 0] [lindex $vector__flag 1] 0
+ break
+ }
+ }
+ }
+
+ # Send port states to PALE (Peripheral Abstraction Layer Engine)
+ set max $time
+ if {!$controllers_conf(X2)} {
+ set max [expr {$max * 2}]
+ }
+ for {set i 1} {$i < $max} {incr i} {
+ $this pale_simulation_cycle $ports_previous_state
+ }
+ set rmw_instruction 1
+ set ports_previous_state [list]
+ for {set i 0; set addr 128} {$i < 5} {incr i; incr addr 16} {
+ if {$feature_avaliable(p$i)} {
+ lappend ports_previous_state $sfr($addr)
+ } {
+ lappend ports_previous_state 0
+ }
+ }
+ $this pale_simulation_cycle $ports_previous_state
+
+ # Analog comparator controller
+ if {[$this pale_is_enabled]} {
+ if {$controllers_conf(CEN)} {
+ anlcmp_controller
+ } {
+ set anlcmp_running 0
+ $this pale_SLSF $PIN(ANL0) 0
+ $this pale_SLSF $PIN(ANL1) 0
+ }
+ }
+
+ # UART controller
+ if {$feature_avaliable(uart)} {
+ if {($uart_RX_in_progress || $uart_TX_in_progress) && ${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(SBUFR)
+ stepback_reg_change S $symbol(SBUFT)
+ stepback_reg_change S $symbol(SCON)
+ }
+ uart_controller $time
+ }
+
+ # Handle exteranal interrupts
+ foreach int_src {0 1} {
+ set intx 1 ;# State of pin INTx
+ set ext_int 0 ;# Local external interrupt flag
+
+ # Analyze port state
+ for {set i -$time} {$i < 0} {incr i} {
+ # Determinate value of input pin INTx
+ set intx [$this pale_RRPPV $PIN(INT${int_src}) $i]
+
+ # Detect falling edge on INTx
+ if {$controllers_conf(IT${int_src})} {
+ set intx_prev $controllers_conf(INT${int_src})
+ set controllers_conf(INT${int_src}) $intx
+
+ if {$intx_prev && !$intx} {
+ set ext_int 1
+ }
+
+ # Just copy inverted value from INTx to IEx
+ } {
+ set ext_int [expr {!$intx}]
+ }
+ }
+
+ # Invoke external interrupt
+ if {
+ ( $controllers_conf(IT${int_src}) && $ext_int )
+ ||
+ ( !$controllers_conf(IT${int_src}) && ($controllers_conf(IE${int_src}) != $ext_int) )
+ } then {
+ setBit $symbol(IE${int_src}) $ext_int
+ }
+ }
+
+ ## Timers control
+ # Timers 0 and 1 are engaged by PWM
+ if {$controllers_conf(PWMEN)} {
+ if {!$pwm_running} {
+ set pwm_running 1
+ $this pale_SLSF $PIN(T1) 3
+ } {
+ # Make backup for affected SFR
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(TL0)
+ stepback_reg_change S $symbol(TH0)
+ stepback_reg_change S $symbol(TL1)
+ }
+
+ # Timer 0 is forced into mode 2 (8-bit autoreload)
+ # TL1 is incremented after each T0 overflow
+ incr sfr($symbol(TL0)) $time
+ while 1 {
+ if {$sfr($symbol(TL0)) > 255} {
+ set sfr($symbol(TL0)) [expr {$sfr($symbol(TL0)) - 256 + $sfr($symbol(TH0))}]
+ # Increment TL1
+ incr sfr($symbol(TL1))
+
+ # TL1 overflow -> High PWM pulse
+ if {$sfr($symbol(TL1)) > 255} {
+ set sfr($symbol(TL1)) 0 ;# Clear TL1
+ set pwm_OCR $sfr($symbol(TH1)) ;# Load OCR
+ pale_WPBBL $PIN(T2) 1 -$sfr($symbol(TL0))
+ }
+
+ # OCR and TL1 are equal -> Low PWM pulse
+ if {$pwm_OCR == $sfr($symbol(TL1))} {
+ set time_back [expr {256 - $sfr($symbol(TL0))}]
+ if {$time_back >= 0} {
+ $this pale_WPBBL $PIN(T1) 0
+ } {
+ $this pale_WPBBL $PIN(T1) $time_back
+ }
+ }
+ } {
+ break
+ }
+ }
+
+ # Synchronize affected SFR
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(TL0)
+ $this Simulator_GUI_sync S $symbol(TH0)
+ $this Simulator_GUI_sync S $symbol(TL1)
+ }
+ }
+
+ # Timers 0 and 1 are free
+ } else {
+ # Shutdown PWM controller
+ if {$pwm_running} {
+ set pwm_running 0
+ $this pale_SLSF $PIN(T1) 0
+ }
+
+ # Make backup for TCON register
+ if {($controllers_conf(TR0) || $controllers_conf(TR1)) && ${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(TCON)
+ }
+
+ # Increment timer 0
+ if {$controllers_conf(TR0)} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(TL0)
+ stepback_reg_change S $symbol(TH0)
+ }
+ timer_controller_01 0
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(TL0)
+ $this Simulator_GUI_sync S $symbol(TH0)
+ }
+ # Shutdown timer 0
+ } {
+ set timer_0_running 0
+ }
+
+ # Increment timer 1
+ if {$controllers_conf(TR1)} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(TL1)
+ stepback_reg_change S $symbol(TH1)
+ if {$controllers_conf(T0_MOD) == 3} {
+ stepback_reg_change S $symbol(TH0)
+ }
+ }
+ timer_controller_01 1
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(TL1)
+ $this Simulator_GUI_sync S $symbol(TH1)
+ if {$controllers_conf(T0_MOD) == 3} {
+ $this Simulator_GUI_sync S $symbol(TH0)
+ }
+ }
+ # Shutdown timer 1
+ } {
+ set timer_1_running 0
+ }
+
+ # Keep timer 1 running while timer 0 is in mode 3
+ if {$controllers_conf(T0_MOD) == 3} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(TL1)
+ stepback_reg_change S $symbol(TH1)
+ }
+ special_timer1_controller_T0_MOD_3
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(TL1)
+ $this Simulator_GUI_sync S $symbol(TH1)
+ }
+ }
+ }
+
+ # Increment timer 2
+ if {$feature_avaliable(t2)} {
+ if {$controllers_conf(TR2)} {
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(TL2)
+ stepback_reg_change S $symbol(TH2)
+ stepback_reg_change S $symbol(RCAP2L)
+ stepback_reg_change S $symbol(RCAP2H)
+ stepback_reg_change S $symbol(T2CON)
+ }
+ timer_controller_2
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(TL2)
+ $this Simulator_GUI_sync S $symbol(TH2)
+ $this Simulator_GUI_sync S $symbol(RCAP2L)
+ $this Simulator_GUI_sync S $symbol(RCAP2H)
+ }
+ # Shutdown timer 2
+ } {
+ set timer_2_running 0
+ }
+ }
+
+ # Manage interrupt monitor
+ $this interrupt_monitor_intr_flags [simulator_get_active_intr_flags]
+
+ # Adjust stopwatch timer
+ incr run_statistics(3)
+ $this stopwatch_refresh
+
+ # Manage stack for stepback stack
+ stepback_save_norm
+ set stepback_ena 0
+
+ # Manage PALE
+ $this pale_finish_simulation_cycle
+}
+
+## Analog comparator controller
+ # It's safe to call this function even if there is no analog comparator implemented on the MCU
+ # @return void
+private method anlcmp_controller {} {
+ set sample 0
+
+ # Start analog comparator
+ if {!$anlcmp_running} {
+ $this pale_SLSF $PIN(ANL0) 4
+ $this pale_SLSF $PIN(ANL1) 4
+
+ set anlcmp_running 1
+ return
+ }
+
+ ## Sample inputs
+ # Debounce mode
+ if {[lsearch {2 3 6} $controllers_conf(AC_MOD)] != -1} {
+ incr anlcpm_db_timer $timer1_overflow
+ if {$anlcpm_db_timer >= 2} {
+ incr anlcpm_db_timer -$anlcpm_db_timer
+ set sample 1
+ }
+ # Normal mode (sample every S4)
+ } {
+ set sample 1
+ }
+ # Sample port pins ANL0 and ANL1
+ if {!$sample} {
+ return
+ }
+ set anlcmp_output_prev $anlcmp_output
+ set anlcmp_output [expr {([$this pale_RRPPV $PIN(ANL0)] - [$this pale_RRPPV $PIN(ANL1)]) > 0 ? 1 : 0}]
+
+ # Conditionaly ionvoke analog comparator interrupt
+ switch -- $controllers_conf(AC_MOD) {
+ 0 { ;# Negative (Low) level
+ if {!$anlcmp_output} {
+ write_sfr $symbol(ACSR) [expr {$sfr($symbol(ACSR)) | 0x10}]
+ }
+ }
+ 1 { ;# Positive edge
+ if {!$anlcmp_output_prev && $anlcmp_output} {
+ write_sfr $symbol(ACSR) [expr {$sfr($symbol(ACSR)) | 0x10}]
+ }
+ }
+ 2 { ;# Toggle with debounce
+ if {$anlcmp_output_prev != $anlcmp_output} {
+ write_sfr $symbol(ACSR) [expr {$sfr($symbol(ACSR)) | 0x10}]
+ }
+ }
+ 3 { ;# Positive edge with debounce
+ if {!$anlcmp_output_prev && $anlcmp_output} {
+ write_sfr $symbol(ACSR) [expr {$sfr($symbol(ACSR)) | 0x10}]
+ }
+ }
+ 4 { ;# Negative edge
+ if {$anlcmp_output_prev && !$anlcmp_output} {
+ write_sfr $symbol(ACSR) [expr {$sfr($symbol(ACSR)) | 0x10}]
+ }
+ }
+ 5 { ;# Toggle
+ if {$anlcmp_output_prev != $anlcmp_output} {
+ write_sfr $symbol(ACSR) [expr {$sfr($symbol(ACSR)) | 0x10}]
+ }
+ }
+ 6 { ;# Negative edge with debounce
+ if {$anlcmp_output_prev && !$anlcmp_output} {
+ write_sfr $symbol(ACSR) [expr {$sfr($symbol(ACSR)) | 0x10}]
+ }
+ }
+ 7 { ;# Positive (High) level
+ if {$anlcmp_output} {
+ write_sfr $symbol(ACSR) [expr {$sfr($symbol(ACSR)) | 0x10}]
+ }
+ }
+ }
+}
+
+## Timer controller for timer 2
+ # @retrun void
+private method timer_controller_2 {} {
+ set timer2_overflow 0
+ set increment 0
+
+ ## Determinate counter increment
+ # Counter 16-bit
+ if {$controllers_conf(CT2)} {
+ # Detect 1-to-0 transition on external input
+ for {set i -$time} {$i < 0} {incr i} {
+ set counter_input_prev $controllers_conf(T2)
+ set controllers_conf(T2) [$this pale_RRPPV $PIN(T2) $i]
+
+ if {$counter_input_prev && !$controllers_conf(T2)} {
+ incr increment
+ }
+ }
+
+ # Timer 16-bit
+ } {
+ set increment $time
+ }
+
+ # Programmable Clock-output
+ if {$controllers_conf(T2OE)} {
+ for {set i [expr {-$time + 1}]} {$i <= 0} {incr i} {
+ $this pale_WPBBL $PIN(T2) $controllers_conf(T2) $i
+ }
+
+ # 16-bit timer
+ if {$timer_2_running && !$controllers_conf(CT2)} {
+ set increment [expr {$time * 6}]
+ } {
+ set increment 0
+ }
+ if {[increment_timer2 $increment 1]} {
+ while 1 {
+ set sfr($symbol(TH2)) $sfr($symbol(RCAP2H))
+ if {![increment_timer2 $sfr($symbol(RCAP2L)) 1]} {
+ break
+ }
+ incr timer2_overflow
+ }
+
+ # Detect transition on external input
+ puts "set controllers_conf(T2) [expr {!$controllers_conf(T2)}]"
+ set controllers_conf(T2) [expr {!$controllers_conf(T2)}]
+ }
+
+ # External interrupt
+ for {set i -$time} {$i < 0} {incr i} {
+ # Detect 1-to-0 transition on external input
+ set t2ex_prev $controllers_conf(T2EX)
+ set controllers_conf(T2EX) [$this pale_RRPPV $PIN(T2EX) $i]
+
+ # Invoke external interrupt
+ if {$t2ex_prev && !$controllers_conf(T2EX) && $controllers_conf(EXEN2)} {
+ setBit $symbol(EXF2) 1
+ }
+ }
+
+ # Baud Rate Generator
+ } elseif {$controllers_conf(RCLK) || $controllers_conf(TCLK)} {
+ if {$controllers_conf(CT2)} {
+ set increment [expr {$increment * 6}]
+ }
+ if {[increment_timer2 $increment 1]} {
+ while 1 {
+ set sfr($symbol(TH2)) $sfr($symbol(RCAP2H))
+ if {![increment_timer2 $sfr($symbol(RCAP2L)) 1]} {
+ break
+ }
+ incr timer2_overflow
+ }
+ }
+
+ # External interrupt
+ for {set i -$time} {$i < 0} {incr i} {
+ # Detect 1-to-0 transition on external input
+ set t2ex_prev $controllers_conf(T2EX)
+ set controllers_conf(T2EX) [$this pale_RRPPV $PIN(T2EX) $i]
+
+ # Invoke external interrupt
+ if {$t2ex_prev && !$controllers_conf(T2EX) && $controllers_conf(EXEN2)} {
+ setBit $symbol(EXF2) 1
+ }
+ }
+
+ # 16-bit Capture
+ } elseif {$controllers_conf(CPRL2) && $timer_2_running} {
+ set capture_flag 0
+
+ # Increment timer registers
+ if {[increment_timer2 $increment 1]} {
+ setBit $symbol(TF2) 1
+ }
+
+ # Detect 1-to-0 transition on external input
+ for {set i -$time} {$i < 0} {incr i} {
+ set t2ex_prev $controllers_conf(T2EX)
+ set controllers_conf(T2EX) [$this pale_RRPPV $PIN(T2EX) $i]
+
+ # Capture TL2 and TH2 to RCAP2L and RCAP2H
+ if {$t2ex_prev && !$controllers_conf(T2EX) && $controllers_conf(EXEN2)} {
+ setBit $symbol(EXF2) 1
+
+ set sfr($symbol(RCAP2L)) $sfr($symbol(TL2))
+ set sfr($symbol(RCAP2H)) $sfr($symbol(TH2))
+
+ }
+ }
+
+ # 16-bit Auto-reload (DCEN == 1)
+ } elseif {$controllers_conf(DCEN) && $timer_2_running} {
+ set updown [$this pale_RRPPV $PIN(T2EX)]
+ set result [increment_timer2 $increment $updown]
+
+ # Overflow
+ if {$result == 1} {
+ while 1 {
+ set sfr($symbol(TH2)) $sfr($symbol(RCAP2H))
+ if {![increment_timer2 $sfr($symbol(RCAP2L)) $updown]} {
+ break
+ }
+ }
+
+ setBit $symbol(TF2) 1
+ setBit $symbol(EXF2) [expr {![getBit $symbol(EXF2)]}]
+ }
+
+ # Underflow
+ if {!$updown || $result == -1} {
+ while 1 {
+ set cur_val [expr {$sfr($symbol(TL2)) + ($sfr($symbol(TH2)) << 8)}]
+ set min_val [expr {$sfr($symbol(RCAP2L)) + ($sfr($symbol(RCAP2H)) << 8)}]
+
+ set diff [expr {$min_val - $cur_val}]
+
+ if {$diff > 0} {
+ incr diff -1
+ set sfr($symbol(TL2)) 255
+ set sfr($symbol(TH2)) 255
+
+ increment_timer2 $diff 0
+ set result -1
+
+ } else {
+ break
+ }
+ }
+ }
+
+ if {$result == -1} {
+ setBit $symbol(TF2) 1
+ setBit $symbol(EXF2) [expr {![getBit $symbol(EXF2)]}]
+ }
+
+ # 16-bit Auto-reload (DCEN == 0)
+ } elseif {$timer_2_running} {
+ if {[increment_timer2 $increment 1]} {
+ while 1 {
+ set sfr($symbol(TH2)) $sfr($symbol(RCAP2H))
+ if {![increment_timer2 $sfr($symbol(RCAP2L)) 1]} {
+ break
+ }
+ }
+ setBit $symbol(TF2) 1
+ setBit $symbol(EXF2) [expr {![getBit $symbol(EXF2)]}]
+ }
+ }
+
+ # Start the timer if it is not already started
+ if {!$timer_2_running} {
+ set timer_2_running 1
+ return
+ }
+}
+
+## Increment timer 2
+ # @parm Int increment_by - value to increment by
+ # @parm Bool updown - 1 == count up; 0 == count down
+ # @retrun Int - 1 == Owerflow; -1 == Underflow; 0 == normal
+private method increment_timer2 {increment_by updown} {
+ if {$updown} {
+ incr sfr($symbol(TL2)) $increment_by
+ } {
+ incr sfr($symbol(TL2)) -$increment_by
+ }
+
+ # Low-order byte overflow
+ if {$sfr($symbol(TL2)) > 255} {
+ incr sfr($symbol(TH2))
+ incr sfr($symbol(TL2)) -256
+ if {$sfr($symbol(TH2)) > 255} {
+ set sfr($symbol(TH2)) 0
+ return 1
+ }
+ # Low-order byte underflow
+ } elseif {$sfr($symbol(TL2)) < 0} {
+ incr sfr($symbol(TH2)) -1
+ incr sfr($symbol(TL2)) 256
+ if {$sfr($symbol(TH2)) < 0} {
+ set sfr($symbol(TH2)) 255
+ return -1
+ }
+ }
+
+ # Normal operation
+ return 0
+
+}
+
+## Order UART to initialize transmission cycle
+ # @return void
+private method uart_start_transmission {} {
+ # Begin transmission with two instruction cycles delay
+ set uart_TX_in_progress -1
+
+ # Initialize internall transmission buffer (shift register)
+ switch $controllers_conf(UART_M) {
+ 0 {
+ set uart_TX_shift_reg [expr {$sfr($symbol(SBUFT)) + 0x100}]
+ }
+ 1 {
+ set uart_TX_shift_reg [expr {($sfr($symbol(SBUFT)) << 1) + 0x600}]
+ }
+ 2 {
+ set uart_TX_shift_reg [expr {($sfr($symbol(SBUFT)) << 1) + 0xC00 + ([getBit $symbol(TB8)] << 9)}]
+ }
+ 3 {
+ set uart_TX_shift_reg [expr {($sfr($symbol(SBUFT)) << 1) + 0xC00 + ([getBit $symbol(TB8)] << 9)}]
+ }
+ }
+
+ # Set line special funtion to data transmission
+ if {$controllers_conf(UART_M) == 0} {
+ $this pale_SLSF $PIN(TXD) 2
+ $this pale_SLSF $PIN(RXD) 1
+ } {
+ $this pale_SLSF $PIN(TXD) 1
+ }
+}
+
+## UART (Universal Asynchronous Receiver Transmitter) controller
+ # @parm Int num - Number of machine cycles performed by last set of instructions
+ # @return void
+private method uart_controller {num} {
+ set send_tx_shift_clock_sequence 0
+
+ # Manage UART clock prescaler
+ if {$uart_RX_in_progress || $uart_TX_in_progress} {
+ if {$controllers_conf(UART_M) == 1 || $controllers_conf(UART_M) == 3} {
+ incr uart_clock_prescaler $timer1_overflow
+ } elseif {$controllers_conf(UART_M) == 2} {
+ incr uart_clock_prescaler $num
+ }
+ }
+
+ # ----------------------------------------------------------------------
+ # RECEPTION PROCEDURE
+ # ----------------------------------------------------------------------
+
+ # Reception is already in progress
+ if {$uart_RX_in_progress} {
+ # Make backup for SBUF-R
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(SBUFR)
+ }
+
+ # Mode 0
+ if {!$controllers_conf(UART_M)} {
+ set send_tx_shift_clock_sequence $num
+ for {set i -$num} {$i <= 0} {incr i} {
+ set uart_RX_shift_reg [expr {$uart_RX_shift_reg << 1}]
+ incr uart_RX_shift_reg [$this pale_RRPPV $PIN(RXD) $i]
+
+ if {!($uart_RX_shift_reg & 0x100)} {
+ # Stop reception
+ set uart_RX_in_progress 0
+ $this pale_SLSF $PIN(RXD) 0
+ $this pale_SLSF $PIN(TXD) 0
+
+ # Set RI and SBUF
+ setBit $symbol(RI) 1
+ set sfr($symbol(SBUFR)) [expr {$uart_RX_shift_reg & 0x0FF}]
+
+ break
+ }
+ }
+ # Mode 1, 2 or 3
+ } else {
+ ## Select RX clock source
+ if {$controllers_conf(UART_M) == 2} {
+ if {$controllers_conf(SMOD)} {
+ incr uart_RX_clock [expr {$uart_clock_prescaler / 2}]
+ } {
+ incr uart_RX_clock [expr {$uart_clock_prescaler / 4}]
+ }
+ } {
+ # Timer 2 overflow
+ if {$controllers_conf(RCLK)} {
+ incr uart_RX_clock $timer2_overflow
+ # Timer 1 overflow
+ } {
+ if {$controllers_conf(SMOD)} {
+ incr uart_RX_clock $timer1_overflow
+ } {
+ incr uart_RX_clock [expr {$uart_clock_prescaler / 2}]
+ }
+ }
+ }
+
+ # Prescaler overflew -> Commence 1b reception
+ if {$uart_RX_clock >= 16} {
+ incr uart_RX_clock -16
+ set uart_RX_shift_reg [expr {$uart_RX_shift_reg << 1}]
+ incr uart_RX_shift_reg [$this pale_RRPPV $PIN(RXD)]
+
+ # Mode 1
+ if {$controllers_conf(UART_M) == 1} {
+ if {!($uart_RX_shift_reg & 0x200)} {
+ # Stop reception
+ set uart_RX_in_progress 0
+ $this pale_SLSF $PIN(RXD) 0
+
+ # Set RI and SBUF
+ setBit $symbol(RB8) [expr {$uart_RX_shift_reg & 1}]
+ set sfr($symbol(SBUFR)) [expr {($uart_RX_shift_reg & 0x1FE) >> 1}]
+
+ if {
+ (!$controllers_conf(RI) &&
+ (!$controllers_conf(SM2) || ($uart_RX_shift_reg & 1))
+ )
+ } then {
+ setBit $symbol(RI) 1
+ # Frame error
+ } else {
+ $this simulator_uart_invalid_stop_bit $pc $Line($pc)
+ internal_shutdown
+ }
+
+ # Frame error detection
+ if {$feature_avaliable(smod0) && !($uart_RX_shift_reg & 1)} {
+ set controllers_conf(FE) 1
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(SCON)
+ }
+ }
+ }
+ # Mode 2 or 3
+ } elseif {!($uart_RX_shift_reg & 0x400)} {
+ # Stop reception
+ set uart_RX_in_progress 0
+ $this pale_SLSF $PIN(RXD) 0
+
+ # Set RI and SBUF
+ setBit $symbol(RB8) [expr {$uart_RX_shift_reg & 2}]
+ set sfr($symbol(SBUFR)) [expr {($uart_RX_shift_reg & 0x3FC) >> 2}]
+ if {$controllers_conf(SM2)} {
+ if {$feature_avaliable(euart)} {
+ # Check for broadcast address
+ if {$sfr($symbol(SBUFR)) == ($sfr($symbol(SADEN)) | $sfr($symbol(SADDR)))} {
+ setBit $symbol(RI) $controllers_conf(RB8)
+ # Check for the given address
+ } elseif {($sfr($symbol(SBUFR)) & $sfr($symbol(SADEN))) == ($sfr($symbol(SADDR)) & $sfr($symbol(SADEN)))} {
+ setBit $symbol(RI) $controllers_conf(RB8)
+ }
+ } {
+ setBit $symbol(RI) $controllers_conf(RB8)
+ }
+ } {
+ setBit $symbol(RI) 1
+ }
+
+ # Frame error
+ if {$feature_avaliable(smod0) && !($uart_RX_shift_reg & 1)} {
+ set controllers_conf(FE) 1
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(SCON)
+ }
+ }
+ }
+ }
+ }
+
+ # Synchronize SBUF-R
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(SBUFR)
+ }
+
+ # Reception may begin now ...
+ } else {
+ # Mode 0 - REN starts reception
+ if {!$controllers_conf(UART_M)} {
+ if {$controllers_conf(REN) && !$controllers_conf(RI)} {
+ set uart_RX_in_progress 1
+ $this pale_SLSF $PIN(TXD) 2
+ $this pale_SLSF $PIN(RXD) 1
+
+ set uart_RX_shift_reg 0x1FE
+ }
+ # Mode 1, 2, 3 - Start bit starts reception
+ } {
+ if {![$this pale_RRPPV $PIN(RXD)]} {
+ set uart_RX_clock 0
+ set uart_RX_in_progress 1
+ $this pale_SLSF $PIN(RXD) 1
+
+ set uart_RX_shift_reg 0x3FE
+ }
+ }
+ }
+
+ # ----------------------------------------------------------------------
+ # TRASMISSION PROCEDURE
+ # ----------------------------------------------------------------------
+
+ # Trasmission just began, but with one machine cycle delay
+ if {$uart_TX_in_progress == -2} {
+ set uart_TX_in_progress 1
+ incr num -1
+
+ # Begin transmission on next instruction
+ } elseif {$uart_TX_in_progress == -1} {
+ set uart_TX_in_progress -2
+
+ # Transmission
+ } elseif {$uart_TX_in_progress == 1} {
+ # Make bakup for SBUF-T
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S $symbol(SBUFT)
+ }
+
+ # Mode 0
+ if {!$controllers_conf(UART_M)} {
+ set start_pos [expr {$num * (-2)}]
+
+ for {set i $start_pos} {$i < 0} {} {
+ incr i
+ set bit_to_send [expr {$uart_TX_shift_reg & 1}]
+ if {!$controllers_conf(X2)} {
+ $this pale_WPBBL $PIN(RXD) $bit_to_send $i
+ $this pale_WPBBL $PIN(TXD) 0 $i
+ incr i
+ $this pale_WPBBL $PIN(RXD) $bit_to_send $i
+ $this pale_WPBBL $PIN(TXD) 1 $i
+ } {
+ incr i
+ $this pale_WPBBL $PIN(TXD) {|} [expr {int($i / 2)}]
+ $this pale_WPBBL $PIN(RXD) $bit_to_send [expr {int($i / 2)}]
+ }
+
+ set uart_TX_shift_reg [expr {$uart_TX_shift_reg >> 1}]
+ set sfr($symbol(SBUFT)) $uart_TX_shift_reg
+
+ if {!($uart_TX_shift_reg & 0x1FE)} {
+
+ # Stop transmission
+ set uart_TX_in_progress 0
+ $this pale_SLSF $PIN(RXD) 0
+ $this pale_SLSF $PIN(TXD) 0
+
+ # Set TI
+ setBit $symbol(TI) 1
+
+ break
+ }
+ }
+ # Mode 1, 2, 3
+ } else {
+
+ ## Select TX clock source
+ if {$controllers_conf(UART_M) == 2} {
+ if {$controllers_conf(SMOD)} {
+ incr uart_TX_clock [expr {$uart_clock_prescaler / 2}]
+ } {
+ incr uart_TX_clock [expr {$uart_clock_prescaler / 4}]
+ }
+ } {
+ # Timer 2 overflow
+ if {$controllers_conf(TCLK)} {
+ incr uart_TX_clock $timer2_overflow
+ # Timer 1 overflow
+ } {
+ if {$controllers_conf(SMOD)} {
+ incr uart_TX_clock $timer1_overflow
+ } {
+ incr uart_TX_clock [expr {$uart_clock_prescaler / 2}]
+ }
+ }
+ }
+
+ # Prescaler overflew -> Commence 1b transmission
+ if {$uart_TX_clock >= 16} {
+ incr uart_TX_clock -16
+
+ $this pale_WPBBL $PIN(TXD) [expr {$uart_TX_shift_reg & 1}]
+ set uart_TX_shift_reg [expr {$uart_TX_shift_reg >> 1}]
+ set sfr($symbol(SBUFT)) $uart_TX_shift_reg
+
+ if {!($uart_TX_shift_reg & 0x7FE)} {
+ # Stop transmission
+ set uart_TX_in_progress 0
+ $this pale_SLSF $PIN(TXD) 0
+
+ # Set TI
+ setBit $symbol(TI) 1
+ }
+ }
+ }
+
+ # Synchronize SBUF-T
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S $symbol(SBUFT)
+ }
+ }
+
+ # Again manage UART clock prescaler
+ if {$uart_clock_prescaler && $controllers_conf(UART_M)} {
+ if {$controllers_conf(SMOD)} {
+ set uart_clock_prescaler [expr {$uart_clock_prescaler % 2}]
+ } {
+ set uart_clock_prescaler [expr {$uart_clock_prescaler % 4}]
+ }
+ }
+}
+
+## Timer 1 controller which operate while timer 0 is engaged in mode 3
+ # @return void
+private method special_timer1_controller_T0_MOD_3 {} {
+ set timer1_overflow 0
+
+ set TL1 $symbol(TL1)
+ set TH1 $symbol(TH1)
+
+ # Timer 1 mode
+ switch -- $controllers_conf(T1_MOD) {
+ 0 { ;# Mode 0 - 13 bit counter
+ incr sfr($TL1) $time
+ if {$sfr($TL1) > 31} {
+ incr sfr($TH1)
+ incr sfr($TL1) -32
+ if {$sfr($TH1) > 255} {
+ set sfr($TH1) 0
+ set timer1_overflow 1
+ }
+ }
+ }
+ 1 { ;# Mode 1 - 16 bit counter
+ incr sfr($TL1) $time
+ if {$sfr($TL1) > 255} {
+ incr sfr($TH1)
+ incr sfr($TL1) -256
+ if {$sfr($TH1) > 255} {
+ set sfr($TH1) 0
+ set timer1_overflow 1
+ }
+ }
+ }
+ 2 { ;# Mode 2 - 8 bit auto-reload counter
+ incr sfr($TL1) $time
+ while 1 {
+ if {$sfr($TL1) > 255} {
+ set sfr($TL1) [expr {$sfr($TL1) - 256 + $sfr($TH1)}]
+ incr timer1_overflow
+ } {
+ break
+ }
+ }
+ }
+ 3 { ;# Timer halted
+ }
+ }
+}
+
+## Timers controller for timers 0 and 1
+ # -- should be called after each instruction cycle
+ # @parm Int timer_num - Number of timer to hadnle ('0' or '1')
+ # @return void
+private method timer_controller_01 {timer_num} {
+ set timer1_overflow 0
+ set increment 0
+
+ # Start the timer if it is not already started
+ if {$timer_num == 1} {
+ if {!$timer_1_running} {
+ set timer_1_running 1
+ return
+ }
+ } {
+ if {!$timer_0_running} {
+ set timer_0_running 1
+ return
+ }
+ }
+
+ # Determinate counter increment
+ if {$controllers_conf(CT${timer_num})} {
+ # Detect 1-to-0 transition on external input
+ for {set i -$time} {$i < 0} {incr i} {
+ set counter_input_prev $controllers_conf(T${timer_num})
+ set controllers_conf(T${timer_num}) [$this pale_RRPPV $PIN(T${timer_num}) $i]
+
+ if {$counter_input_prev && !$controllers_conf(T${timer_num})} {
+ incr increment
+ }
+ }
+
+ # Trigered counter
+ if {$controllers_conf(GATE${timer_num})} {
+ # Read Intx and allow increment only if INTx is 1
+ if {![$this pale_RRPPV $PIN(INT${timer_num})]} {
+ set increment 0
+ }
+ }
+ } {
+ set increment $time
+
+ # Trigered timer
+ if {$controllers_conf(GATE${timer_num})} {
+ # Read Intx and allow increment only if INTx is 1
+ if {![$this pale_RRPPV $PIN(INT${timer_num})]} {
+ set increment 0
+ }
+ }
+ }
+
+ # Inrement timer 0 in mode 3 (Dual timer/counter)
+ if {$controllers_conf(T0_MOD) == 3} {
+ # Increment TH0
+ if {$timer_num == 1} {
+ incr sfr($symbol(TH0)) $time
+ if {$sfr($symbol(TH0)) > 255} {
+ set sfr($symbol(TH0)) [expr {$sfr($symbol(TH0)) - 256}]
+ setBit $symbol(TF1) 1
+ }
+ # Increment TL0
+ } {
+ incr sfr($symbol(TL0)) $increment
+ if {$sfr($symbol(TL0)) > 255} {
+ set sfr($symbol(TL0)) [expr {$sfr($symbol(TL0)) - 256}]
+ setBit $symbol(TF0) 1
+ }
+ }
+
+ return
+ }
+
+ # Determinate TLx and THx addresses
+ set TL_addr $symbol(TL${timer_num})
+ set TH_addr $symbol(TH${timer_num})
+
+ # Increment the timer in mode 0, 1 or 2
+ switch -- $controllers_conf(T${timer_num}_MOD) {
+ 0 { ;# Mode 0 - 13 bit counter
+
+ set TL_upper_3_bits [expr {$sfr($TL_addr) & 0xE0}]
+ set sfr($TL_addr) [expr {$sfr($TL_addr) & 0x1F}]
+
+ incr sfr($TL_addr) $increment
+ if {$sfr($TL_addr) > 31} {
+ incr sfr($TH_addr)
+ incr sfr($TL_addr) -32
+ if {$sfr($TH_addr) > 255} {
+ set sfr($TH_addr) 0
+ setBit $symbol(TF${timer_num}) 1
+ if {$timer_num} {
+ set timer1_overflow 1
+ }
+ }
+ }
+ set sfr($TL_addr) [expr {$sfr($TL_addr) | $TL_upper_3_bits}]
+ }
+ 1 { ;# Mode 1 - 16 bit counter
+ incr sfr($TL_addr) $increment
+ if {$sfr($TL_addr) > 255} {
+ incr sfr($TH_addr)
+ incr sfr($TL_addr) -256
+ if {$sfr($TH_addr) > 255} {
+ set sfr($TH_addr) 0
+ setBit $symbol(TF${timer_num}) 1
+ if {$timer_num} {
+ set timer1_overflow 1
+ }
+ }
+ }
+ }
+ 2 { ;# Mode 2 - 8 bit auto-reload counter
+ incr sfr($TL_addr) $increment
+ while 1 {
+ if {$sfr($TL_addr) > 255} {
+ set sfr($TL_addr) [expr {$sfr($TL_addr) - 256 + $sfr($TH_addr)}]
+ setBit $symbol(TF${timer_num}) 1
+ if {$timer_num} {
+ incr timer1_overflow
+ }
+ } {
+ break
+ }
+ }
+ }
+ 3 { ;# Timer halted (timer 1)
+ }
+ }
+}
+
+## Data EEPROM controller
+ # @parm Int num - Number of clock cycles preformed divided by 6
+ # @return void
+private method eeprom_controller {num} {
+ if {!$eeprom_size || !$eeprom_WR} {return}
+
+ # Conditionaly abort write cycle
+ if {!$controllers_conf(WRTINH) || !$controllers_conf(EEMWE)} {
+ if {!${::Simulator::ignore_EEPROM_WR_abort}} {
+ $this simulator_EEPROM_WR_abort $pc $Line($pc)
+ internal_shutdown
+ }
+
+ # Fill incomplite bytes with random values
+ set eeprom_prev_new [list]
+ foreach reg $eeprom_prev {
+ lappend eeprom_prev_new [lindex $reg 0] [undefined_octet]
+ }
+ set eeprom_prev $eeprom_prev_new
+
+ simulator_cancel_write_to_eeprom
+ return
+ }
+
+ set eeprom_WR_time_org [expr {int($eeprom_WR_time)}]
+ set eeprom_WR_time [expr {$eeprom_WR_time + $num * (300.0 / $clock_kHz)}]
+
+ # Write cycle complete
+ if {$eeprom_WR_time > 100.0} {
+ simulator_finalize_write_to_eeprom
+
+ # Write still in progress
+ } elseif {$eeprom_WR_time_org != int($eeprom_WR_time)} {
+ $this simulator_WTE_prg_set [expr {int($eeprom_WR_time)}]
+ }
+
+}
+
+## Watchdog controller
+ # @return Bool - true == MCU reseted; false == all in normal
+private method watchdog_controller {} {
+
+ # Watchdog timer software controll
+ if {!$controllers_conf(HWDT)} {
+
+ # Reset
+ if {$controllers_conf(WSWRST)} {
+ set watchdog_value -$time
+ set controllers_conf(WSWRST) 0
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 167
+ }
+ set sfr(167) [expr {$sfr(167) - 2}]
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S 167
+ }
+ }
+
+ # Enable / Disable
+ if {$controllers_conf(WDTEN) && !$controllers_conf(WatchDogTimer)} {
+ incr watchdog_value -$time
+ set controllers_conf(WatchDogTimer) 1
+ }
+
+ # Hardware control -- WDTEN is read-only (1 == running; 0 == stopped)
+ } elseif {$controllers_conf(WatchDogTimer) != $controllers_conf(WDTEN)} {
+ set controllers_conf(WDTEN) $controllers_conf(WatchDogTimer)
+ if {${::Simulator::reverse_run_steps}} {
+ stepback_reg_change S 167
+ }
+ if {$controllers_conf(WDTEN)} {
+ set sfr(167) [expr {$sfr(167) | 1}]
+ } {
+ set sfr(167) [expr {$sfr(167) - 1}]
+ }
+ if {$sync_ena} {
+ $this Simulator_GUI_sync S 167
+ }
+ }
+
+ # Check if watchdog is enabled
+ if {!$controllers_conf(WatchDogTimer)} {
+ return 0
+ }
+
+ # Increment watchdog prescaler first
+ set increment 0
+ if {$controllers_conf(WatchDogPrescaler)} {
+ incr wdt_prescaler_val $time
+ while 1 {
+ if {$wdt_prescaler_val >= $controllers_conf(WatchDogPrescaler)} {
+ incr wdt_prescaler_val -$controllers_conf(WatchDogPrescaler)
+ incr increment
+ } {
+ break
+ }
+ }
+ } {
+ set increment $time
+ }
+
+ # Increment watchdog time
+ if {!$increment} {return 0}
+ incr watchdog_value $increment
+ if {$watchdog_value < 8192} {
+ return 0
+ }
+
+ # Handle watchdog overflow
+ incr watchdog_value -8192
+ incr time -$watchdog_value
+ incr time 8
+ set watchdog_value 0
+ master_reset -
+ $this Simulator_sync_PC_etc
+
+ # Shutdown simulator and inform user about the situation
+ if {!${::Simulator::ignore_watchdog_reset}} {
+ internal_shutdown
+ $this simulator_watchdog_reset $pc $Line($pc)
+ }
+
+ return 1
+}
+
+## Resolve interrupt priority
+ # @parm String flag - Interrupt name
+ # @return Int - 0..3
+private method interrupt_priority {IntName} {
+ return [lindex $controllers_conf(IP_level) \
+ [lsearch $controllers_conf(IP) $IntName] \
+ ]
+}
+
+## Translate interrupt name to interrupt vector
+ # @parm String IntName - Interrupt name (one of {PX0 PT0 PX1 PT1 PS PT2 PC})
+ # @return Int - Interrupt vector
+public method intr2vector {intname} {
+ switch -- $intname {
+ {PX0} {return 3}
+ {PT0} {return 11}
+ {PX1} {return 19}
+ {PT1} {return 27}
+ {PS} {return 35}
+ {PT2} {return 43}
+ {PC} {return 51}
+ }
+}
+
+## Interrupt controller -- handles interrupt requests
+ # @parm String IntName - Interrupt name (one of {PX0 PT0 PX1 PT1 PS PT2 PC})
+ # @parm Int vector - Interrupt vector (eg. '27' (T1 on 0x1B))
+ # @parm String flag_bit - Name of interrupt flag
+ # @parm Bool immediately - Invoked by user
+ # @return Bool - 0 == interrupt denied; 1 == interrupt accepted
+private method interrupt_handler {IntName vector flag_bit immediately} {
+
+ if {!$immediately} {
+ # Set interrupt_on_next if the time is too low
+ if {$time == 1 && !$interrupt_on_next} {
+ set interrupt_on_next 1
+ return 0
+ }
+
+ # If the last instruction was RETI or any access to the IE, IP or IPH registers -> SKIP
+ if {$skip_interrupt} {
+ set skip_interrupt 0
+ return 0
+ }
+ }
+
+ # Adjust program run statistics
+ incr run_statistics(5)
+
+ # Set interrupt related variables
+ set interrupt_on_next 0 ;# Bool: Invoke interrupt on the next instruction
+ lappend interrupts_in_progress $IntName ;# List: Priority flags of interrupts which are in progress
+ lappend inter_in_p_flags $flag_bit ;# List: Interrupt flags of interrupts which are in progress
+
+ # Adjust status bar
+ simulator_Sbar [mc "Interrupt PC: 0x%s; line: %s; vector 0x%s " [format %X $pc] [lindex $Line($pc) 0] [format %X $vector]] 1 $this
+ $this pale_interrupt $vector
+
+ # Invoke LCALL to interrupt vector
+ incr time 2
+ if {!$immediately} {
+ stepback_save_spec_subprog 1
+ }
+ uart_controller 2
+ if {[increment_program_time 2]} {return}
+ stack_push [expr {$pc & 255}]
+ stack_push [expr {($pc & 65280) >> 8}]
+ $this subprograms_call 2 $pc $vector
+ $this stack_monitor_set_last_values_as 2 2
+ incr run_statistics(3)
+
+ # Unset interrupt flag
+ switch -- $IntName {
+ {PX0} { ;# External 0
+ if {$controllers_conf(IT0)} {
+ setBit $symbol(IE0) 0
+ }
+ }
+ {PT0} { ;# Timer 0
+ setBit $symbol(TF0) 0
+ }
+ {PX1} { ;# External 1
+ if {$controllers_conf(IT1)} {
+ setBit $symbol(IE1) 0
+ }
+ }
+ {PT1} { ;# Timer 1
+ setBit $symbol(TF1) 0
+ }
+ {PT2} { ;# Timer 2
+ }
+ {PS} { ;# UART
+ }
+ {PC} { ;# Analog comparator
+ }
+ }
+
+ # Report interrupt to interrupt monitor
+ set flag {}
+ switch $IntName {
+ {PX0} {set flag IE0}
+ {PT0} {set flag TF0}
+ {PX1} {set flag IE1}
+ {PT1} {set flag TF1}
+ {PT2} {
+ foreach flag {TF2 EXF2} {
+ if {$controllers_conf($flag)} {break}
+ }
+ }
+ {PS} {
+ foreach flag {SPIF TI RI} {
+ if {$controllers_conf($flag)} {break}
+ }
+ }
+ {PC} {set flag CF}
+ }
+ if {!$immediately} {
+ $this interrupt_monitor_intr $flag
+ }
+
+ # Done ...
+ set pc $vector
+ return 1
+}
+
+## Test if the given interrupt is active (routine engaged)
+ # @parm String IntName - Interrupt name
+ # @return List - Interrupt vector or 0 in there is no interrupt active & Flag bit
+private method isInterruptActive {IntName} {
+ switch -- $IntName {
+ {PX0} { ;# External 0
+ if {!$controllers_conf(EX0)} {return 0}
+ if {$controllers_conf(IE0)} {return {3 IE0}}
+ }
+ {PT0} { ;# Timer 0
+ if {!$controllers_conf(ET0)} {return 0}
+ if {$controllers_conf(TF0)} {return {11 TF0}}
+ }
+ {PX1} { ;# External 1
+ if {!$controllers_conf(EX1)} {return 0}
+ if {$controllers_conf(IE1)} {return {19 IE1}}
+ }
+ {PT1} { ;# Timer 1
+ if {!$controllers_conf(ET1)} {return 0}
+ if {$controllers_conf(TF1)} {return {27 TF1}}
+ }
+ {PS} { ;# UART & SPI
+ if {!$controllers_conf(ES)} {return 0}
+ if {$feature_avaliable(uart)} {
+ if {$controllers_conf(TI)} {
+ return {35 TI}
+ } elseif {$controllers_conf(RI)} {
+ return {35 RI}
+ }
+ }
+ if {$feature_avaliable(spi) && $controllers_conf(SPIE) && $controllers_conf(SPIF)} {
+ return {35 SPIE}
+ }
+ }
+ {PT2} { ;# Timer 2
+ if {!$controllers_conf(ET2)} {return 0}
+ if {$controllers_conf(TF2)} {
+ return {43 TF2}
+ } elseif {
+ $controllers_conf(EXF2) && $timer_2_running && (
+ $controllers_conf(T2OE) || $controllers_conf(RCLK) ||
+ $controllers_conf(TCLK) || $controllers_conf(CPRL2)
+ )
+ } then {
+ return {43 EXF2}
+ } else {
+ return 0
+ }
+ }
+ {PC} { ;# Analog comparator
+ if {!$controllers_conf(EC)} {return 0}
+ if {$controllers_conf(CF)} {return {51 CF}}
+ }
+ }
+ return 0
+}
diff --git a/lib/simulator/hibernate.tcl b/lib/simulator/hibernate.tcl
new file mode 100755
index 0000000..c35f4f8
--- /dev/null
+++ b/lib/simulator/hibernate.tcl
@@ -0,0 +1,1051 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides program hibernation capability. It ohter words it can save
+# current state of simulator engine to a file (*.m5ihib) and later
+# restrore state save in that file and resume hibernated program.
+#
+# Usage:
+# hibernate_hibernate <filename.m5ihib> <sourcefile> <source_md5> <exclude_stepback>
+# ;# -> Bool (1 == successfull; 0 == failed)
+# ;# This function also invokes dialog showing hibernation progress
+#
+# hibernate_resume <filename.m5ihib> <exclude_stepback>
+# ;# -> Bool (1 == successfull; 0 == failed)
+# ;# This function also invokes dialog showing progress
+#
+# Note: These functions are safe (checks for filename usability)
+# --------------------------------------------------------------------------
+
+class Hibernate {
+ ## COMMON
+ common version {1.0} ;# Float: Hibernate facility version
+ common hib_progress_d 0 ;# Int: Variable for hibernation progress dialog -- Memory
+ common hib_progress_s 0 ;# Int: Variable for hibernation progress dialog -- Program steps
+ common hib_abort 0 ;# Bool: Abort hibernation process
+ common expected ;# String: Expected next XML element
+ common take_data ;# Bool: Take element data on next parsing cycle
+ common current_element {} ;# String: Current XML element -- auxiliary variable for XML parser handler
+ common xml_tmp {} ;# Mixed: Auxiliary variable of any kind for XML parser handler
+ common source_file {} ;# String: Filename of the file from which the given file was generated
+ common exclude_stepback 0 ;# Bool: Exclude program steps
+ common counter 0 ;# Int: Counter of iterations for resume function for XML parser handler
+ common xdata_size 0 ;# Int: Size of external data memory
+ common eeprom_size 0 ;# Int: Size of data EEPROM
+ common sbs_length 0 ;# Int: Size of stepback stack
+ common file_variable ;# Bool: Checkbox variable for "Different filename"
+ common mcu_variable ;# Bool: Checkbox variable for "Different processor"
+ common xdata_variable ;# Int: RadioButton variable for "Different XDATA size"
+ common md5_variable ;# Bool: Checkbox variable for "Different MD5 hash"
+ # Big font for dialog "Program resumption"
+ common big_font [font create \
+ -family {helvetica} \
+ -weight bold -size -35 \
+ ]
+ # Normal font for dialog "Program resumption"
+ common text_font [font create \
+ -family {helvetica} \
+ -weight bold -size -14 \
+ ]
+
+ ## PRIVATE
+ private variable parser ;# Object: Reference to active XML parser
+ private variable mem_prg_bar ;# Widget: Memory progress bar
+ private variable stb_prg_bar ;# Widget: Program steps progress bar
+
+ private variable dlg_ok_but ;# Widget: Button "Ok" in dialog "Program resumption"
+ private variable dlg_result ;# Bool: Result of dialog "Program resumption"
+ private variable dlg_bits ;# List of Booleans: Differencies between hibernation file and engine config
+
+ ## Dafety close hibernation/resumption progress dialog
+ # @return void
+ public method hibernate_close_progress_dialog {} {
+ set win {.hibernation_progress_dialog}
+ if {[winfo exists $win]} {
+ grab release $win
+ destroy $win
+ }
+ }
+
+ ## Set maximum value for some progress bar in the hibernation progress dialog
+ # @parm String for_what - "data" == Memory ProgressBar; "step" == "Program steps"
+ # @parm Int value - New maximum value
+ # @return void
+ private method progress_dialog_set_max {for_what value} {
+ if {![winfo exists {.hibernation_progress_dialog}]} {
+ return
+ }
+ if {$value < 1} {
+ set value 1
+ }
+ if {$for_what == {data}} {
+ $mem_prg_bar configure -maximum $value
+ } {
+ $stb_prg_bar configure -maximum $value
+ }
+ }
+
+ ## Invoke hibernation / resumption progress dialog
+ # @parm String header - Window header
+ # @parm Int data_max - Maximum value for progress bar "Memory" (can be less than 1)
+ # @parm Int stepback_max - Maximum value for progress bar "Program steps" (can be less than 1)
+ # @return void
+ private method show_progress_dialog {header data_max stepback_max} {
+ # Reset NS variables related to this dialog
+ set hib_progress_d 0
+ set hib_progress_s 0
+ set hib_abort 0
+
+ # Adjust input values
+ if {$data_max < 1} {
+ set data_max 1
+ }
+ incr data_max 2
+ if {$stepback_max < 1} {
+ set stepback_max 1
+ }
+
+ # Create dialog window
+ set win [toplevel .hibernation_progress_dialog -class {Progress dialog} -bg {#EEEEEE}]
+
+ # Create dialog header
+ pack [label $win.header \
+ -text $header \
+ -font [font create \
+ -size -17 -weight {bold} \
+ -family {helvetica} \
+ ] \
+ ] -fill x
+
+ # Create progress bar "Memory"
+ set frame [frame $win.frame_0]
+ pack [label $frame.label -text {Memory}] -anchor w -padx 5
+ set mem_prg_bar [ttk::progressbar $frame.progressbar \
+ -mode determinate \
+ -variable ::Hibernate::hib_progress_d \
+ -maximum $data_max \
+ ]
+ pack $mem_prg_bar -fill x
+ pack $frame -pady 5 -fill x -padx 5
+
+ # Create progress bar "Program steps"
+ set frame [frame $win.frame_1]
+ pack [label $frame.label -text {Program steps}] -anchor w -padx 5
+ set stb_prg_bar [ttk::progressbar $frame.progressbar \
+ -mode determinate \
+ -variable ::Hibernate::hib_progress_s \
+ -maximum $stepback_max \
+ ]
+ pack $stb_prg_bar -fill x
+ pack $frame -pady 5 -fill x -padx 5
+
+ # Create button "Abort"
+ pack [ttk::button $win.abort_button \
+ -text [mc "Abort"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command {set ::Hibernate::hib_abort 1} \
+ ] -padx 10 -fill x
+
+ # Configure dialog window
+ wm iconphoto $win ::ICONS::16::bar5
+ wm title $win [mc "Hibernation progress"]
+ wm minsize $win 300 140
+ wm protocol $win WM_DELETE_WINDOW "$this hibernate_close_progress_dialog"
+ wm transient $win .
+ update
+ catch {
+ grab $win
+ raise $win
+ }
+ }
+
+ ## Hibernate running program
+ # @parm String filename - Target file
+ # @parm String sourcefile - Source file (current file in code editor)
+ # @parm String md5 - MD5 hash of the source file
+ # @parm Bool exclude_stepback - Exclude program steps
+ # @return Bool - 1 == Successful; 0 == Failed
+ public method hibernate_hibernate {filename sourcefile md5 exclude_stepback} {
+ # Try to open the destination file
+ if {[catch {
+ set file [open $filename w 420]
+ }]} {
+ return 0
+ }
+
+ # Determinate depth of stepback stack and size of XDATA memory
+ if {$exclude_stepback} {
+ set stacklength 0
+ } {
+ set stacklength [$this simulator_get_SBS_len]
+ }
+ set xdata_size [$this cget -P_option_mcu_xdata]
+ set eeprom_size [lindex [$this cget -procData] 32]
+
+ # Invoke progress dialog
+ show_progress_dialog \
+ {Hibernating program} \
+ [expr {($xdata_size + $eeprom_size) / 4096}] \
+ [expr {$stacklength / 10}]
+
+ # Write XML header to the destination file
+ puts -nonewline $file "<?xml version='1.0' encoding='utf-8'?>\n"
+ puts -nonewline $file "<!--\n"
+ puts -nonewline $file "\tThis is MCU 8051 IDE hibernation data file.\n"
+ puts -nonewline $file "\tIt does not contain program code, only data.\n\n"
+ puts -nonewline $file "\tPLEASE DO NOT EDIT THIS FILE MANUALY, BECAUSE\n"
+ puts -nonewline $file "\tBAD FORMATING OF THIS FILE WILL LEAD MCU 8051 IDE TO CRASH !\n"
+ puts -nonewline $file "-->\n"
+
+ # Write DTD (Document Type Declaration) to the destination file
+ if {[file exists "${::LIB_DIRNAME}/../data/m5ihib.dtd"]} {
+ if {[catch {
+ set dtd [open "${::LIB_DIRNAME}/../data/m5ihib.dtd" r]
+ }]} {
+ puts stderr "Unable to open m5ihib.dtd, please check your installation."
+ } else {
+ puts -nonewline $file "<!DOCTYPE m5ihib \[\n\n"
+ while 1 {
+ if {[eof $dtd]} {
+ close $dtd
+ break
+ }
+ puts -nonewline $file "\t"
+ puts $file [gets $dtd]
+ }
+ puts -nonewline $file "\]>\n"
+ }
+ }
+
+ # Write header
+ puts -nonewline $file "<m5ihib\n"
+ puts -nonewline $file "\tversion=\"$version\"\n"
+ puts -nonewline $file "\tdatetime=\"[clock format [clock seconds] -format {%D %T}]\"\n"
+ puts -nonewline $file "\tsource_file=\"$sourcefile\"\n"
+ puts -nonewline $file "\tprocessor=\"[$this cget -P_option_mcu_type]\"\n"
+ puts -nonewline $file "\txdata=\"$xdata_size\"\n"
+ puts -nonewline $file "\teeprom=\"$eeprom_size\"\n"
+ puts -nonewline $file "\tmd5=\"$md5\">\n"
+
+ ## Write current state of simulator engine
+ puts -nonewline $file "\t<currentstate>\n"
+ # Internal data memory
+ puts -nonewline $file "\t\t<iram>\n\t\t\t"
+ for {set i 0; set j 0} {$i < [lindex [$this cget -procData] 3]} {incr i; incr j} {
+ if {$j > 7} {
+ set j 0
+ puts -nonewline $file "\n\t\t\t"
+ }
+ puts -nonewline $file [$this getDataDEC $i]
+ puts -nonewline $file "\t"
+ }
+ incr hib_progress_d
+ puts -nonewline $file "\n\t\t</iram>\n"
+ # Expanded data memory
+ puts -nonewline $file "\t\t<eram>\n\t\t\t"
+ for {set i 0; set j 0} {$i < [lindex [$this cget -procData] 8]} {incr i; incr j} {
+ if {$j > 7} {
+ set j 0
+ puts -nonewline $file "\n\t\t\t"
+ }
+ puts -nonewline $file [$this getEramDEC $i]
+ puts -nonewline $file "\t"
+ }
+ incr hib_progress_d
+ puts -nonewline $file "\n\t\t</eram>\n"
+ # External data memory
+ puts -nonewline $file "\t\t<xram>\n\t\t\t"
+ set i 0
+ set j 0
+ for {set m 0} {$m < 8} {incr m} {
+ for {set k 0} {$i < $xdata_size && $k < 4096} {incr k} {
+ if {$j > 7} {
+ set j 0
+ puts -nonewline $file "\n\t\t\t"
+ }
+ puts -nonewline $file [$this getXdataDEC $i]
+ puts -nonewline $file "\t"
+ incr i
+ incr j
+
+ if {$hib_abort} {
+ catch {
+ file delete -force $filename
+ }
+ hibernate_close_progress_dialog
+ return 1
+ }
+ }
+ incr hib_progress_d
+ update
+ }
+ puts -nonewline $file "\n\t\t</xram>\n"
+ # Special function registers
+ puts -nonewline $file "\t\t<eeprom>\n\t\t\t"
+ set i 0
+ set j 0
+ for {set m 0} {$m < 8} {incr m} {
+ for {set k 0} {$i < $eeprom_size && $k < 4096} {incr k} {
+ if {$j > 7} {
+ set j 0
+ puts -nonewline $file "\n\t\t\t"
+ }
+ puts -nonewline $file [$this getEepromDEC $i]
+ puts -nonewline $file "\t"
+ incr i
+ incr j
+
+ if {$hib_abort} {
+ catch {
+ file delete -force $filename
+ }
+ hibernate_close_progress_dialog
+ return 1
+ }
+ }
+ incr hib_progress_d
+ update
+ }
+ puts -nonewline $file "\n\t\t</eeprom>\n"
+ # Special function registers
+ puts -nonewline $file "\t\t<sfr>\n"
+ puts -nonewline $file "\t\t\t<addresses>\n\t\t\t\t"
+ set sfr [$this simulator_get_avaliable_sfr]
+ set j 0
+ foreach addr $sfr {
+ if {$j > 6} {
+ set j 0
+ puts -nonewline $file "\n\t\t\t\t"
+ }
+ puts -nonewline $file $addr
+ puts -nonewline $file "\t"
+ incr j
+ }
+ puts -nonewline $file "\n\t\t\t</addresses>\n"
+ puts -nonewline $file "\t\t\t<values>\n\t\t\t\t"
+ set j 0
+ foreach addr $sfr {
+ if {$j > 6} {
+ set j 0
+ puts -nonewline $file "\n\t\t\t\t"
+ }
+ puts -nonewline $file [$this getSfrDEC $addr]
+ puts -nonewline $file "\t"
+ incr j
+ }
+ puts -nonewline $file "\n\t\t\t</values>\n"
+ puts -nonewline $file "\t\t</sfr>\n"
+ # Special engine configuration string
+ puts -nonewline $file "\t\t<special>\n\t\t\t"
+ puts -nonewline $file [$this simulator_get_special]
+ puts -nonewline $file "\n\t\t</special>\n"
+ puts -nonewline $file "\t</currentstate>\n"
+
+ ## Write content of list of active interrupts
+ puts -nonewline $file "\t<subprograms count=\"[$this subprograms_get_count]\">\n"
+ foreach sub [$this subprograms_get_formated_content] {
+ set source [lindex $sub 0]
+ set target [lindex $sub 1]
+ set type [lindex $sub 2]
+ puts -nonewline $file "\t\t<sub source=\"$source\" target=\"$target\" type=\"$type\"/>\n"
+ }
+ puts -nonewline $file "\t</subprograms>\n"
+
+ ## Write stepback stack
+ puts -nonewline $file "\t<stepback stacklength=\"$stacklength\">\n"
+ for {set i 0} {$i < $stacklength} {incr i} {
+ puts -nonewline $file "\t\t<step>\n"
+ puts -nonewline $file "\t\t\t<spec>\n\t\t\t\t"
+ puts -nonewline $file [$this simulator_hib_get_SB_spec $i]
+ puts -nonewline $file "\n\t\t\t</spec><normal>\n"
+ set stepback_normal [$this simulator_hib_get_SB_norm $i]
+ set norm_len [llength $stepback_normal]
+ for {set j 0} {$j < $norm_len} {incr j} {
+ puts -nonewline $file "\t\t\t\t<reg type=\""
+ puts -nonewline $file [lindex $stepback_normal [list $j 0]]
+ puts -nonewline $file "\" addr=\""
+ puts -nonewline $file [lindex $stepback_normal [list $j 1]]
+ puts -nonewline $file "\" val=\""
+ puts -nonewline $file [lindex $stepback_normal [list $j 2]]
+ puts -nonewline $file "\"/>\n"
+ }
+ puts -nonewline $file "\t\t\t</normal>\n"
+ puts -nonewline $file "\t\t</step>\n"
+
+ if {!($i % 10)} {
+ incr hib_progress_s
+ update
+ }
+ if {$hib_abort} {
+ catch {
+ file delete -force $filename
+ }
+ hibernate_close_progress_dialog
+ return 1
+ }
+ }
+ puts -nonewline $file "\t</stepback>\n"
+ puts -nonewline $file "</m5ihib>\n"
+
+ # Close progress dialog and the destination file
+ hibernate_close_progress_dialog
+ if {[catch {close $file}]} {
+ return 0
+ } {
+ return 1
+ }
+ }
+
+ ## Resume hibernated program
+ # @parm String filename - Source file (XML containing hibernation data)
+ # @parm Bool exclude_stepback - Exclude program steps for step back function
+ # @return Int - Exit code
+ # 0 - Success
+ # 1 - Unable to open the given file
+ # 2 - Unable to parse the given file
+ public method hibernate_resume {filename _exclude_stepback} {
+ # Initialize parser variables
+ set expected {m5ihib}
+ set take_data 0
+ set counter 0
+ set sbs_length 0
+ set current_element {}
+ set xml_tmp {}
+ set source_file $filename
+ set exclude_stepback $_exclude_stepback
+
+ set exit_code 0
+
+ # Open hibernation data file
+ if {[catch {
+ set file [open $filename {r}]
+ }]} {
+ return 1
+ }
+
+ # Show progress dialog
+ show_progress_dialog {Resuming hibernated program} 1 1
+
+ # Create XML parser object
+ if {[catch {
+ set parser [::xml::parser -final 1 -ignorewhitespace 1 \
+ -elementstartcommand [list $this hibernate_xml_parser_element] \
+ -characterdatacommand [list $this hibernate_xml_parser_data] \
+ ]
+ }]} {
+ hibernate_close_progress_dialog
+ tk_messageBox \
+ -type ok -icon error -parent . \
+ -title "::xml::parser error" \
+ -message "Unknown error occured in XML parser library,\nplease try to reinstall package \"tdom\"."
+ return 2
+ }
+
+ # Prepare simulator engine
+ if {!$exclude_stepback} {
+ $this stepback_discard_stack
+ }
+
+ # Start XML parser
+ $this set_ignore_warnings_related_to_changes_in_SFR 1
+ if {[catch {
+ $parser parse [read $file]
+ } result]} then {
+ puts stderr $result
+ set exit_code 2
+ } else {
+ if {$xml_tmp != {}} {
+ $this simulator_hib_append_SB_norm $xml_tmp
+ }
+ }
+
+ # Close the file and free the parser
+ if {[catch {
+ close $file
+ }]} {
+ set exit_code 1
+ }
+ catch {
+ $parser free
+ }
+
+ # Synchronize simulator GUI
+ $this clear_graph
+ $this Simulator_sync
+ $this interrupt_monitor_reevaluate
+ $this stopwatch_refresh
+ set interrupts_in_progress [$this simulator_get_interrupts_in_progress_pb]
+ if {[llength $interrupts_in_progress]} {
+ simulator_Sbar [mc "Interrupt at vector 0x%s " [format %X [$this intr2vector [lindex $interrupts_in_progress end]]]] 1 $this
+ } {
+ simulator_Sbar {} 0 $this
+ }
+ set lineNum [$this simulator_getCurrentLine]
+ if {$lineNum != {}} {
+ $this move_simulator_line $lineNum
+ } {
+ $this editor_procedure {} unset_simulator_line {}
+ }
+ ::X::stepback_button_set_ena [$this simulator_get_SBS_len]
+
+ # Cleanup
+ set xml_tmp {}
+ hibernate_close_progress_dialog
+ $this set_ignore_warnings_related_to_changes_in_SFR 0
+ return $exit_code
+ }
+
+ ## Element XML parser handler for method hibernate_resume
+ # @parm String arg1 - name of the element
+ # @parm List attrs - list of attributes '{attr0 val0 attr1 val1 ...}'
+ # @return void
+ public method hibernate_xml_parser_element {arg1 attrs} {
+ if {$hib_abort} {
+ $parser free
+ return
+ }
+
+ set current_element $arg1
+ if {[lsearch $expected $current_element] == -1} {
+ error "Unexpected element: `$current_element'"
+ }
+
+ switch -- $arg1 {
+ {m5ihib} { ;# ROOT ELEMENT
+ set expected {currentstate}
+ set take_data 0
+
+ # Read the file header
+ set len [llength $attrs]
+ set xml_tmp [list {} {} {} {} {} {} {}]
+ for {set i 0} {$i < $len} {incr i} {
+ set arg [lindex $attrs $i]
+ incr i
+ set val [lindex $attrs $i]
+ switch -- $arg {
+ {version} {lset xml_tmp 0 $val}
+ {datetime} {lset xml_tmp 1 $val}
+ {source_file} {lset xml_tmp 2 $val}
+ {processor} {lset xml_tmp 3 $val}
+ {xdata} {lset xml_tmp 4 $val}
+ {eeprom} {lset xml_tmp 5 $val}
+ {md5} {lset xml_tmp 6 $val}
+ }
+ }
+
+ # Check if all of required fields are present
+ foreach str $xml_tmp {
+ if {![string length $str]} {
+ error "XML tag <m5ihib>: Some required attributes missing"
+ }
+ }
+
+ # Check for minimum required version
+ if {$version < [lindex $xml_tmp 0]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Fatal error"] \
+ -message [mc "Version of this M5IHIB file is higher than %s\nUnable to continue." $version]
+ set hib_abort 1
+ }
+
+ # Set maximum for ProgressBar "Memory" and set size of XDATA memory
+ set xdata_size [lindex $xml_tmp 4]
+ set eeprom_size [lindex $xml_tmp 5]
+ progress_dialog_set_max data [expr {$xdata_size / 4096}]
+
+ # Check for remaining requirements
+ check_file_usability
+
+ set xml_tmp {}
+
+ }
+ {currentstate} { ;# Current state of MCU
+ set expected {iram}
+ set take_data 0
+ }
+ {iram} { ;# Internal data memory in decimal
+ set expected {eram}
+ set take_data 1
+ }
+ {eram} { ;# Expanded data memory in decimal
+ set expected {xram}
+ set take_data 1
+ }
+ {xram} { ;# External data memory in decimal
+ set expected {eeprom}
+ set take_data 1
+ set counter 0
+ }
+ {eeprom} { ;# Data EEPROM in decimal
+ set expected {sfr}
+ set take_data 1
+ set counter 0
+ }
+ {sfr} { ;# Special function registers
+ set expected {addresses}
+ set take_data 0
+ }
+ {addresses} { ;# SFR decimal addresses in the same order as in tag values
+ set expected {values}
+ set take_data 1
+ }
+ {values} { ;# SFR decimal values in the same order as in tag values
+ set expected {special}
+ set take_data 1
+ }
+ {special} { ;# Special engine variables
+ set expected {subprograms}
+ set take_data 1
+
+ if {$exclude_stepback} {
+ set hib_abort 1
+ }
+ }
+ {subprograms} { ;# Content of list of active interrupts
+ set expected {stepback sub}
+ set take_data 0
+
+ $this subprograms_clear
+ }
+ {sub} { ;# Active interrupt
+ set expected {stepback sub}
+ set take_data 0
+
+ set source {}
+ set target {}
+ set type {}
+
+ set len [llength $attrs]
+ for {set i 0} {$i < $len} {incr i} {
+ switch -- [lindex $attrs $i] {
+ {type} {
+ incr i
+ set type [lindex $attrs $i]
+ }
+ {source} {
+ incr i
+ set source [lindex $attrs $i]
+ }
+ {target} {
+ incr i
+ set target [lindex $attrs $i]
+ }
+ default {
+ incr i
+ }
+ }
+ }
+ if {$source != {} && $target != {} && $type != {}} {
+ $this subprograms_call $type $source $target
+ } {
+ error "Invalid argument set in tag <step>"
+ }
+ }
+ {stepback} { ;# Stack for stepback function (backward stepping)
+ set expected {step}
+ set take_data 0
+ set counter 0
+
+ set len [llength $attrs]
+ for {set i 0} {$i < $len} {incr i 2} {
+ if {[lindex $attrs $i] == {stacklength}} {
+ incr i
+ set stacklength [lindex $attrs $i]
+ $this simulator_set_SBS_len $stacklength
+ progress_dialog_set_max stepback [expr {$stacklength / 10}]
+ break
+ } {
+ incr i
+ }
+ }
+ }
+ {step} { ;# One program step
+ set expected {spec}
+ set take_data 0
+ }
+ {spec} { ;# Special engine variables
+ set expected {normal}
+ set take_data 1
+ }
+ {normal} { ;# Ordinary registers
+ set expected {step reg}
+ set take_data 0
+
+ if {$xml_tmp != {}} {
+ $this simulator_hib_append_SB_norm $xml_tmp
+ }
+ set xml_tmp {}
+ }
+ {reg} { ;# One register
+ set expected {reg step}
+ set take_data 0
+
+ set reg [list {} {} {}]
+ set len [llength $attrs]
+
+ for {set i 0} {$i < $len} {incr i} {
+ set arg [lindex $attrs $i]
+ incr i
+ set val [lindex $attrs $i]
+
+ switch -- $arg {
+ {type} {lset reg 0 $val}
+ {addr} {lset reg 1 $val}
+ {val} {lset reg 2 $val}
+ }
+ }
+
+ lappend xml_tmp $reg
+ }
+ }
+ }
+
+ ## Data XML parser handler for method hibernate_resume
+ # @parm String arg1 - content of the element
+ # @return void
+ public method hibernate_xml_parser_data {arg1} {
+ if {$hib_abort} {
+ $parser free
+ return
+ }
+
+ # Take data only if they were expected
+ if {!$take_data} {return}
+ set take_data 0
+
+ switch -- $current_element {
+ {iram} { ;# Internal data memory in decimal
+ for {set i 0} {$i < [lindex [$this cget -procData] 3]} {incr i} {
+ $this setDataDEC $i [lindex $arg1 $i]
+ }
+ incr hib_progress_d
+ }
+ {eram} { ;# Expanded data memory in decimal
+ for {set i 0} {$i < [lindex [$this cget -procData] 8]} {incr i} {
+ $this setEramDEC $i [lindex $arg1 $i]
+ }
+ incr hib_progress_d
+ }
+ {xram} { ;# External data memory in decimal
+ set addr 0
+ for {set m 0} {$m < 8} {incr m} {
+ for {set k 0} {$addr < $xdata_size && $k < 4096} {incr k} {
+ $this setXdataDEC $addr [lindex $arg1 $addr]
+ incr addr
+
+ if {$hib_abort} {
+ hibernate_close_progress_dialog
+ return 1
+ }
+ }
+ incr hib_progress_d
+ update
+ }
+ }
+ {eeprom} { ;# Data EEPROM in decimal
+ set addr 0
+ for {set m 0} {$m < 8} {incr m} {
+ for {set k 0} {$addr < $eeprom_size && $k < 4096} {incr k} {
+ $this setEepromDEC $addr [lindex $arg1 $addr]
+ incr addr
+
+ if {$hib_abort} {
+ hibernate_close_progress_dialog
+ return 1
+ }
+ }
+ incr hib_progress_d
+ update
+ }
+ }
+ {addresses} { ;# SFR decimal addresses in the same order as in tag values
+ set xml_tmp $arg1
+ }
+ {values} { ;# SFR decimal values in the same order as in tag values
+ foreach addr $xml_tmp val $arg1 {
+ $this setSfr_directly $addr $val
+ }
+ set xml_tmp {}
+ }
+ {special} { ;# Special engine variables
+ $this simulator_set_special $arg1
+ }
+ {spec} { ;# Special engine variables for stepback funtion
+ $this simulator_hib_append_SB_spec $arg1
+
+ incr counter
+ if {!($counter % 10)} {
+ incr hib_progress_s
+ update
+ }
+ }
+ }
+ }
+
+ ## Check if the current hibernation file is usable and invoke dialog to configure simulator engine
+ # @return void
+ private method check_file_usability {} {
+ # Determinate full name of source file and its MD5 hash
+ set sourcefile [list \
+ [$this cget -projectPath] \
+ [$this cget -P_option_main_file] \
+ ]
+ if {[lindex $sourcefile 1] == {}} {
+ set sourcefile [$this editor_procedure {} getFileName {}]
+ }
+ set sourcefile_md5 {}
+ catch {
+ set sourcefile_md5 [::md5::md5 -hex -file \
+ [file join [lindex $sourcefile 0] [lindex $sourcefile 1]]]
+ }
+
+ ## Determinate list of differencies
+ set differences [list 0 0 0 0]
+ if {[lindex $xml_tmp 2] != [lindex $sourcefile 1]} {
+ lset differences 0 1
+ }
+ if {[lindex $xml_tmp 3] != [$this cget -P_option_mcu_type]} {
+ lset differences 1 1
+ }
+ if {[lindex $xml_tmp 4] != [$this cget -P_option_mcu_xdata]} {
+ lset differences 2 1
+ }
+ if {[lindex $xml_tmp 6] != $sourcefile_md5} {
+ lset differences 3 1
+ }
+
+ # If there are some differencies -> invoke dialog
+ foreach bool $differences {
+ if {$bool} {
+ if {[ask_user_what_to_do $differences]} {
+ set hib_abort 1
+ }
+ break
+ }
+ }
+ }
+
+ ## Invoke dialog showing differencies between the hibernation file and engine configuration
+ # @parm List differences -
+ # @return Bool - 1 == abort process; 0 == keep alive
+ private method ask_user_what_to_do {differences} {
+ # Set NS variables
+ set file_variable 1
+ set mcu_variable 1
+ set xdata_variable 1
+ set md5_variable 1
+
+ set win [toplevel .hibernation_bad_file_dialog -class {Error dialog} -bg {#EEEEEE}]
+ set dlg_result 1
+ set dlg_bits $differences
+
+ # Create dialog header
+ pack [label $win.header_label \
+ -font $text_font \
+ -text [mc "The following problems must be \nresolved before program resumption"] \
+ ] -fill x -padx 10 -pady 5
+
+ # Create main frame
+ set main_frame [frame $win.main_frame]
+
+ # MCU is different
+ set num 0
+ if {[lindex $differences 1]} {
+ incr num
+ set frame [dialog_create_item $num $main_frame [mc "This file is indented for %s but the current MCU is %s" [lindex $xml_tmp 3] [$this cget -P_option_mcu_type]]]
+ pack [checkbutton $frame.chbut \
+ -text [mc "Set current MCU to %s" [lindex $xml_tmp 3]] \
+ -variable ::Hibernate::mcu_variable \
+ -command "$this hibernation_chbut_rabut_command" \
+ ] -anchor w
+ }
+ # XDATA is different
+ if {[lindex $differences 2]} {
+ incr num
+ set frame [dialog_create_item $num $main_frame [mc "This file contains %s B of external data memory but but your processor has %s B" [lindex $xml_tmp 4] [$this cget -P_option_mcu_xdata]]]
+ pack [radiobutton $frame.rabut0 \
+ -text [mc "Set current XDATA capacity to %s B" [lindex $xml_tmp 4]] \
+ -variable ::Hibernate::xdata_variable -value 1 \
+ -command "$this hibernation_chbut_rabut_command" \
+ ] -anchor w
+ pack [radiobutton $frame.rabut1 \
+ -text [mc "Ignore this difference"] \
+ -variable ::Hibernate::xdata_variable -value 2 \
+ -command "$this hibernation_chbut_rabut_command" \
+ ] -anchor w
+ }
+ # MD5 is different
+ if {[lindex $differences 3]} {
+ incr num
+ set frame [dialog_create_item $num $main_frame [mc "Current file (%s) has different MD5 hash than MD5 recorded in this hibernation file" [lindex [$this editor_procedure {} getFileName {}] 1]]]
+ pack [checkbutton $frame.chbut \
+ -text [mc "Ignore this difference"] \
+ -variable ::Hibernate::md5_variable \
+ -command "$this hibernation_chbut_rabut_command" \
+ ] -anchor w
+ }
+ # Filename is different
+ if {[lindex $differences 0]} {
+ incr num
+ set frame [dialog_create_item $num $main_frame [mc "This hibernation file was generated from \"%s\" but current file is \"%s\"" [lindex $xml_tmp 2] [lindex [$this editor_procedure {} getFileName {}] 1]]]
+ pack [checkbutton $frame.chbut \
+ -text [mc "Ignore this difference"] \
+ -variable ::Hibernate::file_variable \
+ -command "$this hibernation_chbut_rabut_command" \
+ ] -anchor w
+ }
+
+ pack $main_frame -fill both -expand 1
+
+ # Create buttons "Ok" and "Cancel"
+ set button_frame [frame $win.button_frame]
+ set dlg_ok_but [ttk::button $button_frame.button_ok \
+ -text [mc "Ok"] \
+ -command "$this hibernation_cls_dlg 0" \
+ -compound left \
+ -image ::ICONS::16::ok \
+ ]
+ pack $dlg_ok_but -side left
+ pack [ttk::button $button_frame.button_cancel \
+ -text [mc "Cancel"] \
+ -command "$this hibernation_cls_dlg 1" \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ ] -side left
+ pack $button_frame -side bottom -anchor e -padx 10 -pady 5
+
+ # Configure dialog window
+ wm iconphoto $win ::ICONS::16::resume
+ wm title $win [mc "Program resumption"]
+ wm minsize $win 480 200
+ wm protocol $win WM_DELETE_WINDOW "
+ grab release $win
+ destroy $win"
+ wm transient $win .hibernation_progress_dialog
+
+ update
+ catch {
+ grab $win
+ raise $win
+ }
+ focus -force $dlg_ok_but
+ tkwait window $win
+ return $dlg_result
+ }
+
+ ## Create one item in dialog generated by proc. ask_user_what_to_do
+ # @parm Int number - Item number
+ # @parm Widget mainframe - Frame where to pack this item
+ # @parm String text - Item text
+ # @return Widget - Frame "Options:"
+ private method dialog_create_item {number mainframe text} {
+ # Create horizontal separator
+ pack [ttk::separator $mainframe.sep_${number} \
+ -orient horizontal \
+ ] -fill x -pady 7 -expand 1 -padx 5
+
+ # Create label with number
+ set local_frame [frame $mainframe.frame_${number}]
+ pack [label $local_frame.lbl \
+ -font $big_font -text "${number}." \
+ ] -side left -anchor n -padx 3
+ set right_frame [frame $local_frame.right]
+
+ # Create text widget for the given message
+ set text_wdg [text $right_frame.top_text \
+ -width 0 -height 3 -wrap word -bd 0 \
+ -relief flat -bg {#EEEEEE} \
+ -font $text_font -cursor left_ptr \
+ ]
+ $text_wdg insert end $text
+ $text_wdg configure -state disabled
+ pack $text_wdg -fill both -expand 1 -pady 3
+
+ # Create frame "Options:"
+ pack [label $right_frame.opt_lbl -text [mc "Options:"]] -anchor w -padx 10
+ set options_frame [frame $right_frame.options]
+
+ # Pack parts of this item and return frame "Options:"
+ pack $options_frame -padx 35 -anchor w
+ pack $right_frame -side left -fill both -expand 1
+ pack $local_frame -fill both -expand 1 -padx 10
+ return $options_frame
+ }
+
+ ## Command for checkbuttons and radiobuttons in options frame
+ # Enables / disables Ok button
+ # @return void
+ public method hibernation_chbut_rabut_command {} {
+ if {$file_variable && $mcu_variable && $xdata_variable && $md5_variable} {
+ $dlg_ok_but configure -state normal
+ } {
+ $dlg_ok_but configure -state disabled
+ }
+ }
+
+ ## Close dialog with some result
+ # @parm Mixed new_result - Dialog result
+ # @return void
+ public method hibernation_cls_dlg {new_result} {
+ if {!$new_result} {
+ # Adjust processor type
+ if {[lindex $dlg_bits 1]} {
+ ::X::change_processor [lindex $xml_tmp 3]
+ }
+
+ # Adjust size of external data memory
+ if {[lindex $dlg_bits 2]} {
+ # Set new value
+ if {$xdata_variable == 1} {
+ if {[lindex [$this cget -procData] 0] == {yes}} {
+ $this configure -P_option_mcu_xdata $xdata_size
+ ::X::close_hexedit xdata $this
+ $this simulator_resize_xdata_memory $xdata_size
+ } {
+ set xdata_size 0
+ }
+
+ # Ignore
+ } elseif {$xdata_variable == 2} {
+ set xdata_size [$this cget -P_option_mcu_xdata]
+ }
+ }
+ }
+
+ # Set dialog result and destroy it
+ set dlg_result $new_result
+
+ catch {
+ grab release .hibernation_bad_file_dialog
+ }
+ catch {
+ destroy .hibernation_bad_file_dialog
+ }
+ }
+}
diff --git a/lib/simulator/interruptmonitor.tcl b/lib/simulator/interruptmonitor.tcl
new file mode 100755
index 0000000..5156382
--- /dev/null
+++ b/lib/simulator/interruptmonitor.tcl
@@ -0,0 +1,1246 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements interrupt monitor
+# --------------------------------------------------------------------------
+
+class InterruptMonitor {
+ ## COMMON
+ common geometry ${::CONFIG(INTR_MON_GEOMETRY)} ;# Last window geometry
+ common count 0 ;# Counter of intances
+ common bg_color {#0088FF} ;# Color for highlighted background
+ # Small header font
+ common header_font [font create \
+ -size -17 -weight bold \
+ -family {helvetica} \
+ ]
+ # Big header font
+ common header_font_big [font create \
+ -size -21 -weight bold \
+ -family {helvetica} \
+ ]
+ # Common label font
+ common lbl_font [font create \
+ -size -12 \
+ -family {helvetica} \
+ ]
+ # Font for value labels
+ common val_font [font create \
+ -size -12 -weight bold \
+ -family {helvetica} \
+ ]
+ # Font for value labels - underline
+ common val_font_under [font create \
+ -size -12 -weight bold \
+ -family {helvetica} \
+ -underline 1 \
+ ]
+
+
+ ## PRIVATE
+ private variable dialog_opened 0 ;# Bool: Dialog window opened
+ private variable win ;# Widget: Dialog window
+ private variable in_progress_frame ;# Widget: Scrollable frame area for interrupts in progress
+ private variable pending_frame ;# Widget: Scrollable frame area for pending interrupts
+ private variable priorities_frame ;# Widget: Scrollable frame area for interrupt priorities
+ private variable in_progress_frame_f ;# Widget: Scrollable frame for interrupts which are in progress
+ private variable pending_frame_f ;# Widget: Scrollable frame for pending interrupts
+ private variable priorities_frame_f ;# Widget: Scrollable frame for interrupt priorities
+ private variable status_bar ;# Widget: Dialog status bar label
+
+ private variable in_progress_wdg {} ;# List: Interrupt sub windows for interrupts in porgress
+ private variable in_progress_flg {} ;# List: Flags of interrupts which are in progress
+ private variable intr_priorities {} ;# List: Interrupt flags in order of their priorities (decremental)
+ private variable pending_flg {} ;# List: Flags of pending interrupts
+ private variable avaliable_interrs {} ;# List: Avaliable interrupt flags
+ private variable maximum_priority 0 ;# Int: Maximum valid priority
+
+
+ constructor {} {
+ # Configure specific ttk styles
+ ttk::style configure InterruptMonitor_Flat.TButton \
+ -background $bg_color \
+ -padding 0 \
+ -borderwidth 1 \
+ -relief flat
+ ttk::style map InterruptMonitor_Flat.TButton \
+ -relief [list active raised] \
+ -background [list disabled $bg_color active $bg_color]
+ }
+
+ destructor {
+ }
+
+ ## Close interrupt monitor window and free its resources
+ # @return void
+ public method interrupt_monitor_close {} {
+ if {!$dialog_opened} {
+ return
+ }
+
+ set geometry [wm geometry $win]
+ set dialog_opened 0
+ set in_progress_wdg {}
+ set in_progress_flg {}
+ set pending_flg {}
+ set intr_priorities {}
+ set avaliable_interrs {}
+
+ if {[winfo exists $win]} {
+ destroy $win
+ }
+ }
+
+ ## Invoke interrupt monitor window
+ # @return void
+ public method interrupt_monitor_invoke_dialog {} {
+ if {$dialog_opened} {return}
+ set dialog_opened 1
+
+ # Create dialog window, main frame and status bar
+ set win [toplevel .interrupt_monitor$count -class {Interrupt monitor} -bg {#EEEEEE}]
+ incr count
+ set main_frame [frame $win.main_frame]
+ set status_bar [label $win.status_bar]
+
+ # Create scrollable frames
+ set in_progress_frame_f [ScrollableFrame $main_frame.in_p \
+ -width 300 -areawidth 300 \
+ -yscrollcommand "$main_frame.in_p_scrl set" \
+ ]
+ set pending_frame_f [ScrollableFrame $main_frame.pending \
+ -width 230 -areawidth 230 \
+ -yscrollcommand "$main_frame.pend_scrl set" \
+ ]
+ set priorities_frame_f [ScrollableFrame $main_frame.prior \
+ -width 230 -areawidth 230 \
+ -yscrollcommand "$main_frame.prior_scrl set" \
+ ]
+
+ # Create headers for scrollable frames
+ set top_frame_0 [frame $main_frame.top_frame_0]
+ set top_frame_1 [frame $main_frame.top_frame_1]
+ set top_frame_2 [frame $main_frame.top_frame_2]
+ foreach num {0 1 2} text {
+ {Interrupts in progress}
+ {Pending interrupts}
+ {Interrupt priorities}
+ } {
+ set frame [subst "\$top_frame_${num}"]
+ pack [ttk::button $frame.expand \
+ -image ::ICONS::16::add \
+ -style Flat.TButton \
+ -command "$this interrupt_monitor_expand $num" \
+ ] -side left -anchor w -padx 3
+ set_status_tip $frame.expand [mc "Expand all"]
+ pack [ttk::button $frame.collapse \
+ -image ::ICONS::16::sub \
+ -style Flat.TButton \
+ -command "$this interrupt_monitor_collapse $num" \
+ ] -side left -anchor w
+ set_status_tip $frame.collapse [mc "Collapse all"]
+ pack [label $frame.in_p_lbl \
+ -font $header_font \
+ -text $text \
+ ] -side left -fill x -expand 1
+ }
+
+ # Show headers for scrollable frames
+ grid $top_frame_0 -row 0 -column 0 -columnspan 2 -sticky we -padx 5
+ grid $top_frame_1 -row 0 -column 3 -columnspan 2 -sticky we -padx 5
+ grid $top_frame_2 -row 0 -column 6 -columnspan 2 -sticky we -padx 5
+
+ # Crate and show scrollbars
+ grid [ttk::scrollbar $main_frame.in_p_scrl \
+ -orient vertical \
+ -command "$in_progress_frame_f yview" \
+ ] -row 1 -column 1 -sticky ns
+ grid [ttk::scrollbar $main_frame.pend_scrl \
+ -orient vertical \
+ -command "$pending_frame_f yview" \
+ ] -row 1 -column 4 -sticky ns
+ grid [ttk::scrollbar $main_frame.prior_scrl \
+ -orient vertical \
+ -command "$priorities_frame_f yview" \
+ ] -row 1 -column 7 -sticky ns
+
+ # Show scrollable frames
+ grid $in_progress_frame_f -sticky ns -padx 3 -row 1 -column 0
+ grid $pending_frame_f -sticky ns -padx 3 -row 1 -column 3
+ grid $priorities_frame_f -sticky ns -padx 3 -row 1 -column 6
+ grid rowconfigure $main_frame 1 -weight 1
+
+ # Set spaces between scrollable frames
+ grid columnconfigure $main_frame 2 -minsize 2
+ grid columnconfigure $main_frame 5 -minsize 2
+
+ # Set container frames fro scrollable frames
+ set in_progress_frame [$in_progress_frame_f getframe]
+ set pending_frame [$pending_frame_f getframe]
+ set priorities_frame [$priorities_frame_f getframe]
+
+ # Fill GUI
+ set maximum_priority [$this simulator_get_max_intr_priority]
+ interrupt_monitor_set_avaliable [$this simulator_get_intr_flags]
+ interrupt_monitor_reevaluate
+
+ # Pack main frame and create bottom frame
+ pack $main_frame -fill both -expand 1
+ pack [ttk::separator $win.sep -orient horizontal] \
+ -fill x -pady 3
+ pack $status_bar -side left -fill x -padx 10
+ pack [ttk::button $win.close_but \
+ -text [mc "Close"] \
+ -compound left \
+ -command "$this interrupt_monitor_close" \
+ -image ::ICONS::16::button_cancel \
+ ] -side right -pady 5 -padx 10
+ set_status_tip $win.close_but {Close this dialog window}
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::kcmdf
+ wm title $win "[mc {Interrupt monitor}] - [string trim $this {:}] - MCU 8051 IDE"
+ wm minsize $win 840 270
+ if {$geometry != {}} {
+ wm geometry $win $geometry
+ }
+ wm resizable $win 0 1
+ wm protocol $win WM_DELETE_WINDOW "$this interrupt_monitor_close"
+ bindtags $win [list $win Toplevel all .]
+ }
+
+ ## Return true if this dialog is opened
+ # @return Bool result
+ public method interrupt_monitor_is_opened {} {
+ return $dialog_opened
+ }
+
+ ## Reevaluate content of the monitor
+ # @return void
+ public method interrupt_monitor_reevaluate {} {
+ if {!$dialog_opened} {return}
+
+ # Remove interrupts in progress
+ foreach widget $in_progress_wdg {
+ destroy $widget
+ }
+ set in_progress_flg {}
+ set in_progress_wdg {}
+
+ # Priorities
+ interrupt_monitor_intr_prior [$this simulator_get_intr_flags_with_priorities]
+ # Pending interrupts
+ interrupt_monitor_intr_flags [$this simulator_get_active_intr_flags]
+
+ # Enable/Disabled buttons "Invoke this interrupt"
+ set state [expr {([$this is_frozen]) ? "normal" : "disabled"}]
+ foreach flag $avaliable_interrs {
+ $priorities_frame.[string tolower $flag].secondary.exec_but configure -state $state
+ }
+
+ # Evaluate list of active interrupts
+ set intrs [$this simulator_get_interrupts_in_progress]
+ for {set i [expr {[llength $intrs] - 1}]} {$i >= 0} {incr i -1} {
+ interrupt_monitor_intr [lindex $intrs $i]
+ $priorities_frame.[string tolower [lindex $intrs $i]].secondary.exec_but \
+ configure -state disabled
+ }
+ }
+
+ ## Set status bar tip for certain widget
+ # @parm Widget widget - Some button or label ...
+ # @parm String text - Status tip
+ # @return void
+ private method set_status_tip {widget text} {
+ bind $widget <Enter> "$status_bar configure -text {$text}"
+ bind $widget <Leave> "$status_bar configure -text {}"
+ }
+
+ ## Clear content of frames "Interrupts in progress" and "Pending iterrupts"
+ # @return void
+ public method interrupt_monitor_reset {} {
+ if {!$dialog_opened} {return}
+ foreach wdg [pack slaves $pending_frame] {
+ destroy $wdg
+ }
+ foreach wdg [pack slaves $in_progress_frame] {
+ destroy $wdg
+ }
+ set in_progress_wdg {}
+ set in_progress_flg {}
+ set pending_flg {}
+ set intr_priorities $avaliable_interrs
+ foreach flag $avaliable_interrs {
+ set flag [string tolower $flag]
+ $priorities_frame.$flag.secondary.exec_but configure -state normal
+ }
+ }
+
+ ## Expand all in scrollable frame specifie by the given number
+ # @parm Int num - 0 == "In progress"; 1 == "Pending"; 2 == "Priorities"
+ # @return void
+ public method interrupt_monitor_expand {num} {
+ switch -- $num {
+ {0} {set frame $in_progress_frame}
+ {1} {set frame $pending_frame}
+ {2} {set frame $priorities_frame}
+ }
+
+ foreach sub_frame [pack slaves $frame] {
+ if {![winfo ismapped $sub_frame.tertiary]} {
+ pack $sub_frame.tertiary -fill both -padx 2 -pady 2
+ }
+ }
+
+ update
+ }
+
+ ## Collapse all in scrollable frame specifie by the given number
+ # @parm Int num - 0 == "In progress"; 1 == "Pending"; 2 == "Priorities"
+ # @return void
+ public method interrupt_monitor_collapse {num} {
+ switch -- $num {
+ {0} {set frame $in_progress_frame}
+ {1} {set frame $pending_frame}
+ {2} {set frame $priorities_frame}
+ }
+
+ foreach sub_frame [pack slaves $frame] {
+ if {[winfo ismapped $sub_frame.tertiary]} {
+ pack forget $sub_frame.tertiary
+ }
+ }
+
+ update
+ }
+
+ ## Collapse / Expand sub window (interrupt details)
+ # @parm Widget widget - Details frame
+ # @return void
+ public method interrupt_monitor_collapse_expand {widget} {
+ if {[winfo ismapped $widget]} {
+ pack forget $widget
+ } {
+ pack $widget -fill both -padx 2 -pady 2
+ }
+ update
+ }
+
+ ## Set avaliable interrupt flags
+ # @parm List flags - Interrupt flags (e.g. {TF2 CF RI IE0})
+ # @return void
+ private method interrupt_monitor_set_avaliable {flags} {
+ # Set avaliable interrupts
+ set avaliable_interrs $flags
+
+ # Create sub windows in frame "Priorities"
+ foreach flag_bit $flags {
+ # Get interrupt details
+ set intr [get_interrupt_details $flag_bit]
+
+ # Create frame for header and details
+ set primary_frame [frame $priorities_frame.[string tolower $flag_bit] -bg $bg_color]
+
+ ## Create header
+ set secondary_frame [frame $primary_frame.secondary -bg $bg_color]
+ # Priority value
+ pack [label $secondary_frame.priority_val \
+ -pady 0 -font $val_font \
+ ] -side left -padx 7 -anchor w
+ set_status_tip $secondary_frame.priority_val [mc "Priority level"]
+ # Header label
+ pack [label $secondary_frame.name \
+ -text [lindex $intr 3] -pady 0 \
+ -bg $bg_color -fg white \
+ -cursor hand1 -anchor w \
+ ] -side left -anchor w -fill x -expand 1
+ bind $secondary_frame.name <Button-1> \
+ "$this interrupt_monitor_collapse_expand $primary_frame.tertiary"
+ # Button "Increase priority level"
+ pack [ttk::button $secondary_frame.up_but \
+ -image ::ICONS::16::up \
+ -style InterruptMonitor_Flat.TButton \
+ -command "$this simulator_incr_intr_priority $flag_bit" \
+ ] -side right -anchor e
+ set_status_tip $secondary_frame.up_but [mc "Increase priority level"]
+ # Button "Decrease priority level"
+ pack [ttk::button $secondary_frame.down_but \
+ -image ::ICONS::16::down \
+ -style InterruptMonitor_Flat.TButton \
+ -command "$this simulator_decr_intr_priority $flag_bit" \
+ ] -side right -anchor e
+ set_status_tip $secondary_frame.down_but [mc "Decrease priority level"]
+ # Button "Invoke interrupt"
+ pack [ttk::button $secondary_frame.exec_but \
+ -image ::ICONS::16::launch \
+ -style InterruptMonitor_Flat.TButton \
+ -command "$this simulator_invoke_interrupt $flag_bit" \
+ ] -side right -anchor e -padx 7
+ set_status_tip $secondary_frame.exec_but [mc "Invoke this interrupt"]
+
+ # Create details frame
+ set tertiary_frame [frame $primary_frame.tertiary -bg {#FFFFFF}]
+ set row 2
+ set col 0
+ set pri_bits [lindex $intr 2]
+ if {[$this get_feature_avaliable iph]} {
+ set pri_bits [linsert $pri_bits 0 "[lindex $intr 2]H"]
+ }
+ foreach lbl {
+ {Vector:} {Enable bit:}
+ {Flag bit:} {Priority bits:}
+ } \
+ val [list \
+ [lindex $intr 0] [lindex $intr 1] \
+ $flag_bit $pri_bits \
+ ] \
+ type {
+ vector e_bit
+ f_bit p_bit
+ } \
+ {
+ # Label describing type of flags
+ grid [label $tertiary_frame.lbl_${row}_${col} \
+ -text [mc $lbl] \
+ -bg white -font $lbl_font -pady 0 \
+ ] -sticky w -row $row -column $col -pady 0
+ incr col
+
+ # Create frame for labels representing bits themselfes
+ set bits_frame [frame $tertiary_frame.$type -bg white]
+ grid $bits_frame -sticky we -row $row -column $col -pady 0
+
+ # Create bits (or possibly other type of labels)
+ switch -- $type {
+ vector {
+ set cursor {left_ptr}
+ set is_bit 0
+ }
+ e_bit -
+ p_bit -
+ f_bit {
+ set cursor {hand1}
+ set is_bit 1
+ }
+ }
+ set bit_i 0
+ foreach bit $val {
+ # Create label containing "," (comma)
+ if {$bit_i} {
+ pack [label $bits_frame.comma_lbl_$bit_i\
+ -bg white -font $val_font \
+ -text {,} -padx 0 -pady 0 \
+ ] -side left -padx 0 -anchor w -ipadx 0
+ }
+
+ # Determinate initial bit color
+ if {$is_bit == 0} {
+ set color {black}
+ } elseif {[intr_mon_getBit $bit]} {
+ set color $::Simulator_GUI::on_color
+ } else {
+ set color $::Simulator_GUI::off_color
+ }
+
+ # Create bit label
+ set label [label $bits_frame.val_$bit \
+ -bg white -font $val_font \
+ -cursor $cursor -padx 0 \
+ -fg $color -text $bit -pady 0 \
+ ]
+ pack $label -pady 0 -side left -padx 0 -ipadx 0 -anchor w
+
+ # Set event bindings for bit label
+ if {$is_bit} {
+ bind $label <Button-1> "$this interrupt_monitor_invert_bit $bit"
+ set_status_tip $label [mc [get_bit_stip $bit]]
+ bind $label <Enter> {+%W configure -font $::InterruptMonitor::val_font_under}
+ bind $label <Leave> {+%W configure -font $::InterruptMonitor::val_font}
+ }
+ incr bit_i
+ }
+
+ incr col 2
+ if {$col > 3} {
+ set col 0
+ incr row
+ }
+ }
+
+ # Finalize
+ grid columnconfigure $tertiary_frame 2 -weight 1
+ pack $secondary_frame -fill x
+ }
+ scrolling_bindings $priorities_frame_f $priorities_frame 1
+ }
+
+ ## Change interrupt priorities
+ # @parm List flags - List of intr. flags in order of their priorities (decremental)
+ # @return void
+ public method interrupt_monitor_intr_prior {flags} {
+ if {!$dialog_opened} {return}
+ set intr_priorities $flags
+
+ # Forget current subwindows
+ foreach wdg [pack slaves $priorities_frame] {
+ pack forget $wdg
+ }
+
+ # Show subwindows in new order
+ foreach flag_bit [string tolower $flags] {
+ pack $priorities_frame.$flag_bit -pady 2 -fill x
+ }
+
+ # Adjust value of priority level in each subwindow
+ foreach flag_bit $avaliable_interrs {
+ set pri__clr [get_priority_and_color $flag_bit]
+ set pri_bits [lindex [get_interrupt_details $flag_bit] 2]
+ set flag_bit [string tolower $flag_bit]
+ if {[$this get_feature_avaliable iph]} {
+ lappend pri_bits "${pri_bits}H"
+ }
+
+
+ # Frame: "Interrupt priorities"
+ $priorities_frame.$flag_bit.secondary.priority_val \
+ configure -text [lindex $pri__clr 0] -bg [lindex $pri__clr 1]
+ if {[lindex $pri__clr 0] == $maximum_priority} {
+ $priorities_frame.$flag_bit.secondary.up_but \
+ configure -state disabled
+ } {
+ $priorities_frame.$flag_bit.secondary.up_but \
+ configure -state normal
+ }
+ if {[lindex $pri__clr 0]} {
+ $priorities_frame.$flag_bit.secondary.down_but \
+ configure -state normal
+ } {
+ $priorities_frame.$flag_bit.secondary.down_but \
+ configure -state disabled
+ }
+ # Pending interrupts
+ if {[winfo exists $pending_frame.$flag_bit]} {
+ $pending_frame.$flag_bit.tertiary.priority_val \
+ configure -text [lindex $pri__clr 0] -bg [lindex $pri__clr 1]
+ }
+ # Interrupts in progress
+ if {[winfo exists $in_progress_frame.$flag_bit]} {
+ $in_progress_frame.$flag_bit.tertiary.priority_val \
+ configure -text [lindex $pri__clr 0] -bg [lindex $pri__clr 1]
+ }
+
+ # Adjust colors of priority bits
+ foreach pri_bit $pri_bits {
+ # Determinate new color
+ if {[intr_mon_getBit $pri_bit]} {
+ set color $::Simulator_GUI::on_color
+ } {
+ set color $::Simulator_GUI::off_color
+ }
+
+ # Set new color
+ foreach widget [list \
+ $priorities_frame.$flag_bit.tertiary.p_bit.val_$pri_bit \
+ $pending_frame.$flag_bit.tertiary.p_bit.val_$pri_bit \
+ $in_progress_frame.$flag_bit.tertiary.p_bit.val_$pri_bit\
+ ] {
+ if {[winfo exists $widget]} {
+ $widget configure -fg $color
+ }
+ }
+ }
+ }
+ }
+
+ ## Set new pending interrupts
+ # @parm List flags - List of intr. flags in decremental order of their priorities
+ # @return void
+ public method interrupt_monitor_intr_flags {flags} {
+ if {!$dialog_opened} {return}
+
+ # Remove subwindows of interrupts which does not longer
+ #+ belong to category pending interrupts
+ foreach flag $pending_flg {
+ if {[lsearch $flags $flag] == -1 || [lsearch $in_progress_flg $flag] != -1} {
+ destroy $pending_frame.[string tolower $flag]
+ }
+ }
+
+ # Remove flags which are in category "In progress" already
+ set new_flag {}
+ foreach flag $flags {
+ if {[lsearch $in_progress_flg $flag] == -1} {
+ lappend new_flag $flag
+ }
+ }
+ set flags $new_flag
+
+ # Sort flags by priority
+ set new_flag {}
+ foreach priority_flag $intr_priorities {
+ if {[lsearch $flags $priority_flag] != -1} {
+ lappend new_flag $priority_flag
+ }
+ }
+ set pending_flg $new_flag
+
+ # Forget or create subwindows for current set of pending interrupts
+ foreach flag $new_flag {
+ if {[winfo exists $pending_frame.[string tolower $flag]]} {
+ pack forget $pending_frame.[string tolower $flag]
+ } {
+ create_pending_interrupt $flag
+ }
+ }
+
+ # Show new subwindows in order of intr. priorities
+ foreach flag $new_flag {
+ set pri__clr [get_priority_and_color $flag]
+
+ set flag [string tolower $flag]
+ $pending_frame.$flag.tertiary.priority_val configure \
+ -text [lindex $pri__clr 0] -bg [lindex $pri__clr 1]
+ pack $pending_frame.$flag -pady 2 -fill x
+ }
+
+ # Adjust colors of flag bits
+ foreach flag_bit $avaliable_interrs {
+ # Determinate new color
+ if {[intr_mon_getBit $flag_bit]} {
+ set color $::Simulator_GUI::on_color
+ } {
+ set color $::Simulator_GUI::off_color
+ }
+ set flag [string tolower $flag_bit]
+
+ # Set new color
+ foreach widget [list \
+ $priorities_frame.$flag.tertiary.f_bit.val_$flag_bit \
+ $pending_frame.$flag.tertiary.f_bit.val_$flag_bit \
+ $in_progress_frame.$flag.tertiary.f_bit.val_$flag_bit \
+ ] {
+ if {[winfo exists $widget]} {
+ $widget configure -fg $color
+ }
+ }
+ }
+ }
+
+ ## Reevaluate state of interrupt enable bits
+ # @return void
+ public method interrupt_monitor_intr_ena_dis {} {
+ if {!$dialog_opened} {return}
+
+ # Adjust colors of flag bits
+ foreach flag_bit $avaliable_interrs {
+ set ena_bit [lindex [get_interrupt_details $flag_bit] 1]
+
+ # Determinate new color
+ if {[intr_mon_getBit $ena_bit]} {
+ set color $::Simulator_GUI::on_color
+ } {
+ set color $::Simulator_GUI::off_color
+ }
+
+ set flag_bit [string tolower $flag_bit]
+
+ # Set new color
+ foreach widget [list \
+ $priorities_frame.$flag_bit.tertiary.e_bit.val_$ena_bit \
+ $pending_frame.$flag_bit.tertiary.e_bit.val_$ena_bit \
+ $in_progress_frame.$flag_bit.tertiary.e_bit.val_$ena_bit\
+ ] {
+ if {[winfo exists $widget]} {
+ $widget configure -fg $color
+ }
+ }
+ }
+ }
+
+ ## Get priority level and color for the given interrupt
+ # @parm String flag - Interrupt flag (e.g. RI)
+ # @return List - {priority color}
+ private method get_priority_and_color {flag} {
+ set priority [$this simulator_get_interrupt_priority $flag]
+ switch -- $priority {
+ 0 {set bg_clr {#00FF00}}
+ 1 {set bg_clr {#DDDD00}}
+ 2 {set bg_clr {#FF8800}}
+ 3 {set bg_clr {#FF0000}}
+ }
+ return [list $priority $bg_clr]
+ }
+
+ ## Add an interrupt to category "Pending interrupts"
+ # @parm String flag - Interrupt flag (e.g. TI)
+ # @return void
+ private method create_pending_interrupt {flag_bit} {
+ if {!$dialog_opened} {return}
+ set intr [get_interrupt_details $flag_bit]
+
+ # Create frame for header and details
+ set primary_frame [frame $pending_frame.[string tolower $flag_bit] -bg $bg_color]
+
+ ## Create subwindow header
+ set secondary_frame [frame $primary_frame.secondary -bg $bg_color]
+ # Label with interrupt name
+ pack [label $secondary_frame.name \
+ -text [lindex $intr 3] -pady 0 \
+ -bg $bg_color -fg white \
+ -cursor hand1 -anchor w \
+ ] -side left -anchor w -fill x -padx 3 -expand 1
+ bind $secondary_frame.name <Button-1> \
+ "$this interrupt_monitor_collapse_expand $primary_frame.tertiary"
+ # Close button
+ pack [ttk::button $secondary_frame.close_but \
+ -style InterruptMonitor_Flat.TButton \
+ -image ::ICONS::16::button_cancel \
+ -command "$this simulator_clear_intr_flag $flag_bit" \
+ ] -side right -anchor e -padx 3
+ set_status_tip $secondary_frame.close_but {Clear interrupt flag}
+
+ ## Create frame for interrupt details
+ set tertiary_frame [frame $primary_frame.tertiary -bg {#FFFFFF}]
+ # Priority:
+ grid [label $tertiary_frame.priority_lbl \
+ -pady 0 -text "Priority:" \
+ -bg white -font $lbl_font \
+ ] -sticky w -pady 0 -row 0 -column 0
+ set pri__clr [get_priority_and_color $flag_bit]
+ grid [label $tertiary_frame.priority_val \
+ -pady 0 -font $val_font \
+ -text [lindex $pri__clr 0] \
+ -bg [lindex $pri__clr 1] \
+ ] -sticky w -pady 0 -row 0 -column 1
+ set_status_tip $tertiary_frame.priority_val {Priority level}
+ # (Separator)
+ grid [ttk::separator $tertiary_frame.sep -orient horizontal] \
+ -sticky we -row 1 -column 0 -columnspan 5 -pady 0
+ # Vector, Enable bit, Flag bit, Priority bits
+ set row 2
+ set col 0
+ set pri_bits [lindex $intr 2]
+ if {[$this get_feature_avaliable iph]} {
+ set pri_bits [linsert $pri_bits 0 "[lindex $intr 2]H"]
+ }
+ foreach lbl {
+ {Vector:} {Enable bit:}
+ {Flag bit:} {Priority bits:}
+ } \
+ val [list \
+ [lindex $intr 0] [lindex $intr 1] \
+ $flag_bit $pri_bits \
+ ] \
+ type {
+ vector e_bit
+ f_bit p_bit
+ } \
+ {
+ # Label describing type of flags
+ grid [label $tertiary_frame.lbl_${row}_${col} \
+ -text [mc $lbl] \
+ -bg white -font $lbl_font -pady 0 \
+ ] -sticky w -row $row -column $col -pady 0
+ incr col
+
+ # Create frame for labels representing bits themselfes
+ set bits_frame [frame $tertiary_frame.$type -bg white]
+ grid $bits_frame -sticky w -row $row -column $col -pady 0
+
+ # Create bits (or possibly other type of labels)
+ switch -- $type {
+ vector {
+ set cursor {left_ptr}
+ set is_bit 0
+ }
+ e_bit -
+ p_bit -
+ f_bit {
+ set cursor {hand1}
+ set is_bit 1
+ }
+ }
+ set bit_i 0
+ foreach bit $val {
+ # Create label containing "," (comma)
+ if {$bit_i} {
+ pack [label $bits_frame.comma_lbl_$bit_i\
+ -bg white -font $val_font \
+ -text {,} -padx 0 -pady 0 \
+ ] -side left -padx 0 -anchor w -ipadx 0
+ }
+
+ # Determinate initial bit color
+ if {$is_bit == 0} {
+ set color {black}
+ } elseif {[intr_mon_getBit $bit]} {
+ set color $::Simulator_GUI::on_color
+ } else {
+ set color $::Simulator_GUI::off_color
+ }
+
+ # Create bit label
+ set label [label $bits_frame.val_$bit \
+ -bg white -font $val_font -pady 0 \
+ -cursor $cursor -padx 0 -text $bit \
+ -fg $color \
+ ]
+ pack $label -pady 0 -side left -padx 0 -ipadx 0 -anchor w
+
+ # Set event bindings for bit label
+ if {$is_bit} {
+ bind $label <Button-1> "$this interrupt_monitor_invert_bit $bit"
+ set_status_tip $label [mc [get_bit_stip $bit]]
+ bind $label <Enter> {+%W configure -font $::InterruptMonitor::val_font_under}
+ bind $label <Leave> {+%W configure -font $::InterruptMonitor::val_font}
+ }
+ incr bit_i
+ }
+
+ incr col 2
+ if {$col > 3} {
+ set col 0
+ incr row
+ }
+ }
+
+ grid columnconfigure $tertiary_frame 2 -weight 1
+ pack $secondary_frame -fill x
+ scrolling_bindings $pending_frame_f $primary_frame 1
+ }
+
+ ## Add an interrupt to category "Interrupts in progress"
+ # @parm String flag - Interrupt flag (e.g. TF0)
+ # @return void
+ public method interrupt_monitor_intr {flag_bit} {
+ if {!$dialog_opened} {return}
+
+ # Local variables
+ set intr [get_interrupt_details $flag_bit]
+ set from_pc [format %X [$this getPC]]
+ set len [string length $from_pc]
+ if {$len < 4} {
+ set from_pc "[string repeat {0} [expr {4 - $len}]]$from_pc"
+ }
+ set from_pc "0x$from_pc"
+ set frame_desc [string tolower $flag_bit]
+
+ # Insure than the same subwindow does not exist already
+ if {[winfo exists $pending_frame.$frame_desc]} {
+ destroy $pending_frame.$frame_desc
+ }
+
+ # Disable button "Invoke this interrupt" in priorities frame
+ $priorities_frame.$frame_desc.secondary.exec_but configure -state disabled
+
+ # Create frame for header and details
+ set primary_frame [frame $in_progress_frame.$frame_desc -bg $bg_color]
+
+ ## Create subwindow header
+ set secondary_frame [frame $primary_frame.secondary -bg $bg_color]
+ # Label with interrupt name
+ pack [label $secondary_frame.name \
+ -text [lindex $intr 3] -pady 0 \
+ -bg $bg_color -fg white \
+ -cursor hand1 -anchor w \
+ ] -side left -anchor w -fill x -padx 3 -expand 1
+ bind $secondary_frame.name <Button-1> \
+ "$this interrupt_monitor_collapse_expand $primary_frame.tertiary"
+ # Close button
+ pack [ttk::button $secondary_frame.close_but \
+ -style InterruptMonitor_Flat.TButton \
+ -image ::ICONS::16::button_cancel \
+ -command "$this simulator_cancel_interrupt $flag_bit" \
+ ] -side right -anchor e -padx 3
+ set_status_tip $secondary_frame.close_but {Force return from this interrupt (may damage program integrity)}
+
+ ## Create frame for interrupt details
+ set tertiary_frame [frame $primary_frame.tertiary -bg {#FFFFFF}]
+ # Priority
+ grid [label $tertiary_frame.priority_lbl \
+ -pady 0 -text "Priority:" \
+ -bg white -font $lbl_font \
+ ] -sticky w -pady 0 -row 0 -column 0
+ set pri__clr [get_priority_and_color $flag_bit]
+ grid [label $tertiary_frame.priority_val \
+ -pady 0 -font $val_font \
+ -text [lindex $pri__clr 0] \
+ -bg [lindex $pri__clr 1] \
+ ] -sticky w -pady 0 -row 0 -column 1
+ set_status_tip $tertiary_frame.priority_val {Priority level}
+ # (Separator)
+ grid [ttk::separator $tertiary_frame.sep -orient horizontal] \
+ -sticky we -row 1 -column 0 -columnspan 5 -pady 0
+
+ # Vector, Flag bit, Enable bit, Priority bits
+ set row 2
+ set pri_bits [lindex $intr 2]
+ if {[$this get_feature_avaliable iph]} {
+ set pri_bits [linsert $pri_bits 0 "[lindex $intr 2]H"]
+ }
+ foreach lbl {
+ {Vector:} {Flag bit:}
+ {Enable bit:} {Priority bits:}
+ } \
+ val [list \
+ [lindex $intr 0] $flag_bit \
+ [lindex $intr 1] $pri_bits \
+ ] \
+ type {
+ vector f_bit
+ e_bit p_bit
+ } \
+ {
+ # Label describing type of flags
+ grid [label $tertiary_frame.lbl_$row \
+ -text [mc $lbl] \
+ -bg white -font $lbl_font -pady 0 \
+ ] -sticky w -row $row -column 0 -pady 0
+
+ # Create frame for labels representing bits themselfes
+ set bits_frame [frame $tertiary_frame.$type -bg white]
+ grid $bits_frame -sticky w -row $row -column 1 -pady 0
+
+ # Create bits (or possibly other type of labels)
+ switch -- $type {
+ vector {
+ set cursor {left_ptr}
+ set is_bit 0
+ }
+ e_bit -
+ p_bit -
+ f_bit {
+ set cursor {hand1}
+ set is_bit 1
+ }
+ }
+ set bit_i 0
+ foreach bit $val {
+ # Create label containing "," (comma)
+ if {$bit_i} {
+ pack [label $bits_frame.comma_lbl_$bit_i\
+ -bg white -font $val_font \
+ -text {,} -padx 0 -pady 0 \
+ ] -side left -padx 0 -anchor w -ipadx 0
+ }
+
+ # Determinate initial bit color
+ if {!$is_bit} {
+ set color {black}
+ } elseif {[intr_mon_getBit $bit]} {
+ set color $::Simulator_GUI::on_color
+ } else {
+ set color $::Simulator_GUI::off_color
+ }
+
+ # Create bit label
+ set label [label $bits_frame.val_$bit \
+ -bg white -font $val_font -pady 0 \
+ -cursor $cursor -padx 0 -text $bit \
+ -fg $color \
+ ]
+ pack $label -pady 0 -side left -padx 0 -ipadx 0 -anchor w
+
+ # Set event bindings for bit label
+ if {$is_bit} {
+ bind $label <Button-1> "$this interrupt_monitor_invert_bit $bit"
+ set_status_tip $label [mc [get_bit_stip $bit]]
+ bind $label <Enter> {+%W configure -font $::InterruptMonitor::val_font_under}
+ bind $label <Leave> {+%W configure -font $::InterruptMonitor::val_font}
+ }
+ incr bit_i
+ }
+ incr row
+ }
+ # Invoked from:
+ set row 2
+ grid [label $tertiary_frame.lbl__$row \
+ -text {Invoked from:} -pady 0 \
+ -bg white -font $lbl_font \
+ ] -sticky w -row $row -column 3 -pady 0 -columnspan 2
+ incr row
+ # PC:
+ grid [label $tertiary_frame.lbl__$row \
+ -pady 0 -text { PC:} \
+ -bg white -font $lbl_font \
+ ] -sticky w -row $row -column 3 -pady 0
+ grid [label $tertiary_frame.val__$row \
+ -pady 0 -text $from_pc \
+ -bg white -font $val_font \
+ ] -sticky w -row $row -column 4 -pady 0
+ incr row
+ # File:
+ grid [label $tertiary_frame.lbl__$row \
+ -pady 0 -text [mc { File:}] \
+ -bg white -font $lbl_font \
+ ] -sticky w -row $row -column 3 -pady 0
+ set filename [$this filelist_get_simulator_editor_obj]
+ if {$filename != {}} {
+ set filename [$filename cget -fullFileName]
+ } {
+ set filename [lindex [$this simulator_get_list_of_filenames] 0]
+ }
+ grid [label $tertiary_frame.val__$row \
+ -pady 0 -bg white -font $val_font \
+ -text [file tail $filename] \
+ ] -sticky w -row $row -column 4 -pady 0
+ incr row
+ # Line:
+ grid [label $tertiary_frame.lbl__$row \
+ -pady 0 -text [mc { Line:}] \
+ -bg white -font $lbl_font \
+ ] -sticky w -row $row -column 3 -pady 0
+ grid [label $tertiary_frame.val__$row \
+ -pady 0 -bg white -font $val_font \
+ -text [$this simulator_get_line_number] \
+ ] -sticky w -row $row -column 4 -pady 0
+
+ grid columnconfigure $tertiary_frame 4 -weight 1
+ pack $secondary_frame -fill x
+
+ # Pack the created subwindow just after the topmost subwindow in the scrollable frame
+ set wdg [lindex $in_progress_wdg end]
+ if {$wdg != {}} {
+ pack $primary_frame -fill x -before $wdg -pady 2
+ } {
+ pack $primary_frame -fill x -pady 2
+ }
+
+ # Register this subwindow for future use
+ lappend in_progress_flg $flag_bit
+ lappend in_progress_wdg $primary_frame
+
+ scrolling_bindings $in_progress_frame_f $primary_frame 1
+ }
+
+ ## Remove interrupt from category "In progress"
+ # @parm String flag_bit - Interrupt flag (e.g. TF0)
+ # @return void
+ public method interrupt_monitor_reti {flag_bit} {
+ if {!$dialog_opened} {return}
+ set idx [lsearch $in_progress_flg $flag_bit]
+ if {$idx == -1} {
+ return
+ }
+ destroy [lindex $in_progress_wdg $idx]
+ $priorities_frame.[string tolower $flag_bit].secondary.exec_but configure -state normal
+
+ set in_progress_flg [lreplace $in_progress_flg $idx $idx]
+ set in_progress_wdg [lreplace $in_progress_wdg $idx $idx]
+ }
+
+ ## Get details for the given interrupt
+ # @parm String flag_bit - Interrupt flag (e.g. EXF2)
+ # @return List - {vector_hex enable_bit priority_bit short_description}
+ private method get_interrupt_details {flag_bit} {
+ switch -- $flag_bit {
+ {IE0} {return {{0x03} {EX0} {PX0} {External Interrupt 0}}}
+ {TF0} {return {{0x0B} {ET0} {PT0} {Timer 0 Overflow}}}
+ {IE1} {return {{0x13} {EX1} {PX1} {External Interrupt 1}}}
+ {TF1} {return {{0x1B} {ET1} {PT1} {Timer 1 Overflow}}}
+ {RI} {return {{0x23} {ES} {PS} {UART receive}}}
+ {TI} {return {{0x23} {ES} {PS} {UART transmit}}}
+ {SPIF} {return {{0x23} {ES} {PS} {SPI}}}
+ {TF2} {return {{0x2B} {ET2} {PT2} {Timer 2 Overflow}}}
+ {EXF2} {return {{0x2B} {ET2} {PT2} {Timer 2 External}}}
+ {CF} {return {{0x33} {EC} {PC} {Analog comparator}}}
+ }
+ }
+
+ ## Get status tip for particular bit
+ # @param String bit_name - Name of bit
+ # @return String - Status tip
+ private method get_bit_stip {bit_name} {
+ switch -- $bit_name {
+ IE0 {return {Bit address: 0x89 -- External Interrupt 0 edge flag}}
+ TF0 {return {Bit address: 0x8D -- Timer 0 overflow flag}}
+ IE1 {return {Bit address: 0x8B -- External Interrupt 1 edge flag}}
+ TF1 {return {Bit address: 0x8F -- Timer 1 overflow flag}}
+ RI {return {Bit address: 0x98 -- Receive interrupt flag}}
+ TI {return {Bit address: 0x99 -- Transmit interrupt flag}}
+ SPIF {return {SPSR.7 -- SPI interrupt flag}}
+ TF2 {return {Bit address: 0xCF -- Timer 2 overflow flag}}
+ EXF2 {return {Bit address: 0xCE -- Timer 2 external flag}}
+ CF {return {ACSR.4 -- Comparator Interrupt}}
+
+ EX0 {return {Bit address: 0xA8 -- Enable or disable External Interrupt 0}}
+ ET0 {return {Bit address: 0xA9 -- Enable or disable the Timer 0 overflow interrupt}}
+ EX1 {return {Bit address: 0xAA -- Enable or disable External Interrupt 1}}
+ ET1 {return {Bit address: 0xAB -- Enable or disable the Timer 1 overflow interrupt}}
+ ES {return {Bit address: 0xAC -- Enable or disable the serial port interrupt}}
+ ET2 {return {Bit address: 0xAD -- Enable or disable the Timer 2 overflow interrupt}}
+ EC {return {Bit address: 0xAE -- Enable or disable the comparator interrupt}}
+
+ PX0 {return {Bit address: 0xB8 -- Defines the External Interrupt 0 priority level}}
+ PT0 {return {Bit address: 0xB9 -- Defines the Timer 0 interrupt priority level}}
+ PX1 {return {Bit address: 0xBA -- Defines External Interrupt 1 priority level}}
+ PT1 {return {Bit address: 0xBB -- Defines the Timer 1 interrupt priority level}}
+ PS {return {Bit address: 0xBC -- Defines the Serial Port interrupt priority level}}
+ PT2 {return {Bit address: 0xBD -- Defines the Timer 2 interrupt priority level}}
+ PC {return {Bit address: 0xBE -- Defines the comparator interrupt priority level}}
+
+ PX0H {return {IPH.0 -- Defines the External Interrupt 0 priority level}}
+ PT0H {return {IPH.1 -- Defines the Timer 0 interrupt priority level}}
+ PX1H {return {IPH.2 -- Defines External Interrupt 1 priority level}}
+ PT1H {return {IPH.3 -- Defines the Timer 1 interrupt priority level}}
+ PSH {return {IPH.4 -- Defines the Serial Port interrupt priority level}}
+ PT2H {return {IPH.5 -- Defines the Timer 2 interrupt priority level}}
+ PCH {return {IPH.6 -- Defines the comparator interrupt priority level}}
+ default {return {}}
+ }
+ }
+
+ ## Disable buttons on this panel which can manipulate with simulator
+ # @return void
+ public method interrupt_monitor_enable_buttons {} {
+ if {!$dialog_opened} {return}
+ foreach widget [pack slaves $priorities_frame] {
+ $widget.secondary.exec_but configure -state normal
+ }
+ }
+
+ ## Disable all buttons on this panel which can manipulate with simulator
+ # @return void
+ public method interrupt_monitor_disable_buttons {} {
+ if {!$dialog_opened} {return}
+ foreach frame [list $in_progress_frame $pending_frame] {
+ foreach widget [pack slaves $frame] {
+ $widget.secondary.close_but configure -state disabled
+ }
+ }
+ foreach widget [pack slaves $priorities_frame] {
+ $widget.secondary.down_but configure -state disabled
+ $widget.secondary.up_but configure -state disabled
+ $widget.secondary.exec_but configure -state disabled
+ }
+ }
+
+ ## Create event bindings to provide scrolling ability for all childern widgets
+ # @parm Widget scrollable_frame - Parent frame (scrollable frame)
+ # @parm Widget this_frame - This frame
+ # @parm Bool also_this - This should be always 1
+ # @return void
+ private method scrolling_bindings {scrollable_frame this_frame also_this} {
+ if {$also_this} {
+ bind $this_frame <Button-5> "$scrollable_frame yview scroll +1 units"
+ bind $this_frame <Button-4> "$scrollable_frame yview scroll -1 units"
+ }
+ foreach w [winfo children $this_frame] {
+ bind $w <Button-5> "$scrollable_frame yview scroll +1 units"
+ bind $w <Button-4> "$scrollable_frame yview scroll -1 units"
+ scrolling_bindings $scrollable_frame $w 0
+ }
+ }
+
+ ## Invert particular bit in simulator
+ # @parm String bit_name - Name of bit to invert (uppercase)
+ # @return void
+ public method interrupt_monitor_invert_bit {bit_name} {
+ if {![$this is_frozen]} {
+ return
+ }
+
+ $this intr_mon_setBit $bit_name [expr {![intr_mon_getBit $bit_name]}]
+ }
+
+ ## Set value for particular bit
+ # @parm String bit_name - Name of bit to set (uppercase)
+ # @parm Bool value - New bit value
+ # @return void
+ private method intr_mon_setBit {bit_name value} {
+ switch -- $bit_name {
+ SPIF {
+ set reg {SPSR}
+ set bit_num 7
+ }
+ CF {
+ set reg {ACSR}
+ set bit_num 4
+ }
+ PX0H {
+ set reg {IPH}
+ set bit_num 0
+ }
+ PT0H {
+ set reg {IPH}
+ set bit_num 1
+ }
+ PX1H {
+ set reg {IPH}
+ set bit_num 2
+ }
+ PT1H {
+ set reg {IPH}
+ set bit_num 3
+ }
+ PSH {
+ set reg {IPH}
+ set bit_num 4
+ }
+ PT2H {
+ set reg {IPH}
+ set bit_num 5
+ }
+ PCH {
+ set reg {IPH}
+ set bit_num 6
+ }
+ default {
+ $this setBit $::Simulator_ENGINE::symbol($bit_name) $value
+ return
+ }
+ }
+
+ # Determinate register address, register value and bit mask for bit to set
+ set reg $::Simulator_ENGINE::symbol($reg)
+ set reg_val [$this getSfrDEC $reg]
+ set bit_num [expr {1 << $bit_num}]
+
+ # Set bit
+ if {(($reg_val & $bit_num) ? 1 : 0) != ($value ? 1 : 0)} {
+ set reg_val [expr {$reg_val ^ $bit_num}]
+ $this setSfr $reg [format %X $reg_val]
+ $this Simulator_sync_sfr $reg
+ }
+ }
+
+ ## Get value of particular bit in simulator
+ # @parm String bit_name - Name of bit (uppercase)
+ # @return Bool - bit value
+ private method intr_mon_getBit {bit_name} {
+ switch -- $bit_name {
+ SPIF {return [$this getBitByReg $::Simulator_ENGINE::symbol(SPSR) 7]}
+ CF {return [$this getBitByReg $::Simulator_ENGINE::symbol(ACSR) 4]}
+ PX0H {return [$this getBitByReg $::Simulator_ENGINE::symbol(IPH) 0]}
+ PT0H {return [$this getBitByReg $::Simulator_ENGINE::symbol(IPH) 1]}
+ PX1H {return [$this getBitByReg $::Simulator_ENGINE::symbol(IPH) 2]}
+ PT1H {return [$this getBitByReg $::Simulator_ENGINE::symbol(IPH) 3]}
+ PSH {return [$this getBitByReg $::Simulator_ENGINE::symbol(IPH) 4]}
+ PT2H {return [$this getBitByReg $::Simulator_ENGINE::symbol(IPH) 5]}
+ PCH {return [$this getBitByReg $::Simulator_ENGINE::symbol(IPH) 6]}
+ default {return [$this getBit $::Simulator_ENGINE::symbol($bit_name)] }
+ }
+ }
+}
diff --git a/lib/simulator/sfrmap.tcl b/lib/simulator/sfrmap.tcl
new file mode 100755
index 0000000..d6d16d2
--- /dev/null
+++ b/lib/simulator/sfrmap.tcl
@@ -0,0 +1,523 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements window showing the map of avaliable special function register
+# --------------------------------------------------------------------------
+
+class SFRMap {
+ ## COMMON
+ common count 0 ;# Int: Counter of object instances
+
+ ## PRIVATE
+ private variable dialog_opened 0 ;# Bool: Dialog window opened
+ private variable defined_sfr ;# List: Addresses of defined SFR in this dialog
+ private variable win ;# Widget: Dialog window
+ private variable enabled 0 ;# Bool: True if simulator is engaged
+ private variable validation_ena 0 ;# Bool: Entry boxes validation enabled
+ private variable main_frame ;# Widget: Frame containing registers
+ private variable det_name ;# Widget: Entry box on bottom bar (Register name)
+ private variable det_hex ;# Widget: Entry box on bottom bar (HEX)
+ private variable det_dec ;# Widget: Entry box on bottom bar (DEC)
+ private variable det_bin ;# Widget: Entry box on bottom bar (BIN)
+ private variable det_oct ;# Widget: Entry box on bottom bar (OCT)
+ private variable bottom_right_frame ;# Widget: Bottom right frame
+ private variable selected_entry -1 ;# Int: Address of selected entry box in the map
+
+ constructor {} {
+ incr count
+ }
+
+ destructor {
+ if {$dialog_opened} {
+ destroy $win
+ }
+ }
+
+ ## Invoke dialog window
+ # @return void
+ public method sfrmap_invoke_dialog {} {
+ if {$dialog_opened} {return}
+ set dialog_opened 1
+
+ # Create dialog window
+ set enabled [$this is_frozen]
+ set win [toplevel .sfr_map$count -bg {#FFFFFF} -class {SFR map} -bg {#EEEEEE}]
+
+ # Create other widgets
+ create_win_gui
+
+ # Configure the window
+ wm iconphoto $win ::ICONS::16::kcmmemory_S
+ wm title $win "Map of SFR area - [string trim $this {:}] - MCU 8051 IDE"
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "$this sfrmap_close_dialog"
+ bindtags $win [list $win Toplevel all .]
+ }
+
+ ## Create window widgets
+ # @return void
+ private method create_win_gui {} {
+ set main_frame [frame $win.main_frame -bg {#888888}]
+
+ ## Create headers for main frame
+ # Horizontal headers
+ set header_idx 0
+ for {set i 0; set j 8; set col 1} {$i < 8} {incr i; incr j; incr col} {
+ set k [format %X $j]
+ grid [label $main_frame.header_$header_idx \
+ -text "$i/$k" -bg {#FFFFFF} -fg {#555555} \
+ ] -sticky nsew -column $col -row 0
+ incr header_idx
+ grid [label $main_frame.header_$header_idx \
+ -text "$i/$k" -bg {#FFFFFF} -fg {#555555} \
+ ] -sticky nsew -column $col -row 17 -pady 1
+ incr header_idx
+ }
+ # Vertical headers
+ set row 1
+ foreach left {F8h F0h E8h E0h D8h D0h C8h C0h B8h B0h A8h A0h 98h 90h 88h 80h} \
+ right {FFh F7h EFh E7h DFh D7h CFh C7h BFh B7h AFh A7h 9Fh 97h 8Fh 87h} \
+ {
+ grid [label $main_frame.header_$header_idx \
+ -text $left -bg {#FFFFFF} -fg {#555555} \
+ ] -sticky nsew -column 0 -row $row
+ incr header_idx
+ grid [label $main_frame.header_$header_idx \
+ -text $right -bg {#FFFFFF} -fg {#555555} \
+ ] -sticky nsew -column 9 -row $row -padx 1
+ incr row
+ incr header_idx
+ }
+ # Corners
+ foreach row {0 0 17 17} col {0 9 0 9} {
+ grid [frame $main_frame.header_$header_idx -bg {#FFFFFF}] \
+ -row $row -column $col -sticky nsew
+ incr header_idx
+ }
+
+ # Create separate frame for each cell
+ set addr 128
+ for {set row 16} {$row > 0} {incr row -1} {
+ for {set col 1} {$col < 9} {incr col} {
+ set frame [frame $main_frame.cell_$addr -bg {#DDDDDD} -padx 1]
+ grid $frame \
+ -row $row -column $col \
+ -sticky nsew -padx [expr {$col % 2}] \
+ -pady [expr {$row % 2}]
+ incr addr
+ }
+ }
+
+ # Insure than all cells have the same width and heigh
+ for {set i 1} {$i < 9} {incr i} {
+ grid columnconfigure $main_frame $i -uniform sfr_col
+ }
+ for {set i 1} {$i < 17} {incr i} {
+ grid rowconfigure $main_frame $i -uniform sfr_row
+ }
+
+ # Create matrix of SFR
+ set validation_ena 0
+ set defined_sfr {}
+ foreach reg [$this simulator_get_sfrs] {
+ set addr [lindex $reg 0]
+ set name [lindex $reg 1]
+ set row 0
+
+ lappend defined_sfr $addr
+
+ switch -- $name {
+ {SBUFR} {
+ set name_d {SBUF R}
+ }
+ {SBUFT} {
+ set name_d {SBUF T}
+ }
+ default {
+ set name_d $name
+ }
+ }
+
+ set n_addr [expr {$addr & 0x0FF}]
+ if {$addr > 0xFF} {
+ set row 1
+ }
+
+ if {!($addr % 8)} {
+ set fg {#00DDDD}
+ } {
+ set fg {#0000DD}
+ }
+ $main_frame.cell_$n_addr configure -bg {#FFFFFF}
+ grid [label $main_frame.lbl_${addr} \
+ -text $name_d -bg {#FFFFFF} -fg $fg \
+ ] -in $main_frame.cell_$n_addr -sticky nsw -row $row -column 0
+ set entry [ttk::entry $main_frame.ent_${addr} \
+ -validatecommand "$this sfrmap_validate $addr h %P m" \
+ -style Simulator_WhiteBg.TEntry \
+ -validate all \
+ -takefocus 0 \
+ -width 3 \
+ -font ${::Simulator_GUI::entry_font} \
+ ]
+ grid $entry -in $main_frame.cell_$n_addr -padx 1 -pady 1 -row $row -column 1 -sticky nse
+ $entry insert end [$this getSfr $addr]
+ if {!$enabled} {
+ $entry configure -state disabled
+ }
+ if {$row} {
+ foreach widget [list \
+ $main_frame.lbl_${addr} $main_frame.lbl_${n_addr} \
+ $main_frame.ent_${addr} $main_frame.ent_${n_addr} \
+ ] {
+ catch {$widget configure -highlightthickness 0}
+ catch {$widget configure -pady 0}
+ catch {$widget configure -bd 0}
+
+ $widget configure -font [font create -family $::DEFAULT_FIXED_FONT -size -3]
+ grid configure $widget -pady 0 -ipady 0
+ }
+ foreach widget [list $main_frame.lbl_${addr} $main_frame.lbl_${n_addr}] {
+ $widget configure -pady 0
+ }
+ grid rowconfigure $main_frame.cell_$n_addr 0 -pad 0
+ grid rowconfigure $main_frame.cell_$n_addr 1 -pad 0
+ }
+ grid columnconfigure $main_frame.cell_$n_addr 0 -weight 1
+
+ bindtags $entry [list $entry TEntry $win all .]
+ bind $entry <Motion> {help_window_show %X %Y+30}
+ bind $entry <Leave> {help_window_hide}
+ bind $entry <FocusIn> "$this sfrmap_map_cell_focused $addr $name"
+ set hex_addr [format %X $addr]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ }
+ bind $entry <Enter> "create_help_window $win \[$this getSfr $addr\] {$hex_addr SFR}"
+ }
+ set validation_ena 1
+
+ ## Create bottom frame
+ set bottom_frame [frame $win.bottom_frame -bg {#FFFFFF}]
+ # Create label "Reserved"
+ pack [label $bottom_frame.res_0 -text [mc "Reserved"] -bg {#FFFFFF}] -side left
+ pack [label $bottom_frame.res_1 -width 6 -bg {#CCCCCC} -bd 1 -relief raised] \
+ -side left -pady 5
+ pack [frame $bottom_frame.frame_foo -width 20] -side left
+ # Create label "Bit addressable"
+ pack [label $bottom_frame.bit_0 -text [mc "Bit addressable"] -bg {#FFFFFF}] -side left
+ pack [label $bottom_frame.bit_1 -width 6 -bg {#00DDDD} -bd 1 -relief raised] \
+ -side left -pady 5
+ # Create bottom right frame (additional entry boxes)
+ set bottom_right_frame [frame $bottom_frame.bottom_right -bg {#FFFFFF}]
+ set det_name [label $bottom_right_frame.name_lbl \
+ -bg {#FFFFFF} -fg {#0000DD} \
+ ]
+ set det_hex [ttk::entry $bottom_right_frame.hex_entry \
+ -validatecommand "$this sfrmap_validate {} h %P p" \
+ -style Simulator_WhiteBg.TEntry \
+ -validate all \
+ -width 3 \
+ ]
+ set det_dec [ttk::entry $bottom_right_frame.dec_entry \
+ -validatecommand "$this sfrmap_validate {} d %P p" \
+ -style Simulator_WhiteBg.TEntry \
+ -validate all \
+ -width 3 \
+ ]
+ set det_bin [ttk::entry $bottom_right_frame.bin_entry \
+ -validatecommand "$this sfrmap_validate {} b %P p" \
+ -style Simulator_WhiteBg.TEntry \
+ -validate all \
+ -width 8 \
+ ]
+ set det_oct [ttk::entry $bottom_right_frame.oct_entry \
+ -validatecommand "$this sfrmap_validate {} o %P p" \
+ -style Simulator_WhiteBg.TEntry \
+ -validate all \
+ -width 3 \
+ ]
+ foreach entry [list $det_hex $det_dec $det_bin $det_oct] {
+ bind $entry <FocusIn> "$this sfrmap_panel_entrybox_focused"
+ bindtags $entry [list $entry TEntry $win all .]
+ }
+ pack [ttk::separator $bottom_right_frame.sep -orient vertical] -side left -fill y -padx 3
+ pack $det_name -side left
+
+ pack [label $bottom_right_frame.lbl_hex \
+ -text [mc "HEX:"] -pady 0 -bg {#FFFFFF} \
+ -font ${::Simulator_GUI::smallfont} \
+ -fg ${::Simulator_GUI::small_color} \
+ ] -side left
+ pack $det_hex -side left
+ pack [label $bottom_right_frame.lbl_dec \
+ -text [mc "DEC:"] -pady 0 -bg {#FFFFFF} \
+ -font ${::Simulator_GUI::smallfont} \
+ -fg ${::Simulator_GUI::small_color} \
+ ] -side left
+ pack $det_dec -side left
+ pack [label $bottom_right_frame.lbl_bin \
+ -text [mc "BIN:"] -pady 0 -bg {#FFFFFF} \
+ -font ${::Simulator_GUI::smallfont} \
+ -fg ${::Simulator_GUI::small_color} \
+ ] -side left
+ pack $det_bin -side left
+ pack [label $bottom_right_frame.lbl_oct \
+ -text [mc "OCT:"] -pady 0 -bg {#FFFFFF} \
+ -font ${::Simulator_GUI::smallfont} \
+ -fg ${::Simulator_GUI::small_color} \
+ ] -side left
+ pack $det_oct -side left
+
+ # Pack main and bottom frame
+ pack $main_frame -fill both
+ pack $bottom_frame -side bottom -fill x
+ }
+
+ ## Close the dialog window
+ # @return void
+ public method sfrmap_close_dialog {} {
+ if {!$dialog_opened} {return}
+ set dialog_opened 0
+ destroy $win
+ }
+
+ ## Binding for event <FocusIn> on SFR entry box in the matrix
+ # @parm Int addr - Register address
+ # @parm String name - Register name
+ # @return void
+ public method sfrmap_map_cell_focused {addr name} {
+ set selected_entry $addr
+
+ # Pack bottom right frame if it has not been packed yet
+ if {![winfo viewable $bottom_right_frame]} {
+ pack $bottom_right_frame -side right -padx 5
+ }
+
+ # Adjust entry boxes
+ sfrmap_validate $addr h [$main_frame.ent_${addr} get] m
+ $det_name configure -text "${name}:"
+
+ # Restore normal color
+ foreach entry [list $main_frame.ent_${addr} $det_hex $det_oct $det_bin $det_dec] {
+ $entry configure -style Simulator_WhiteBg.TEntry
+ }
+
+ # Disable these entry boxes
+ if {!$enabled} {
+ foreach entry [list $det_hex $det_oct $det_bin $det_dec] {
+ $entry configure -state disabled
+ }
+ }
+ }
+
+ ## Binding for event <FocusIn> on SFR entry box in the bottom right panel
+ # Restore normal color for all enty boxes related to the selected SFR
+ # @return void
+ public method sfrmap_panel_entrybox_focused {} {
+ foreach entry [list $main_frame.ent_${selected_entry} $det_hex $det_oct $det_bin $det_dec] {
+ $entry configure -style Simulator_WhiteBg.TEntry
+ }
+ }
+
+ ## Set value for certain register
+ # @parm Int addr - Register address
+ # @parm Int value - New register value
+ # @return void
+ public method sfrmap_map_sync {addr val} {
+ # Check if this call has some meaning
+ if {!$dialog_opened || !$validation_ena} {return}
+ if {[lsearch $defined_sfr $addr] == -1} {return}
+ set original_val [$main_frame.ent_${addr} get]
+ if {[expr "0x$original_val"] == $val} {
+ return
+ }
+
+ # Adjust value
+ set val [format %X $val]
+ if {[string length $val] == 1} {
+ set val "0$val"
+ }
+
+ # Set value
+ $main_frame.ent_${addr} delete 0 end
+ $main_frame.ent_${addr} insert 0 $val
+
+ # Highlight entry boxes
+ $main_frame.ent_${addr} configure -style Simulator_WhiteBg_HG.TEntry
+ if {$selected_entry == $addr} {
+ foreach entry [list $det_hex $det_oct $det_bin $det_dec] {
+ $entry configure -style Simulator_WhiteBg_HG.TEntry
+ }
+ }
+ }
+
+ ## Validate value in some entry box in the matrix
+ # @parm Int addr - Register address
+ # @parm Char type - h == HEX; o == OCT; b == BIN; d == DEC
+ # @parm String value - Content to validate
+ # @parm Char from - m == Matrix; p == Bottom panel
+ # @return Bool - Result
+ public method sfrmap_validate {addr type value from} {
+ # Prevent recursion
+ if {!$validation_ena} {return 1}
+ set validation_ena 0
+
+ if {$from == {p}} {
+ set addr $selected_entry
+ }
+
+ # Validate the value
+ set value [string trimleft $value 0]
+ if {$value == {}} {
+ set value 0
+ }
+ switch -- $type {
+ h {
+ if {[string length $value] > 2 || ![string is xdigit $value]} {
+ set validation_ena 1
+ return 0
+ }
+ set value [expr "0x$value"]
+ }
+ d {
+ if {[string length $value] > 3 || ![string is digit $value]} {
+ set validation_ena 1
+ return 0
+ }
+ }
+ b {
+ if {[string length $value] > 8 || ![regexp {^[01]*$} $value]} {
+ set validation_ena 1
+ return 0
+ }
+ set value [NumSystem::bin2dec $value]
+ }
+ o {
+ if {[string length $value] > 3 || ![regexp {^[0-7]*$} $value]} {
+ set validation_ena 1
+ return 0
+ }
+ set value [expr "0$value"]
+ }
+ }
+ if {$value > 255 || $value < 0} {
+ set validation_ena 1
+ return 0
+ }
+
+ # Synchronize with engine and simulator control panel
+ $this setSfr $addr [format %X $value]
+ $this SimGUI_disable_sync
+ $this Simulator_GUI_sync S $addr
+ $this SimGUI_enable_sync
+
+ # Synchronize the rest of entry boxes related to this SFR
+ if {$selected_entry == $addr} {
+ if {$type != {d}} {
+ $det_dec delete 0 end
+ $det_dec insert 0 $value
+ }
+ if {$type != {b}} {
+ set txt [NumSystem::dec2bin $value]
+ set len [string length $txt]
+ if {$len != 8} {
+ set txt "[string repeat 0 [expr {8 - $len}]]$txt"
+ }
+ $det_bin delete 0 end
+ $det_bin insert 0 $txt
+ }
+ if {$type != {o}} {
+ set txt [format %o $value]
+ set len [string length $txt]
+ if {$len != 3} {
+ set txt "[string repeat 0 [expr {3 - $len}]]$txt"
+ }
+ $det_oct delete 0 end
+ $det_oct insert 0 $txt
+ }
+ }
+ set txt [format %X $value]
+ if {[string length $txt] == 1} {
+ set txt "0$txt"
+ }
+ if {$from == {p}} {
+ $main_frame.ent_${addr} delete 0 end
+ $main_frame.ent_${addr} insert 0 $txt
+ if {$selected_entry == $addr && $type != {h}} {
+ $det_hex delete 0 end
+ $det_hex insert 0 $txt
+ }
+ } elseif {$selected_entry == $addr} {
+ $det_hex delete 0 end
+ $det_hex insert 0 $txt
+ }
+
+ # Done
+ set validation_ena 1
+ return 1
+ }
+
+ ## Commint new set special function registers
+ # @return void
+ public method sfrmap_commit_new_sfr_set {} {
+ if {!$dialog_opened} {return}
+ foreach wdg [pack slaves $win] {
+ destroy $wdg
+ }
+ set validation_ena 0
+ set selected_entry -1
+ create_win_gui
+ }
+
+ ## Set state of this panel
+ # @parm Bool bool - 0 == Disable; 1 == Enable
+ # @return void
+ public method sfrmap_setEnabled {bool} {
+ if {!$dialog_opened} {return}
+ set enabled $bool
+ if {$bool} {
+ set bool {normal}
+ } {
+ set bool {disabled}
+ }
+ foreach entry [list $det_hex $det_oct $det_bin $det_dec] {
+ $entry configure -state $bool
+ }
+ foreach addr [$this simulator_get_avaliable_sfr] {
+ $main_frame.ent_${addr} configure -state $bool
+ }
+ }
+
+ ## Clear highlight of changed cells
+ # @return void
+ public method sfrmap_clear_hg {} {
+ if {!$dialog_opened} {return}
+
+ foreach addr $defined_sfr {
+ $main_frame.ent_${addr} configure -style Simulator_WhiteBg.TEntry
+ }
+ }
+}
diff --git a/lib/simulator/simulator.tcl b/lib/simulator/simulator.tcl
new file mode 100755
index 0000000..06ce985
--- /dev/null
+++ b/lib/simulator/simulator.tcl
@@ -0,0 +1,1202 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements 8051 Simulator environment.
+# Object constist of GUI panel of controls (class Simulator_GUI)
+# and Simulator Engine (class Simulator_ENGINE).
+# --------------------------------------------------------------------------
+
+# --------------------------------------------------------------------------
+# This file was modified & fixed by Kostya V. Ivanov <kostya@istcom.spb.ru>
+#
+# Special thanks to Kostya V. Ivanov !
+# --------------------------------------------------------------------------
+
+# Load sources
+source "${::LIB_DIRNAME}/simulator/engine/engine_core.tcl" ;# Simulator engine
+source "${::LIB_DIRNAME}/simulator/simulator_gui.tcl" ;# Simulator panel
+source "${::LIB_DIRNAME}/simulator/interruptmonitor.tcl" ;# Interrupt monitor
+source "${::LIB_DIRNAME}/simulator/virtual_uart_term.tcl" ;# Virtual UART Terminal
+source "${::LIB_DIRNAME}/simulator/sfrmap.tcl" ;# SFR Map monitor
+source "${::LIB_DIRNAME}/simulator/stopwatch.tcl" ;# Stopwatch
+source "${::LIB_DIRNAME}/simulator/bitmap.tcl" ;# Map of bit addressable area
+source "${::LIB_DIRNAME}/simulator/stackmonitor.tcl" ;# Stack monitor
+
+class Simulator {
+ inherit Simulator_GUI Simulator_ENGINE InterruptMonitor SFRMap Stopwatch BitMap StackMonitor VirtualUartTerminal
+
+ ## COMMON
+ common highlight_color {#DD8800} ;# Foreground color for changed registers
+ common normal_color {#000000} ;# Foreground color for unchanged registers
+ common error_dialog_project ;# Object: $this for current addressing error dialog
+ common not_again_val 0 ;# Bool: Value of checkbutton "Do not shot this dialog again"
+
+ common reverse_run_steps 10 ;# Int: Number of steps which can be taken back
+ common ignore_stack_overflow 0 ;# Bool: Do not show "Stack overflow" dialog
+ common ignore_stack_underflow 0 ;# Bool: Do not show "Stack underflow" dialog
+ common ignore_watchdog_reset 0 ;# Bool: Ignore reset invoked by watchdog overflow
+ common ignore_read_from_wr_only 0 ;# Bool: Ignore reading from read only register
+ common ignore_invalid_reti 0 ;# Bool: Ignore invalid return fom interrupt
+ common ignore_invalid_ins 0 ;# Bool: Ignore invalid instructions
+ common ignore_invalid_IDATA 0 ;# Bool: Ignore access to unimplemented IDATA memory
+ common ignore_invalid_EDATA 0 ;# Bool: Ignore access to unimplemented EDATA memory
+ common ignore_invalid_XDATA 0 ;# Bool: Ignore access to unimplemented XDATA memory
+ common ignore_invalid_BIT 0 ;# Bool: Ignore access to unimplemented bit
+ common ignore_invalid_CODE 0 ;# Bool: Ignore access to unimplemented CODE memory
+ common ignore_invalid_USB 0 ;# Bool: Ignore "UART: Frame discarded"
+ common ignore_invalid_UMC 0 ;# Bool: Ignore "UART mode has been changed while UART was engaged"
+ common ignore_invalid_TMC 0 ;# Bool: Ignore "Timer mode has been changed while timer was running"
+
+ common ignore_EEPROM_WR_fail 0 ;# Bool: Ignore EEPROM write failure (due to EECON.WRTINH, EECON.RDYBSY or EECON.EEMWE)
+ common ignore_EEPROM_WR_abort 0 ;# Bool: Ignore EEPROM write cycle abort
+ common undefined_value 2 ;# Int: 2 == Random; 1 == 255; 0 == 0
+
+ # Normal font for error dialog
+ common error_normal_font [font create \
+ -family {helvetica} -size -14 \
+ ]
+ # Bold font for error dialog
+ common error_bold_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ -weight bold \
+ ]
+ # Header font for error dialog
+ common error_header_font [font create \
+ -family {helvetica} -size -17 -weight bold \
+ ]
+ # Main header font
+ common error_main_header [font create \
+ -family {helvetica} -size -20 -weight bold \
+ ]
+
+ ## PRIVATE
+ private variable widgets ;# Array of widgets related to MCU registers
+ private variable highlight_ena 0 ;# Enable regsters highlighting
+ private variable error_dialog_textwdg ;# Widget: Text widget used in error dialog
+ private variable addr_error_save_type ;# Type of file to save
+
+ # Bool: Related to warnings dialogs
+ private variable ignore_warnings_related_to_changes_in_SFR 0
+
+ ## Obejct constructor
+ constructor {} {
+ }
+
+ ## Synchronize GUI with Engine, Entries: PC, Clock and Watchdog
+ # @return void
+ public method Simulator_sync_PC_etc {} {
+ # Disable GUI synchronization
+ $this SimGUI_disable_sync
+
+ # Get new and old value of Program Counter
+ set new_val [getPC]
+ set original_val [subst "\$::Simulator_GUI::ENV${obj_idx}_PC_dec"]
+
+ # Display new value of PC and highlight it if it has changed
+ set ::Simulator_GUI::ENV${obj_idx}_PC_dec $new_val
+ if {$highlight_ena && ($original_val != $new_val)} {
+ mark_entry PC
+ $this sim_eval_PC dec $new_val
+ }
+
+ # Mode program pointer in code mememory hexeditor
+ ::X::program_counter_changed $this $new_val
+
+ # Synchronize Watchdog
+ if {[$this get_feature_avaliable wtd]} {
+ set val [format %X [$this simulator_getWatchDogTimerValue]]
+ set len [string length $val]
+ if {$len != 4} {
+ set val "[string repeat {0} [expr {4 - $len}]]$val"
+ }
+ set ::Simulator_GUI::ENV${obj_idx}_WatchDog $val
+ $this simulator_evaluate_wtd_onoff_switch
+ $this watchdog_validate $val
+
+ if {[$this get_feature_avaliable wdtcon] || [$this get_feature_avaliable wdtprg]} {
+ set val [format %X [$this simulator_getWatchDogPrescalerValue]]
+ if {[string length $val] == 1} {
+ set val "0$val"
+ }
+ set ::Simulator_GUI::ENV${obj_idx}_WatchDogP $val
+ }
+ }
+
+ # Synchronize Clock
+ Simulator_sync_clock
+
+ # Enable GUI synchronization
+ $this SimGUI_enable_sync
+ }
+
+ ## Synchronize GUI with Engine, Entry: Time
+ # @return void
+ public method Simulator_sync_clock {} {
+ # Display the new value of the clock
+ if {[$this cget -P_option_clock] != {}} {
+ set ::Simulator_GUI::ENV${obj_idx}_TIME [getTime]
+ }
+ }
+
+ ## Set new clock value (entrybox: Clock)
+ # @parm Int value - new clock frequency 0..99999 (kHz)
+ # @return void
+ public method Simulator_set_clock {value} {
+ set ::Simulator_GUI::ENV${obj_idx}_CLOCK $value
+ }
+
+ ## Synchronize particular register in Internal Data Memory
+ # @parm Int addr - address of register to synchronize
+ # @return void
+ public method Simulator_sync_reg {addr} {
+ Simulator_GUI_sync I $addr
+ }
+
+ ## Synchronize particular register in SFR area
+ # @parm Int addr - address of register to synchronize
+ # @return void
+ public method Simulator_sync_sfr {addr} {
+ Simulator_GUI_sync S $addr
+ }
+
+ ## Synchronize particular register in External and Expanded Data Memory
+ # @parm Int addr - address of register to synchronize
+ # @return void
+ public method Simulator_XDATA_sync {addr} {
+ # Convert address to 4 and 3 digits HEX number
+ set addr [format "%X" $addr]
+ set len [string length $addr]
+ if {$len < 4} {
+ $this rightPanel_watch_sync "[string repeat 0 [expr {3 - $len}]]$addr"
+ set addr "[string repeat 0 [expr {4 - $len}]]$addr"
+ }
+
+ # Synchronize with HEX Editor
+ X::sync_xram_mem_window $addr $this
+
+ # Synchronize with C variables view
+ $this cvarsview_sync F [expr "0x$addr"]
+ }
+
+ ## Synchronize particular register in Internal Data Memory or SFR area
+ # @pamr Char type - I == IDATA; S == SFR
+ # @parm Int addr - address of register to synchronize
+ # @return void
+ public method Simulator_GUI_sync {type addr} {
+
+ # Internal RAM
+ if {$type == {I}} {
+ # Get new and old value
+ set new_val [getDataDEC $addr]
+ set original_val [simulator_hexeditor get_values $addr $addr]
+ if {$original_val == {}} {
+ set original_val 0
+ }
+
+ # Display (and highlight) new value
+ if {$addr < 32} {
+ set hexvalue [getData $addr]
+ set ::Simulator_GUI::ENV${obj_idx}_DATA($addr) $hexvalue
+
+ set bnk [expr {$addr / 8}]
+ set idx [expr {$addr % 8}]
+ if {$bnk == [getBank]} {
+ set ::Simulator_GUI::ENV${obj_idx}_R${idx} $hexvalue
+ if {$highlight_ena && ($original_val != $new_val)} {
+ mark_entry R${idx}
+ }
+ }
+ }
+
+ # Update IDATA hex editor
+ simulator_hexeditor setValue $addr $new_val
+ if {$highlight_ena && ($original_val != $new_val)} {
+ simulator_hexeditor setHighlighted $addr 1
+ }
+
+ # Update RAM help window
+ set hex_addr [format %X $addr]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ }
+ help_window_update $hex_addr $new_val
+
+ # Synchronize with C variables view
+ if {$addr < 128} {
+ $this cvarsview_sync E $addr
+ } {
+ $this cvarsview_sync G $addr
+ }
+
+ # Synchronize watches on right panel and stack monitor
+ $this rightPanel_watch_sync $hex_addr
+ $this stack_monitor_sync $addr
+
+ # Synchronize with map of bit addressable area
+ $this bitmap_sync $addr
+
+ # Done ..
+ return
+
+ # Program Status Word
+ } elseif {$addr == 208} {
+ # Get value of PSW
+ set psw [getSfr 208]
+ set psw [expr "0x$psw"]
+
+ # Evaluate separate bits and highlight them
+ set mask 256
+ foreach bit {C AC F0 RS1 RS0 OV - P} {
+
+ # Evaluate bit mask
+ set mask [expr {$mask >> 1}]
+ # Skip NULL registers
+ if {$bit == {-}} {continue}
+
+ # Determinate boolean value of the bit
+ if {$psw == 0} {
+ set bool 0
+ } {
+ if {[expr {$psw & $mask}] > 0} {
+ set bool 1
+ } {
+ set bool 0
+ }
+ }
+
+ # Set bit value
+ set ::Simulator_GUI::ENV${obj_idx}_SFR($bit) $bool
+
+ # Take care of bit color
+ if {$bool} {
+ $Simulator_panel_parent._PSW_$bit configure -fg $on_color
+ } {
+ $Simulator_panel_parent._PSW_$bit configure -fg $off_color
+ }
+ }
+ # Set Registers values
+ for {set i 0} {$i < 8} {incr i} {
+ set idx [expr {[getBank] * 8 + $i}]
+ set hexvalue [getData $idx]
+ set ::Simulator_GUI::ENV${obj_idx}_R${i} $hexvalue
+ }
+ # Synchronize with SFR watches
+ $this sfr_watches_sync 208 $psw
+ $this sfrmap_map_sync 208 $psw
+ $this rightPanel_watch_sync_sfr 208
+
+ # Update RAM help window
+ help_window_update {D0 SFR} $psw
+
+ # Synchronize with C variables view
+ $this cvarsview_sync I 208
+
+ # Done ..
+ return
+
+ # Special Function Registers
+ } else {
+ # Evaluate register name
+ set name_resolved 1
+ switch -- $addr {
+ 128 {set regName {P0} }
+ 144 {set regName {P1} }
+ 160 {set regName {P2} }
+ 176 {set regName {P3} }
+ 192 {set regName {P4} }
+ 131 {set regName {DPH} }
+ 130 {set regName {DPL} }
+ 133 {set regName {DP1H} }
+ 132 {set regName {DP1L} }
+ 153 {set regName {SBUFR} }
+ 409 {set regName {SBUFT} }
+ 152 {set regName {SCON} }
+ 141 {set regName {TH1} }
+ 139 {set regName {TL1} }
+ 140 {set regName {TH0} }
+ 138 {set regName {TL0} }
+ 136 {set regName {TCON} }
+ 137 {set regName {TMOD} }
+ 135 {set regName {PCON} }
+ 168 {set regName {IE} }
+ 184 {set regName {IP} }
+ 129 {set regName {SP} }
+ 224 {set regName {A_hex} }
+ 240 {set regName {B_hex} }
+ 200 {set regName {T2CON} }
+ 201 {set regName {T2MOD} }
+ 202 {set regName {RCAP2L} }
+ 203 {set regName {RCAP2H} }
+ 204 {set regName {TL2} }
+ 205 {set regName {TH2} }
+ 162 {set regName {AUXR1} }
+ 166 {set regName {WDTRST} }
+ 142 {set regName {AUXR} }
+ 151 {set regName {ACSR} }
+ 183 {set regName {IPH} }
+ 169 {set regName {SADDR} }
+ 185 {set regName {SADEN} }
+ 213 {set regName {SPCR} }
+ 170 {set regName {SPSR} }
+ 134 {set regName {SPDR} }
+ 150 {set regName {EECON} }
+ 143 {
+ if {[$this get_feature_avaliable ckcon]} {
+ set regName {CKCON}
+ } {
+ set regName {CLKREG}
+ }
+ }
+ 167 {
+ if {[$this get_feature_avaliable wdtprg]} {
+ set regName {WDTPRG}
+ } {
+ set regName {WDTCON}
+ }
+ }
+ default {set name_resolved 0}
+ }
+
+ # Synchronize with SFR watches
+ set new_val [getSfr $addr]
+ set dec_val [expr {"0x$new_val"}]
+ $this sfr_watches_sync $addr $dec_val
+
+ # Synchronize with SFR map
+ $this sfrmap_map_sync $addr $dec_val
+
+ # Synchronize with C variables view
+ $this cvarsview_sync I $addr
+
+ # Synchronize with simulator control panel
+ if {$name_resolved} {
+ set original_val [subst "\$::Simulator_GUI::ENV${obj_idx}_${regName}"]
+ set ::Simulator_GUI::ENV${obj_idx}_${regName} $new_val
+
+ if {$highlight_ena && ($original_val != $new_val)} {
+ mark_entry $addr
+ }
+
+ # Synchronize special values
+ switch -- $addr {
+ 152 { ;# SCON
+ ## Synchronize bits FE and SM0
+ # FE
+ set bit_FE [$this sim_engine_get_FE]
+ if {$bit_FE != {}} {
+ set ::Simulator_GUI::ENV${obj_idx}_SFR(FE) $bit_FE
+ if {$bit_FE} {
+ $Simulator_panel_parent._SCON_FE configure -fg $::Simulator_GUI::on_color
+ } {
+ $Simulator_panel_parent._SCON_FE configure -fg $::Simulator_GUI::off_color
+ }
+ }
+ # SM0
+ if {[$this sim_engine_get_SM0]} {
+ $Simulator_panel_parent._SCON_SM0 configure -fg $::Simulator_GUI::on_color
+ set ::Simulator_GUI::ENV${obj_idx}_SFR(SM0) 1
+ } {
+ $Simulator_panel_parent._SCON_SM0 configure -fg $::Simulator_GUI::off_color
+ set ::Simulator_GUI::ENV${obj_idx}_SFR(SM0) 0
+ }
+ }
+ 153 { ;# SBUF
+ ## Synchronize both registers (receive & transmit)
+ Simulator_GUI_sync S ${::Simulator_ENGINE::symbol(SBUFT)}
+ }
+ }
+ }
+
+ # Update RAM help window
+ set hex_addr [format %X $addr]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ }
+ help_window_update [list $hex_addr {SFR}] $new_val
+
+ $this rightPanel_watch_sync_sfr $addr
+
+ # Explicitly call entry box validator
+ switch -- $addr {
+ 224 {$this sim_eval_AB A hex $new_val}
+ 240 {$this sim_eval_AB B hex $new_val}
+
+ 205 - 204 - 203 -
+ 202 - 141 - 139 -
+ 140 -
+ 138 {$this validate_Txx $regName $new_val}
+
+ 128 - 144 - 160 -
+ 176 -
+ 192 {$this sim_eval_Px $regName hex $new_val}
+
+ 142 - 162 - 151 -
+ 150 - 213 - 170 -
+ 167 - 167 - 183 -
+ 143 - 200 - 201 -
+ 135 - 152 - 168 -
+ 184 - 136 -
+ 137 {$this validate_hex_bitmap_reg $new_val $regName}
+ }
+ }
+ }
+
+ ## Synchronize all registers in IRAM and SFR
+ # @return void
+ public method Simulator_sync {} {
+ # Synchronize PC and Clock
+ Simulator_sync_PC_etc
+
+ # Synchronize IRAM
+ set iram_size [lindex [$this cget -procData] 3]
+ for {set i 0} {$i < $iram_size} {incr i} {
+ Simulator_sync_reg $i
+ }
+
+ # Synchronize SFR
+ foreach addr [simulator_get_avaliable_sfr] {
+ Simulator_GUI_sync S $addr
+ }
+ }
+
+ ## Synchronization after simulator initialization
+ # @return void
+ public method Simulator_first_sync {} {
+ set highlight_ena 0
+ Simulator_sync
+ set highlight_ena 1
+ }
+
+ ## Reset simulator engine and synchronize all registers
+ # @parm Int arg - argument for reset procedure
+ # @return void
+ public method Simulator_reset {arg} {
+ # Perform master reset
+ master_reset $arg
+
+ # Synchronize
+ set highlight_ena 0
+ Simulator_sync
+ set highlight_ena 1
+
+ # Clear stepback stack
+ stepback_discard_stack
+ ::X::stepback_button_set_ena 0
+
+ # Clear highlight
+ simulator_clear_highlight
+
+ # Clear time entry
+ set ::Simulator_GUI::ENV${obj_idx}_TIME {}
+ }
+
+ ## Clear highlight for all internal registers
+ # @return void
+ public method simulator_clear_highlight {} {
+ simulator_hexeditor clearHighlighting
+ foreach addr [simulator_get_avaliable_sfr] {
+ unmark_entry $addr
+ }
+ foreach addr {R0 R1 R2 R3 R4 R5 R6 R7} {
+ unmark_entry $addr
+ }
+ unmark_entry PC
+ }
+
+ ## Add register entry widget reference to array of registers
+ # @parm Int addr - Register address
+ # @parm Widget widget - Register entry widget
+ # @return void
+ public method add_sfr_entry {addr widget} {
+ lappend widgets($addr) $widget
+ }
+
+ ## Clear list of registred widgets in simulator control panel
+ # This list is used for enabling/disabling these widgets on start/shutdown
+ # @return void
+ public method sumulator_clear_widgets {} {
+ array unset widgets
+ }
+
+ ## Highlight register entry widget
+ # @parm Int addr - Register address
+ # @return void
+ public method mark_entry {addr} {
+ # Skip PSW
+ if {$addr == 208} {return}
+
+ foreach wdg $widgets($addr) {
+ if {[winfo class $wdg] == {TEntry}} {
+ $wdg configure -style Simulator_HG.TEntry
+ } {
+ $wdg configure -fg $highlight_color
+ }
+ }
+ }
+
+ ## "Unhighlight" register entry widget
+ # @parm Int addr - Register address
+ # @return void
+ public method unmark_entry {addr} {
+ # Skip PSW
+ if {$addr == 208} {return}
+
+ foreach wdg $widgets($addr) {
+ if {[winfo class $wdg] == {TEntry}} {
+ $wdg configure -style Simulator.TEntry
+ } {
+ $wdg configure -fg $normal_color
+ }
+ }
+ }
+
+ ## Invokes error message "Undefined result"
+ # @parm Char location - Memory type
+ # D == IDATA direct addressing
+ # I == IDATA indirect addressing (or operations on stack)
+ # B == Bit area
+ # E == ERAM
+ # X == XDATA
+ # C == CODE
+ # @parm Int address - Memory address (0..65536)
+ # @return void
+ public method invalid_addressing_dialog {location address} {
+ # Gain error and processor details
+ set addr_dec $address
+ set address [format %X $address]
+ set len [string length $address]
+ if {$len < 4} {
+ set address "[string repeat 0 [expr {4 - $len}]]$address"
+ }
+ set processor [$this cget -P_option_mcu_type]
+ switch -- $location {
+ {D} { ;# IDATA direct addressing
+ set conf_variable {ignore_invalid_IDATA}
+ set addressing {direct }
+ if {$addr_dec > 127} {
+ set memory {special function registers area}
+ set mem {SFR}
+ } {
+ set mem {IDATA}
+ set memory {internal data memory}
+ }
+ }
+ {I} { ;# IDATA indirect addressing (or operations with stack)
+ set conf_variable {ignore_invalid_IDATA}
+ set addressing {indirect }
+ set memory {internal data memory}
+ set mem {IDATA}
+ }
+ {B} { ;# Bit area
+ set conf_variable {ignore_invalid_BIT}
+ set addressing {direct }
+ set memory {bit addressable area}
+ set mem {Bit area}
+ }
+ {X} { ;# XDATA
+ set conf_variable {ignore_invalid_XDATA}
+ set addressing {indirect }
+ set memory {external data memory}
+ set mem {XDATA}
+ }
+ {C} { ;# CODE
+ set conf_variable {ignore_invalid_CODE}
+ set addressing {}
+ set memory {program memory}
+ set mem {CODE}
+ }
+ }
+
+ # Create dialog window
+ set win [toplevel .undefined_result -class {Error dialog} -bg {#EEEEEE}]
+
+ # Create dialog header
+ set top_frame [frame $win.top_frame]
+ pack [label $top_frame.left \
+ -image ::ICONS::32::messagebox_critical \
+ ] -side left
+ pack [label $top_frame.right \
+ -text [mc "Undefined result"] \
+ -font $error_main_header \
+ ] -side left -fill x
+
+ # Create middle frame (text widget and scrollbar)
+ set middle_frame [frame $win.middle_frame]
+ set text_wdg [text $middle_frame.text \
+ -height 0 -width 0 -font $error_normal_font \
+ -yscrollcommand "$middle_frame.scrollbar set" \
+ -wrap word -relief flat -bg {#EEEEEE} \
+ -tabstyle wordprocessor \
+ ]
+ set error_dialog_textwdg $text_wdg
+ pack $text_wdg -side left -fill both -expand 1
+ pack [ttk::scrollbar $middle_frame.scrollbar \
+ -command "$text_wdg yview" \
+ -orient vertical \
+ ] -side right -fill y -after $text_wdg
+
+ # Create bottom frame (buttons: Save as text, Save as XHTML, Ok)
+ set bottom_frame [frame $win.bottom_frame]
+ pack [ttk::button $bottom_frame.save_as_txt \
+ -image ::ICONS::16::ascii \
+ -compound left \
+ -text [mc "Save as plain text"] \
+ -command "$this simulator_addr_error_save T" \
+ ] -side left
+ pack [ttk::button $bottom_frame.save_as_xhtml \
+ -image ::ICONS::16::html \
+ -compound left \
+ -text [mc "Save as XHTML"] \
+ -command "$this simulator_addr_error_save X" \
+ ] -side left
+ pack [ttk::button $bottom_frame.ok \
+ -image ::ICONS::16::ok \
+ -compound left \
+ -text [mc "Ok"] \
+ -command "grab release $win; destroy $win" \
+ ] -side right
+
+ $text_wdg tag configure tag_bold -font $error_bold_font
+ $text_wdg tag configure tag_header -font $error_header_font
+
+ # Error summary
+ $text_wdg insert end [mc "Summary:"]
+ $text_wdg tag add tag_header {insert linestart} insert
+ $text_wdg insert end [mc "\nYour program tried ${addressing}access to register at address "]
+ set index [$text_wdg index insert]
+ $text_wdg insert end [mc "0x%s in $memory" $address]
+ $text_wdg tag add tag_bold $index insert
+ $text_wdg insert end [mc ". This register is not implemented on this processor ("]
+ set index [$text_wdg index insert]
+ $text_wdg insert end "$processor"
+ $text_wdg tag add tag_bold $index insert
+ $text_wdg insert end [mc ") in this configuration. You can continue in simulation but result of this operation is undefined."]
+
+ # Error details
+ $text_wdg insert end [mc "\n\nError details:"]
+ $text_wdg tag add tag_header {insert linestart} insert
+ $text_wdg insert end [mc "\n\tTarget memory:\t\t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end [mc $mem]
+ $text_wdg insert end [mc "\n\tTarget address: \t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end "0x$address ($addr_dec)"
+ $text_wdg insert end [mc "\n\tLine:\t\t\t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end [$this editor_actLineNumber]
+ $text_wdg insert end [mc "\n\tFile:\t\t\t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end [$this editor_procedure {} cget -filename]
+ $text_wdg insert end [mc "\n\tProject:\t\t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end [string trim $this {:}]
+
+ # Processor details
+ $text_wdg insert end [mc "\n\nProcessor details:"]
+ $text_wdg tag add tag_header {insert linestart} insert
+ $text_wdg insert end [mc "\n\tType:\t\t\t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end [$this cget -P_option_mcu_type]
+ $text_wdg insert end [mc "\n\tRam size:\t\t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end "[lindex [$this cget -procData] 3] B"
+ $text_wdg insert end [mc "\n\tProgram memory: \t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end "[expr [lindex [$this cget -procData] 2] * 1024 + [$this cget -P_option_mcu_xcode]] B"
+ $text_wdg insert end [mc "\n\tExternal memory:\t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end "[$this cget -P_option_mcu_xdata] B"
+ $text_wdg insert end [mc "\n\tExpanded memory:\t"]
+ $text_wdg tag add tag_bold {insert linestart} insert
+ $text_wdg insert end "[lindex [$this cget -procData] 8] B"
+
+ # Disable text widget and pack dialog frames
+ $text_wdg configure -state disabled
+ pack $top_frame -pady 5
+ pack $middle_frame -fill both -expand 1 -pady 15 -padx 10
+ pack [ttk::separator $win.sep -orient horizontal] -fill x -padx 5 -pady 5
+ set ::Simulator::not_again_val 0
+ pack [checkbutton $win.not_again_checkbutton \
+ -text [mc "Do not show this dialog again"] \
+ -variable ::Simulator::not_again_val \
+ -command "::configDialogs::simulator::set_variable $conf_variable \$::Simulator::not_again_val" \
+ ] -anchor w -padx 15 -pady 5
+ DynamicHelp::add $win.not_again_checkbutton \
+ -text [mc "See simulator configuration dialog\nMain Menu -> Configure -> Simulator"]
+ pack $bottom_frame -fill x -side bottom -after $middle_frame -padx 5 -pady 5
+
+ # Show dialog window
+ bell
+ focus -force $bottom_frame.ok
+ wm title $win [mc "Undefined result - MCU 8051 IDE"]
+ wm iconphoto $win ::ICONS::16::no
+ wm minsize $win 450 400
+ wm protocol $win WM_DELETE_WINDOW "
+ grab release $win
+ destroy $win
+ "
+ wm transient $win .
+ wm geometry $win "+[expr {([winfo screenwidth .] - 450) / 2}]+[expr {([winfo screenheight .] - 400) / 2}]"
+ raise $win
+ catch {
+ grab $win
+ }
+ tkwait window $win
+ }
+
+ ## Invoke dialog to save contents of dialog "Undefined result" as plain text or XHTML
+ # @parm Char type - T == plain text; X == XHTML
+ # @return void
+ public method simulator_addr_error_save {type} {
+ set addr_error_save_type $type
+ set error_dialog_project $this
+ if {$type == {T}} {
+ set init {error.log}
+ set filetypes {
+ {{Log files} {*.log} }
+ {{All files} {*} }
+ }
+ } {
+ set init {error.html}
+ set filetypes {
+ {{XHTML files} {*.html}}
+ {{All files} {*} }
+ }
+ }
+
+ # Invoke the file selection dialog
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Save error log - MCU 8051 IDE"] \
+ -directory [$this cget -projectPath] \
+ -initialfile $init -defaultmask 0 \
+ -filetypes $filetypes -multiple 0
+
+ # Open file after press of OK button
+ fsd setokcmd {
+ # Get filename
+ set filename [::Simulator::fsd get]
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "[${::Simulator::error_dialog_project} cget -ProjectDir]/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join [${::Simulator::error_dialog_project} cget -ProjectDir] $filename]
+ }
+ }
+ set filename [file normalize $filename]
+
+ # Overwrite ?
+ if {[file exists $filename]} {
+ if {[tk_messageBox \
+ -icon question \
+ -type yesno \
+ -title [mc "Overwrite file ?"] \
+ -parent .undefined_result \
+ -message [mc "Specified file does already exist,\ndo you want to overwrite it ?"]
+ ] != {yes}} then {
+ return
+ }
+ }
+
+ # Open the specified file
+ if {[catch {
+ ${::Simulator::error_dialog_project} simulator_save_error_log $filename
+ } result]} then {
+ puts stderr $result
+ tk_messageBox \
+ -type ok \
+ -icon warning \
+ -parent .undefined_result \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to access file:\n%s" $filename]
+ }
+ }
+
+ # activate the dialog
+ fsd activate
+ }
+
+ ## Wrap lines in the given text to the specified length
+ # @parm Int length - Maximum line length
+ # @parm String txt - Text to wrap
+ # @return String - Wrapped text
+ private method line_wrap {length txt} {
+ set result {}
+ foreach line [split $txt "\n"] {
+ set len [string length $line]
+ if {$len <= $length} {
+ append result $line "\n"
+ continue
+ }
+
+ while {$len > $length} {
+ append result [string range $line 0 [expr {$length - 1}]] "\n"
+ set line [string range $line $length end]
+ set len [string length $line]
+ }
+ }
+ return $result
+ }
+
+ ## Save contents of dialog "Undefined result" as plain text or XHTML
+ # Type of file depends on variable $addr_error_save_type
+ # @parm String filename - target file
+ # @return void
+ public method simulator_save_error_log {filename} {
+ set file [open $filename w]
+
+ ## SAVE AS PLAIN TEXT
+ if {$addr_error_save_type == {T}} {
+ puts -nonewline $file [line_wrap 70 [$error_dialog_textwdg get 1.0 end]]
+
+ ## SAVE AS XHTML
+ } {
+ # Local variables
+ set end [$error_dialog_textwdg index end] ;# Widget end index
+ set last_index 0 ;# Current position (by characters)
+ set line(1) 0 ;# Map of indexes ($line(num) == scalar_index)
+
+ # Create XHTML declaration and header
+ set html "<?xml version='1.0' encoding='utf-8' standalone='no'?>\n"
+ append html "<!DOCTYPE html PUBLIC\n"
+ append html "\t'-//W3C//DTD XHTML 1.1//EN'\n"
+ append html "\t'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'>\n"
+ append html "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en'>\n"
+ append html "\t<head>\n"
+ append html "\t\t<title>$filename</title>\n"
+ append html "\t\t<meta http-equiv=\"Content-Type\" content=\"application/xhtml+xml; charset=UTF-8\">\n"
+ append html "\t\t<meta name=\"Generator\" content=\"${::APPNAME}\" />\n"
+ append html "\t</head>\n"
+ append html "\t<body>\n"
+ puts -nonewline $file $html
+ set html {}
+
+ # Create map of indexes
+ for {set i 1; set j 2} {$i < $end} {incr i; incr j} {
+ # Determinate last column of the line
+ set idx [$error_dialog_textwdg index [list $i.0 lineend]]
+ regexp {\d+$} $idx idx
+
+ # Adjust map of indexes
+ incr last_index $idx
+ incr last_index
+ set line($j) $last_index
+ }
+
+ ## Determinate highlighting tag ranges
+ set ranges {}
+ foreach tag {tag_header tag_bold} {
+ # Local variables
+ set range [$error_dialog_textwdg tag ranges $tag] ;# List of tag ranges
+ set len [llength $range] ;# Number of ranges
+
+ # If the tag isn't present in the text -> skip
+ if {$len == 0} {continue}
+ # Adjust tag name
+ if {$tag == {tag_header}} {
+ set tag {h2}
+ } elseif {$tag == {tag_bold}} {
+ set tag {b}
+ }
+
+ for {set i 0} {$i < $len} {incr i} {
+ lappend ranges [list [lindex $range $i] $tag 1]
+ incr i
+ lappend ranges [list [lindex $range $i] $tag 0]
+ }
+ }
+ set ranges [lsort -command "::FileList::editor__sort_tag_ranges" $ranges]
+
+ # Write XHTML tags to plain text
+ set i 0
+ set html [$error_dialog_textwdg get 1.0 end]
+ foreach range $ranges {
+ # Local variables
+ set idx [split [lindex $range 0] {.}] ;# Text index
+ set row [lindex $idx 0] ;# Line number
+ set col [lindex $idx 1] ;# Column number
+
+ # Determinate scalar text index
+ set idx [expr {$line($row) + $col}]
+ # Skip unused tags
+ if {$idx < 0} {set idx 0}
+
+ # Deterinate string to insert
+ if {[lindex $range 2]} {
+ set tag [lindex $range 1]
+ } {
+ set tag "/[lindex $range 1]"
+ }
+
+ # Insert XHTML tag into the text
+ set char [string index $html $idx]
+ set html [string replace $html $idx $idx "<$tag>$char"]
+
+ incr i
+ }
+
+ regsub -all {\n} $html "<br />\n" html
+ append html "\n\t</body>\n"
+ append html "</html>\n"
+ puts -nonewline $file $html
+ }
+
+ close $file
+ }
+
+ ## Set flag: ignore_warnings_related_to_changes_in_SFR
+ # @parm Bool value - New value
+ # @return void
+ public method set_ignore_warnings_related_to_changes_in_SFR {value} {
+ set ignore_warnings_related_to_changes_in_SFR $value
+ }
+
+ ## Invoke simulator warning dialog "UART: Frame discarded"
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @return void
+ public method simulator_uart_invalid_stop_bit {pc line} {
+ if {$ignore_warnings_related_to_changes_in_SFR || ![$this sim_is_busy]} {
+ return
+ }
+ if {$line == {}} {
+ set line {-}
+ }
+
+ simulator_warning_dialog \
+ ignore_invalid_USB \
+ [mc "UART: Frame discarded (acording to MCS-51 manual)\n"] $pc $line
+ }
+
+ ## Invoke simulator warning dialog "UART mode has been changed while UART was engaged"
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @return void
+ public method simulator_invalid_uart_mode_change {pc line} {
+ if {$ignore_warnings_related_to_changes_in_SFR || ![$this sim_is_busy]} {
+ return
+ }
+ if {$line == {}} {
+ set line {-}
+ }
+
+ simulator_warning_dialog \
+ ignore_invalid_UMC \
+ [mc "UART mode has been changed while UART was engaged.\n"] $pc $line
+ }
+
+ ## Invoke simulator warning dialog "Timer mode has been changed while timer was running"
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @parm Int timer - Timer number (0/1/2)
+ # @return void
+ public method simulator_invalid_timer_mode_change {timer pc line} {
+ if {$ignore_warnings_related_to_changes_in_SFR || ![$this sim_is_busy]} {
+ return
+ }
+ if {$line == {}} {
+ set line {-}
+ }
+
+ simulator_warning_dialog \
+ ignore_invalid_TMC \
+ [mc "Timer mode has been changed while timer was running.\nIt is important to stop timer/counter before changing modes.\n\nTimer number: %s\n" $timer] $pc $line
+ }
+
+ ## Invoke watchdog reset dialog
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @return void
+ public method simulator_watchdog_reset {pc line} {
+ if {$line == {}} {
+ set line {-}
+ }
+
+ simulator_warning_dialog \
+ ignore_watchdog_reset \
+ [mc "WATCHDOG OVERFLOW\n"] $pc $line
+ }
+
+ ## Invokes dialog "Stack Overflow" / "Stack underflow"
+ # @parm String type - {over} == overflow; {under} == underflow
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @return void
+ public method simulator_stack_warning {type pc line} {
+ if {$line == {}} {
+ set line {-}
+ }
+ if {$type == {over}} {
+ set foo {overflow}
+ set conf_variable {ignore_stack_overflow}
+ } {
+ set foo {underflow}
+ set conf_variable {ignore_stack_underflow}
+ }
+
+ simulator_warning_dialog \
+ $conf_variable \
+ [mc "Stack $foo\n"] $pc $line
+ }
+
+ ## Invoke dialog "Invalid instruction OP code"
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @return void
+ public method simulator_invalid_instruction {pc line} {
+ $this simulator_warning_dialog \
+ ignore_invalid_ins \
+ [mc "Invalid instruction OP code\n"] $pc $line
+ }
+
+
+ ## Invoke dialog "Reading from write-only register"
+ # @parm Int addr - Register address
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @return void
+ public method simulator_reading_wr_only {addr pc line} {
+ if {$line == {}} {
+ set line {-}
+ }
+
+ simulator_warning_dialog \
+ ignore_read_from_wr_only \
+ [mc "Unable to read write-only register.\nRandom value returned.\n\nRegister:\t\t0x%s" [format %X $addr]] $pc $line
+ }
+
+ ## Invoke dialog "EEPROM programing cycle abort"
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @return void
+ public method simulator_EEPROM_WR_abort {pc line} {
+ if {$line == {}} {
+ set line {-}
+ }
+
+ simulator_warning_dialog \
+ ignore_EEPROM_WR_abort \
+ [mc "Data EEPROM write cycle aborted\n"] $pc $line
+ }
+
+ ## Invoke dialog "EEPROM write failed"
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @return void
+ public method simulator_EEPROM_WR_fail {pc line} {
+ if {$line == {}} {
+ set line {-}
+ }
+
+ simulator_warning_dialog \
+ ignore_EEPROM_WR_fail \
+ [mc "Unable to initialize EEPROM programing cycle\nbecause EEMWE, RDYBSY and WRTINH must be set\n"] $pc $line
+ }
+
+ ## Invoke dialog "Invalid return from interrupt"
+ # @parm Int pc - Value of program counter
+ # @parm Int line - Line in source code where this error occured
+ # @return void
+ public method simulator_invalid_reti_dlg {pc line} {
+ if {$line == {}} {
+ set line {-}
+ }
+
+ simulator_warning_dialog \
+ ignore_invalid_reti \
+ [mc "Invalid return from interrupt"] $pc $line
+ }
+
+ ## Invoke simulator warning dialog (like tk_messageBox)
+ # @parm String conf_variable - Configuration variable for disabling this dialog
+ # @parm String text - Text to show
+ # @parm Int pc - Value of program counter
+ # @parm List line - Line in source code where this error occured
+ # @return void
+ public method simulator_warning_dialog {conf_variable text pc line} {
+
+ # Create dialog window
+ set win {.simulator_warning_dialog}
+ if {[winfo exists $win]} {
+ destroy $win
+ }
+ toplevel $win -class {Error dialog} -bg {#EEEEEE}
+
+ ## Create dialog icon and text
+ set top_frame [frame $win.top_frame]
+ pack [label $top_frame.left \
+ -image ::ICONS::32::messagebox_critical \
+ ] -side left -padx 10
+
+ append text "\n[mc {PC:}]\t\t0x" [format %X $pc] "\n[mc {Line:}]\t\t" [lindex $line 0] "\n[mc {File:}]\t\t" [file tail [$this simulator_get_filename [lindex $line 1]]]
+ pack [label $top_frame.right \
+ -justify left \
+ -text $text \
+ ] -side left -fill x
+
+ ## Create bottom frame
+ # Checkbutton "Do not show this dialog again"
+ set bottom_frame [frame $win.bottom_frame]
+ set ::Simulator::not_again_val 0
+ pack [checkbutton $bottom_frame.not_again_checkbutton \
+ -text [mc "Do not show this dialog again"] \
+ -variable ::Simulator::not_again_val \
+ -command "::configDialogs::simulator::set_variable $conf_variable \$::Simulator::not_again_val" \
+ ] -anchor w -side left -anchor w
+ DynamicHelp::add $bottom_frame.not_again_checkbutton \
+ -text [mc "See simulator configuration dialog\nMain Menu -> Configure -> Simulator"]
+ # Button "Ok"
+ pack [ttk::button $bottom_frame.ok \
+ -image ::ICONS::16::ok \
+ -compound left \
+ -text [mc "Ok"] \
+ -command "grab release $win; destroy $win" \
+ ] -side right -anchor e
+
+ # Pack dialog fames
+ pack $top_frame -padx 5 -pady 5 -fill x -side top
+ pack $bottom_frame -padx 5 -pady 5 -fill x -side bottom
+
+ # Show dialog window
+ bell
+ focus -force $bottom_frame.ok
+ wm iconphoto $win ::ICONS::16::status_unknown
+ wm title $win [mc "Simulator warning"]
+ wm minsize $win 350 100
+ wm protocol $win WM_DELETE_WINDOW "
+ grab release $win
+ destroy $win"
+ wm transient $win .
+ wm geometry $win "+[expr {([winfo screenwidth .] - 350) / 2}]+[expr {([winfo screenheight .] - 100) / 2}]"
+ raise $win
+ catch {
+ grab $win
+ }
+ tkwait window $win
+ }
+}
diff --git a/lib/simulator/simulator_gui.tcl b/lib/simulator/simulator_gui.tcl
new file mode 100755
index 0000000..ddaba65
--- /dev/null
+++ b/lib/simulator/simulator_gui.tcl
@@ -0,0 +1,3986 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Provides graphical frontend for simulator engine (intended to be
+# used at the bottom panel). This class is part of class Simulator.
+# --------------------------------------------------------------------------
+
+# --------------------------------------------------------------------------
+# This file was modified & fixed by Kostya V. Ivanov <kostya@istcom.spb.ru>
+#
+# Special thanks to Kostya V. Ivanov !
+# --------------------------------------------------------------------------
+
+class Simulator_GUI {
+ ## COMMON
+ common count 0 ;# Counter of instances
+ common name_color {#0000DD} ;# Color for register name labels (eg. 'SP')
+ common name_nr_color {#8800DD} ;# Color for not-register name labels (eg. 'Clock')
+
+ common on_color {green} ;# Foreground color for bits in state 1 (for bit maps)
+ common off_color {red} ;# Foreground color for bits in state 0 (for bit maps)
+ # Font for bit labels (eg. 'EA')
+ common bitfont [font create \
+ -family {helvetica} \
+ -size -11 \
+ -weight bold]
+ # Same as $bitfont but underlined
+ common bitfont_under [font create \
+ -family {helvetica} \
+ -size -11 -underline 1 \
+ -weight bold]
+
+ # Color for small labels (eg. 'HEX')
+ common small_color {#5599BB}
+ # Font for small labels (eg. 'OCT')
+ common smallfont $::smallfont
+
+ common hcolor {#FFAA00} ;# Highlight foreground color for entry widgets
+ common hbcolor {#CCCCCC} ;# Highlight background color for entry widgets
+
+ # Font for other memory entries (eg. PCON)
+ common entry_font [font create -size -12 -family $::DEFAULT_FIXED_FONT -weight bold]
+
+ # Postfixes for entry text variables
+ common entry_variables {
+ B_char A_bin IP DPH T0 T1 DPL PCON P1_bin
+ P3_bin TMOD A_hex PC_dec B_oct SCON B_dec A_char TL0
+ TL1 DATA SP P0 P1 B_bin P2 P3 PC_hex
+ P0_bin P2_bin CLOCK TCON A_oct B_hex SBUFR SBUFT R0
+ R1 A_dec R2 TH0 R3 TH1 R4 IE TIME
+ R5 R6 R7 PSW AUXR1 WDTRST AUXR SPDR WatchDog
+ DP1H DP1L T2CON T2MOD RCAP2L RCAP2H TL2 TH2 WDTCON
+ EECON CLKREG ACSR IPH SADDR SADEN SPCR SPSR WDTPRG
+ CKCON SFR
+ }
+
+ ## PRIVATE
+ private variable eeprom_operation_frame {} ;# ID of the middle frame
+ private variable bottom_right_spec_frame {} ;# ID of special frame (Bottom -> Right -> Bottom)
+ private variable eeprom_progressbar {} ;# Prograssbar for special function "Writing to EEPROM"
+ private variable middle_f {} ;# ID of the middle frame
+ private variable ctrl_f {} ;# ID of frame with controlls (step, run, etc.)
+ private variable right_f {} ;# ID of the right frame
+ private variable disable_sync 0 ;# Bool: Disabled synchronization with outside enviromet
+ private variable disable_validation 1 ;# Bool: Disabled register entries validation
+ private variable Rx_validation_ena 1 ;# Bool: Enabled validation of entries R0..R7
+ private variable bitmap_hex_validation_ena 1 ;# Bool: Enabled validation of bitmap register (eg. 'IP')
+ private variable sync_AB_in_progress 0 ;# Bool: Synchronization of A or B entries in progress
+ private variable sync_Px_in_progress 0 ;# Bool: Synchronization of P0..03 entries in progress
+ private variable sync_PC_in_progress 0 ;# Bool: Synchronization of PC entries in progress
+ private variable sync_Txx_in_progress 0 ;# Bool: Synchronization of TL0/1 TH0/1 entries in progress
+ private variable sim_enabled 1 ;# Bool: Simulator engaged
+ private variable entries {} ;# List of entry widgets to enable/disable on (dis)engage
+ private variable hexeditor {} ;# Hexadecimal editor for low ram map
+ private variable scrollable_frame {} ;# Widget: Scrollable area (parent for all other widgets)
+ private variable horizontal_scrollbar {} ;# Widget: Horizontal scrollbar for scrollable area
+ private variable vertical_scrollbar {} ;# Widget: Vertical scrollbar for scrollable area
+ private variable wtd_clear_button {} ;# Widget: Watchdog clear button
+ private variable watchdog_entry {} ;# Widget: Watchdog timer entrybox
+ private variable wdt_prescaler_entry {} ;# Widget: Watchdog timer prescaler entrybox
+ private variable watchdog_onoff_switch {} ;# Widget: Label widget of Watchdog ON/OFF switch
+ private variable bitmenu {} ;# Widget: Bit popup menu for
+ private variable bit_popup_menu_args {} ;# Arguments from bit popup menu (see bit_popup_menu_setto)
+ private variable sf_registers {} ;# List of special function registers ({{addr_dec name} ... })
+ private variable sf_register_labels {} ;# List of labels for special function registers
+ private variable set_pc_by_line_button {} ;# Button: Set PC by line number
+
+ # Variables related to object initialization
+ private variable gui_initialized 0 ;# Bool: GUI created
+ private variable parent ;# Parent widget
+
+ ## PUBLIC
+ public variable Simulator_panel_parent ;# ID of parent GUI component (some frame)
+ public variable bit_in_particular_regs ;# Array of Lists: Bit in hexbitmaps, see below
+
+ ## PROTECTED
+ protected variable obj_idx ;# Object index (for creating unique GUI component descriptors)
+
+
+ ## Object constructor
+ constructor {} {
+ incr count ;# Increment instances counter
+ set obj_idx $count ;# Set object index
+ }
+
+ ## Object destructor
+ destructor {
+ # Unallocate entry text variables
+ if {$gui_initialized} {
+ SimGUI_clean_up
+ }
+ }
+
+ ## Prepare object for creating its GUI
+ # @parm Widget _parent - parent container (some frame)
+ # @return void
+ public method PrepareSimulator {_parent} {
+ set parent $_parent
+ set gui_initialized 0
+ }
+
+ ## Inform simulator panel than it has became active
+ # @return void
+ public method SimulatorTabRaised {} {
+ }
+
+ ## Initialize simulator GUI
+ # @return void
+ public method CreateSimulatorGUI {} {
+ if {$gui_initialized} {return}
+ set gui_initialized 1
+
+ # Set object variables
+ set disable_validation 1
+ set Rx_validation_ena 1
+ set bitmap_hex_validation_ena 1
+ set entries {}
+ set sf_registers {}
+ set sf_register_labels {}
+
+ ## Create scrollable area and scrollbars
+ set vertical_scrollbar [ttk::scrollbar $parent.scrollbar \
+ -orient vertical \
+ -command "$parent.right.scrollable_frame yview" \
+ ]
+ pack $vertical_scrollbar -side left -fill y
+ set parent [frame $parent.right]
+ pack $parent -side right -fill both -expand 1
+
+ set scrollable_frame [ScrollableFrame $parent.scrollable_frame \
+ -xscrollcommand "$this simulator_gui_scroll_set x" \
+ -yscrollcommand "$this simulator_gui_scroll_set y" \
+ ]
+ set horizontal_scrollbar [ttk::scrollbar \
+ $parent.horizontal_scrollbar \
+ -orient horizontal \
+ -command "$scrollable_frame xview" \
+ ]
+ pack $scrollable_frame -fill both -side bottom -expand 1
+ $scrollable_frame yview scroll 0 units
+
+ set Simulator_panel_parent [$scrollable_frame getframe]
+ set main_top_frame [frame $Simulator_panel_parent.top]
+ set main_bottom_frame [frame $Simulator_panel_parent.middle]
+
+ pack $main_top_frame -fill x -anchor w
+ pack $main_bottom_frame -fill x -anchor w
+
+
+ # Create bit popup menu
+ set bitmenu $Simulator_panel_parent.bit_menu
+ menuFactory {
+ {command {Set to 1} {} 7 "bit_popup_menu_setto 1"
+ {up0} "Set this bit to 1"}
+ {command {Set to 0} {} 7 "bit_popup_menu_setto 0"
+ {button_cancel} "Set this bit to 0"}
+ } $bitmenu 0 "$this " 0 {}
+
+ #
+ # Create left part
+ #
+
+ for {set i 0} {$i < 32} {incr i} {
+ set ::Simulator_GUI::ENV${obj_idx}_DATA($i) 0
+ }
+ set cap [lindex [$this cget -procData] 3]
+ set hg [expr {$cap / 8}]
+ if {[expr {$cap % 8}]} {
+ incr hg
+ }
+ set hexeditor [HexEditor hexeditor${obj_idx} $main_top_frame.left_frame 8 $hg 2 hex 0 1 8 $cap]
+ $hexeditor bindCellValueChanged "$this simulator_hexedit_value_changed"
+ $hexeditor bindCellLeave {help_window_hide}
+ $hexeditor bindCellEnter "$this create_help_window_ram"
+ $hexeditor bindCellMotion {help_window_show}
+ pack $main_top_frame.left_frame -side left -anchor nw -fill none -expand 0
+
+
+ #
+ # Create middle part
+ #
+
+ # Create frames of middle part
+ set middle_f [frame $main_top_frame.mid_frame]
+ set ctrl_f [frame $middle_f.ctrl_frame]
+ set sim_gregs_f [frame $middle_f.gregs_frame]
+
+ # Pack frames of middle part
+ pack $ctrl_f -fill x -padx 2
+ pack $sim_gregs_f
+ pack $middle_f -side left -fill both -anchor w
+
+ # Create controls icon bar
+ iconBarFactory $ctrl_f "X::" [string range $ctrl_f.controls_ 1 end] ::ICONS::16:: {
+ {start_stop "Initialize simulator" {launch} {__initiate_sim}
+ "Load sim file into simulator engine"}
+ {separator}
+ {reset "Reset" {rebuild} {__reset -}
+ "Perform HW reset"}
+ {separator}
+ {stepback "Step back" {undo} {__stepback}
+ "Take MCU back to state before the last instruction"}
+ {step "Step program" {goto} {__step}
+ "Step by 1 instruction"}
+ {quick_step "Step over" {goto} {__stepover}
+ "Step by 1 line of code"}
+ {animate "Animate program" {1rightarrow} {__animate}
+ "Run program and show results after each instruction"}
+ {run "Run program" {2rightarrow} {__run}
+ "Run program and show results after some time"}
+ }
+ foreach slave [pack slaves $ctrl_f] {
+ pack configure $slave -padx 0
+ }
+
+ # Create separator under controls icon bar
+ pack [ttk::separator $sim_gregs_f.mid_sep \
+ -orient horizontal \
+ ] -fill x -expand 1 -pady 2
+
+ ## Create registers: A B
+ set sim_gregs_f_AB [frame $sim_gregs_f.gregs_f_AB]
+ pack $sim_gregs_f_AB -anchor w
+
+ # Create num. base headers
+ set col 1
+ foreach base {HEX DEC BIN OCT CHAR} {
+ incr col
+ grid [label $sim_gregs_f_AB._AB_${base}_l \
+ -text [mc $base] \
+ -font $smallfont \
+ -fg $small_color -pady 0 \
+ ] -row 0 -column $col
+ }
+
+ # registers entries
+ set row 0 ;# Grid row
+ foreach reg {A B} addr {224 240} \
+ stip {{SFR 0xE0: Primary Accumulator} {SFR 0xF0: Secondary Accumulator}} {
+
+ incr row ;# Increment grid row
+ set col 1 ;# Grid column
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $sim_gregs_f_AB._${reg}_l
+
+ # Create register label
+ set label [Label $sim_gregs_f_AB._${reg}_l \
+ -text "$reg:" -fg $name_color -pady 0 \
+ -helptext [mc "Address: %s" "0x[format {%X} $addr]"] \
+ -font $bitfont \
+ ]
+ setStatusTip -widget $label -text [mc $stip]
+ # Show the label
+ grid $label -row $row -column $col
+
+ # Create and show register bitmap
+ foreach base {hex dec bin oct char } \
+ init_val {00 0 00000000 0 {} } \
+ width {2 3 8 3 2 } \
+ next_base {dec bin oct char - } \
+ prev_base {- hex dec bin oct } \
+ {
+ incr col ;# Increment column index
+
+ set ::Simulator_GUI::ENV${obj_idx}_${reg}_$base $init_val
+
+ # Register entry
+ set entry [ttk::entry $sim_gregs_f_AB._${reg}_$base \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg}_$base \
+ -validatecommand "$this sim_eval_AB $reg $base %P" \
+ -style Simulator.TEntry \
+ -font $entry_font \
+ -width $width \
+ -validate key \
+ ]
+
+ setStatusTip -widget $entry -text $stip
+ # Register register entry for disabling/enabling
+ add_entry $entry
+ # Register register entry for synchronizations
+ $this add_sfr_entry $addr $entry
+ # Show the entry
+ grid $entry -row $row -column $col
+
+ # Set entry bindings
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ if {$reg == {A}} {
+ bind $entry <Key-Down> "
+ $sim_gregs_f_AB._B_$base icursor \[$entry index insert\]
+ focus $sim_gregs_f_AB._B_$base
+ "
+ } {
+ bind $entry <Key-Up> "
+ $sim_gregs_f_AB._A_$base icursor \[$entry index insert\]
+ focus $sim_gregs_f_AB._A_$base
+ "
+ }
+ if {$next_base != {-}} {
+ bind $entry <Key-Right> "Simulator_GUI::sim_entry_right $entry $sim_gregs_f_AB._${reg}_${next_base}"
+ }
+ if {$prev_base != {-}} {
+ bind $entry <Key-Left> "Simulator_GUI::sim_entry_left $entry $sim_gregs_f_AB._${reg}_${prev_base}"
+ }
+ }
+ }
+
+ ## Create register: PSW
+ set sim_gregs_f_PSW [frame $sim_gregs_f.gregs_f_PSW]
+ pack $sim_gregs_f_PSW -anchor w
+ set ::Simulator_GUI::ENV${obj_idx}_PSW 0
+ create_bitmap_register $sim_gregs_f_PSW 1 PSW {C AC F0 RS1 RS0 OV - P} 0 {
+ {Bit address: 0xD7 -- Carry Flag}
+ {Bit address: 0xD6 -- Auxiliary Carry Flag}
+ {Bit address: 0xD5 -- Flag 0 available to the user for general purpose}
+ {Bit address: 0xD4 -- Register Bank selector bit 1}
+ {Bit address: 0xD3 -- Register Bank selector bit 0}
+ {Bit address: 0xD2 -- Overflow Flag}
+ {Bit address: 0xD1 -- Usable as a general purpose flag}
+ {Bit address: 0xD0 -- Parity flag}
+ } {SFR 0xD0: Program Status Word} {
+ {Carry Flag}
+ {Auxiliary Carry flag.\n(For BCD operations.)}
+ {Flag 0\n(Available to the user for general purposes.)}
+ {Register bank Select control bit 1. Set/cleared\nby software to determine working register bank.}
+ {Register bank Select control bit 0. Set/cleared\nby software to determine working register bank.}
+ {Overflow flag}
+ {(reserved)}
+ {Parity flag.\nSet/cleared by hardware each instruction cycle to\nindicate and odd/even number of “one” bits in the\naccumulator, i.e., even parity.}
+ }
+ # Register PSW SFR
+ lappend sf_registers [list 208 {PSW}]
+ lappend sf_register_labels $Simulator_panel_parent._PSW_l
+
+ ## Create registers: R0..R7 (of active bank)
+ set sim_gregs_f_Rx [frame $sim_gregs_f.gregs_f_Rx]
+ pack $sim_gregs_f_Rx -fill x
+
+ for {set i 7; set col 2} {$i >= 0} {incr i -1; incr col} {
+ set stip [mc "Register %s: Located in IDATA, address depends on bits RS0 and RS1 in PSW" $i]
+
+ # Create entry label (register name)
+ grid [label $sim_gregs_f_Rx._R${i}_l \
+ -text "R$i" -fg $name_color -pady 0 \
+ -font $bitfont \
+ ] -row 1 -column $col -sticky we
+ setStatusTip -widget $sim_gregs_f_Rx._R${i}_l -text $stip
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_R$i {00}
+ set entry [ttk::entry $sim_gregs_f_Rx._R${i}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_R$i \
+ -validatecommand "$this entry_Rx_validate %P $i" \
+ -font $entry_font \
+ -validate key \
+ -width 2 \
+ ]
+
+ # Show the entry
+ grid $entry -row 2 -column $col
+ # Register register entry for disabling/enabling
+ add_entry $entry
+ # Set entry default value
+ set ::Simulator_GUI::ENV${obj_idx}_R$i {00}
+ # Register register entry for synchronizations
+ $this add_sfr_entry R$i $entry
+
+ # Set entry bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide}
+ bind $entry <Enter> "$this create_help_window_Rx $i; Sbar -freeze {$stip}"
+ bind $entry <FocusIn> "$this unmark_entry R$i"
+ if {$i != 0} {
+ bind $entry <Key-Right> \
+ "Simulator_GUI::sim_entry_right $entry $sim_gregs_f_Rx._R[expr {$i-1}]_e"
+ }
+ if {$i != {7}} {
+ bind $entry <Key-Left> \
+ "Simulator_GUI::sim_entry_left $entry $sim_gregs_f_Rx._R[expr {$i+1}]_e"
+ }
+
+ grid columnconfigure $sim_gregs_f_Rx $col -weight 1
+ }
+
+ #
+ # Create right part
+ #
+
+ # Create and pack frame
+ set right_f [frame $main_top_frame.right_frame]
+ pack $right_f -side left -fill both -anchor nw
+
+ ## FRAME 0 (timers + interrupt)
+ set frame0 [frame $right_f.frame0]
+ pack $frame0 -side left -anchor nw
+
+ # Create timers frame (hexadecimal entries and bitmaps)
+ set timers_frame [ttk::labelframe $frame0.timers_f \
+ -padding 2 \
+ -labelwidget [label $frame0.timers_lbl -text "TIMERS 0 & 1" -font $smallfont -pady 0]]
+ pack $timers_frame -anchor nw -fill x
+
+ # Create frame for hexadecimal entries: TH1 TL1 TH0 TL0
+ set timers_values_f [frame $timers_frame.timers_values_f]
+ pack $timers_values_f -anchor nw -fill x
+
+ # Create hexadecimal entries for registers: TH1 TL1 TH0 TL0
+ set col 0 ;# Grid column
+ foreach reg {TH1 TL1 TH0 TL0} addr {141 139 140 138} \
+ stip {
+ {SFR 0x8D: 2nd part of 16-bit counting register for timer 1}
+ {SFR 0x8B: 1st part of 16-bit counting register for timer 1}
+ {SFR 0x8C: 2nd part of 16-bit counting register for timer 0}
+ {SFR 0x8A: 1nd part of 16-bit counting register for timer 0}
+ } {
+ incr col ;# Increment grid column
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $timers_values_f._${reg}_l
+
+ # Create register name label
+ grid [label $timers_values_f._${reg}_l \
+ -text $reg -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row 1 -column $col
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $timers_values_f._Txx${col}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -validatecommand "$this validate_Txx $reg %P" \
+ -font $entry_font \
+ -validate key \
+ -width 2 \
+ ]
+
+ # Show and register created memory cell
+ grid $entry -row 2 -column $col
+ add_entry $entry
+ $this add_sfr_entry $addr $entry
+
+ # Set entry event bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+ bind $entry <Key-Right> \
+ "Simulator_GUI::sim_entry_right $entry $timers_values_f._Txx[expr {$col+1}]_e"
+ if {$col != {1}} {
+ bind $entry <Key-Left> \
+ "Simulator_GUI::sim_entry_left $entry $timers_values_f._Txx[expr {$col-1}]_e"
+ }
+ }
+
+ # Create decimal entries for timers
+ foreach reg {T1 T0} addresses {{141 139} {140 138}} \
+ stip {
+ {SFR 0x8D..0x8B: 16-bit counting register for timer 1}
+ {SFR 0x8C..0x8A: 16-bit counting register for timer 0}
+ } {
+ incr col ;# Increment grid column
+
+ # Create register name label
+ grid [label $timers_values_f._${reg}_l \
+ -text $reg -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row 1 -column $col
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $timers_values_f._Txx${col}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 5 \
+ -validate key \
+ -validatecommand "$this validate_Txx $reg %P" \
+ -font $entry_font \
+ ]
+ setStatusTip -widget $entry -text [mc $stip]
+
+ # Show and register created memory cell
+ grid $entry -row 2 -column $col
+ add_entry $entry
+
+ # Set entry event bindings
+ bind $entry <Key-Right> \
+ "Simulator_GUI::sim_entry_right $entry $timers_values_f._Txx[expr {$col+1}]_e"
+ bind $entry <Key-Left> \
+ "Simulator_GUI::sim_entry_left $entry $timers_values_f._Txx[expr {$col-1}]_e"
+ foreach addr $addresses {
+ $this add_sfr_entry $addr $entry
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ }
+ }
+
+ # Create frame for registers: TCON TMOD (bitmaps)
+ set timers_frame_reg [frame $timers_frame.timers_reg_f]
+ pack $timers_frame_reg -anchor nw
+ # Create TCON and TMOD bitmaps
+ create_bitmap_register $timers_frame_reg 1 TCON {TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0} 1 {
+ {Bit address: 0x8F -- Timer 1 overflow flag}
+ {Bit address: 0x8E -- Timer 1 run control bit}
+ {Bit address: 0x8D -- Timer 0 overflow flag}
+ {Bit address: 0x8C -- Timer 0 run control bit}
+ {Bit address: 0x8B -- External Interrupt 1 edge flag}
+ {Bit address: 0x8A -- Interrupt 1 type control bit}
+ {Bit address: 0x89 -- External Interrupt 0 edge flag}
+ {Bit address: 0x88 -- Interrupt 0 type control bit}
+ } {SFR 0x88: Timer/Counter control register} {
+ {Timer 1 Overflow Flag\nCleared by hardware when processor vectors to interrupt routine.\nSet by hardware on timer/counter overflow, when the timer 1 register overflows.}
+ {Timer 1 Run Control Bit\nClear to turn off timer/counter 1.\nSet to turn on timer/counter 1.}
+ {Timer 0 Overflow Flag\nCleared by hardware when processor vectors to interrupt routine.\nSet by hardware on timer/counter overflow, when the timer 0 register overflows.}
+ {Timer 0 Run Control Bit\nClear to turn off timer/counter 0.\nSet to turn on timer/counter 0.}
+ {Interrupt 1 Edge Flag\nCleared by hardware when interrupt is processed if edge-triggered (see IT1).\nSet by hardware when external interrupt is detected on INT1# pin.}
+ {Interrupt 1 Type Control Bit\nClear to select low level active (level triggered) for external interrupt 1 (INT1#).\nSet to select falling edge active (edge triggered) for external interrupt 1.}
+ {Interrupt 0 Edge Flag\nCleared by hardware when interrupt is processed if edge-triggered (see IT0).\nSet by hardware when external interrupt is detected on INT0# pin.}
+ {Interrupt 0 Type Control Bit\nClear to select low level active (level triggered) for external interrupt 0 (INT0#).\nSet to select falling edge active (edge triggered) for external interrupt 0.}
+ }
+ create_bitmap_register $timers_frame_reg 2 TMOD {G1 CT1 M11 M10 G0 CT0 M01 M00} 1 {
+ {Timer 1 Gating Control Bit}
+ {Timer 1 Counter/Timer Select Bit}
+ {Timer 1 Mode Select Bit}
+ {Timer 1 Mode Select Bit}
+ {Timer 0 Gating Control Bit}
+ {Timer 0 Counter/Timer Select Bit}
+ {Timer 0 Mode Select Bit}
+ {Timer 0 Mode Select Bit}
+ } {SFR 0x89: Timer/Counter mode control register} {
+ {Timer 1 Gating Control Bit\nClear to enable timer 1 whenever the TR1 bit is set.\nSet to enable timer 1 only while the INT1# pin is high and TR1 bit is set.}
+ {Timer 1 Counter/Timer Select Bit\nClear for timer operation: timer 1 counts the divided-down system clock.\nSet for Counter operation: timer 1 counts negative transitions on external pin T1.}
+ {Timer 1 Mode Select Bits\nM11\tM01\tOperating mode\n 0\t 0\tMode 0: 8-bit timer/counter (TH1) with 5-bit prescaler (TL1).\n 0\t 1\tMode 1: 16-bit timer/counter.\n 1\t 0\tMode 2: 8-bit auto-reload timer/counter (TL1). Reloaded from TH1 at overflow.\n 1\t 1\tMode 3: timer 1 halted. Retains count.}
+ {Timer 1 Mode Select Bits\nM11\tM01\tOperating mode\n 0\t 0\tMode 0: 8-bit timer/counter (TH1) with 5-bit prescaler (TL1).\n 0\t 1\tMode 1: 16-bit timer/counter.\n 1\t 0\tMode 2: 8-bit auto-reload timer/counter (TL1). Reloaded from TH1 at overflow.\n 1\t 1\tMode 3: timer 1 halted. Retains count.}
+ {Timer 0 Gating Control Bit\nClear to enable timer 0 whenever the TR0 bit is set.\nSet to enable timer/counter 0 only while the INT0# pin is high and the TR0 bit is set.}
+ {Timer 0 Counter/Timer Select Bit\nClear for timer operation: timer 0 counts the divided-down system clock.\nSet for counter operation: timer 0 counts negative transitions on external pin T0.}
+ {Timer 0 Mode Select Bit\nM1\tM0\tOperating mode\n 0\t 0\tMode 0: 8-bit timer/counter (TH0) with 5-bit prescaler (TL0).\n 0\t 1\tMode 1: 16-bit timer/counter.\n 1\t 0\tMode 2: 8-bit auto-reload timer/counter (TL0). Reloaded from TH0 at overflow.\n 1\t 1\tMode 3: TL0 is an 8-bit timer/counter.\nTH0 is an 8-bit timer using timer 1’s TR0 and TF0 bits.}
+ {Timer 0 Mode Select Bit\nM10\tM00\tOperating mode\n 0\t 0\tMode 0: 8-bit timer/counter (TH0) with 5-bit prescaler (TL0).\n 0\t 1\tMode 1: 16-bit timer/counter.\n 1\t 0\tMode 2: 8-bit auto-reload timer/counter (TL0). Reloaded from TH0 at overflow.\n 1\t 1\tMode 3: TL0 is an 8-bit timer/counter.\nTH0 is an 8-bit timer using timer 1’s TR0 and TF0 bits.}
+ }
+
+ # Create hexadecimal entries for registers: TCON TMOD
+ foreach reg {TCON TMOD} \
+ addr {136 137} \
+ bits {{TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0} {G1 CT1 M11 M10 G0 CT0 M01 M00}} \
+ stip {
+ {SFR 0x88: Timer/Counter control register}
+ {SFR 0x89: Timer/Counter mode control register}
+ } {
+ incr col ;# Increment grid column
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $Simulator_panel_parent._${reg}_l
+
+ # Create register name label
+ grid [label $timers_values_f._${reg}_hex_l \
+ -text $reg -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row 1 -column $col
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $timers_values_f._Txx${col}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this validate_hex_bitmap_reg %P $reg" \
+ -font $entry_font \
+ ]
+ set bit_in_particular_regs($reg) $bits
+
+ # Show and register created memory cell
+ grid $entry -row 2 -column $col
+ $this add_sfr_entry $addr $entry
+ add_entry $entry
+
+ # Set entry event bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+ if {$reg != {TMOD}} {
+ bind $entry <Key-Right> \
+ "Simulator_GUI::sim_entry_right $entry $timers_values_f._Txx[expr {$col+1}]_e"
+ }
+ bind $entry <Key-Left> \
+ "Simulator_GUI::sim_entry_left $entry $timers_values_f._Txx[expr {$col-1}]_e"
+ }
+
+ # Create frame for interrupt control registers (IE and IP)
+ set interrupt_frame [ttk::labelframe $frame0.interrupt_f \
+ -padding 2 \
+ -labelwidget [label $frame0.int_lbl -text "INTERRUPTS" -font $smallfont -pady 0]]
+ pack $interrupt_frame -anchor nw -fill x
+
+ # Create IE, IP bitmaps
+ if {[$this get_feature_avaliable t2]} {
+ set et2 {ET2}
+ set pt2 {PT2}
+ set et2_stip {Bit address: 0xAD -- Enable or disable the Timer 2 overflow interrupt}
+ set pt2_stip {Bit address: 0xBD -- Defines the Timer 2 interrupt priority level}
+ set et2_ttip {Timer 2 interrupt enable bit}
+ set pt2_ttip {Timer 2 interrupt priority bit}
+ } {
+ set et2 {-}
+ set pt2 {-}
+ set et2_stip {Bit address: 0xAD -- Not implemented}
+ set pt2_stip {Bit address: 0xBD -- Not implemented}
+ set et2_ttip {Not implemented}
+ set pt2_ttip {Not implemented}
+ }
+ if {[$this get_feature_avaliable uart]} {
+ set es {ES}
+ set ps {PS}
+ set es_stip {Bit address: 0xAC -- Enable or disable the serial port interrupt}
+ set ps_stip {Bit address: 0xBC -- Defines the Serial Port interrupt priority level}
+ set es_ttip {Serial Port interrupt enable bit}
+ set ps_ttip {Serial Port interrupt priority bit}
+ } {
+ set es {-}
+ set ps {-}
+ set es_stip {Bit address: 0xAD -- Not implemented}
+ set ps_stip {Bit address: 0xBC -- Not implemented}
+ set es_ttip {Not implemented}
+ set ps_ttip {Not implemented}
+ }
+ if {[$this get_feature_avaliable acomparator]} {
+ set ec {EC}
+ set pc {PC}
+ set ec_stip {Bit address: 0xAE -- Enable or disable the comparator interrupt}
+ set pc_stip {Bit address: 0xBE -- Defines the comparator interrupt priority level}
+ set ec_ttip {EC Comparator Interrupt Enable bit}
+ set pc_ttip {Comparator Interrupt Priority bit}
+ } {
+ set ec {-}
+ set pc {-}
+ set ec_stip {Bit address: 0xAE -- Not implemented}
+ set pc_stip {Bit address: 0xBE -- Not implemented}
+ set ec_ttip {Not implemented}
+ set pc_ttip {Not implemented}
+ }
+ create_bitmap_register $interrupt_frame 1 IE [list EA $ec $et2 $es ET1 EX1 ET0 EX0] 1 [list \
+ {Bit address: 0xAF -- Disables all interrupts} \
+ $ec_stip \
+ $et2_stip \
+ $es_stip \
+ {Bit address: 0xAB -- Enable or disable the Timer 1 overflow interrupt} \
+ {Bit address: 0xAA -- Enable or disable External Interrupt 1} \
+ {Bit address: 0xA9 -- Enable or disable the Timer 0 overflow interrupt} \
+ {Bit address: 0xA8 -- Enable or disable External Interrupt 0} \
+ ] {SFR 0xA8: Interrupt enable register} [list \
+ {Global disable bit. If EA = O, all Interrupts are disabled. If EA = 1, each interrupt can be\nindividually enabled or disabled by setting or clearing its enable bit.} \
+ $ec_ttip \
+ $et2_ttip \
+ $es_ttip \
+ {Timer 1 interrupt enable bit.} \
+ {External interrupt 1 enable bit.} \
+ {Timer 0 interrupt enable bit.} \
+ {External interrupt O enable bit.} \
+ ]
+ create_bitmap_register $interrupt_frame 2 IP [list - $pc $pt2 $ps PT1 PX1 PT0 PX0] 1 [list \
+ {Bit address: 0xBF -- Not implemented} \
+ $pc_stip \
+ $pt2_stip \
+ $ps_stip \
+ {Bit address: 0xBB -- Defines the Timer 1 interrupt priority level} \
+ {Bit address: 0xBA -- Defines External Interrupt 1 priority level} \
+ {Bit address: 0xB9 -- Defines the Timer 0 interrupt priority level} \
+ {Bit address: 0xB8 -- Defines the External Interrupt 0 priority level} \
+ ] {SFR 0xB8: Interrupt priority register} [list \
+ {Not implemented} \
+ $pc_ttip \
+ $pt2_ttip \
+ $ps_ttip \
+ {Timer 1 interrupt priority bit} \
+ {External interrupt 1 priority bit} \
+ {Timer 0 interrupt priority bit} \
+ {External interrupt 0 priority bit} \
+ ]
+
+ # Create BITMAP//HEX vertical separator
+ grid [ttk::separator $interrupt_frame._IE_IP_sep \
+ -orient vertical \
+ ] \
+ -row 1 \
+ -column 11 \
+ -rowspan 2 \
+ -sticky ns \
+ -padx 5
+
+ # Create IE, IP hexadecimal entries
+ set row 0 ;# Grid row
+ foreach reg {IE IP} \
+ addr {168 184} \
+ bits [list \
+ [list EA $ec $et2 $es ET1 EX1 ET0 EX0] \
+ [list - $pc $pt2 $ps PT1 PX1 PT0 PX0] \
+ ] \
+ stip {
+ {SFR 0xA8: Interrupt enable register}
+ {SFR 0xB8: Interrupt priority register}
+ } {
+ incr row ;# Increment grid row
+
+ # Create register name label
+ grid [label $interrupt_frame._${reg}_hex_l \
+ -padx 0 -text {HEX} -fg $small_color -font $smallfont \
+ ] -row $row -column 12
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $Simulator_panel_parent._${reg}_l
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $interrupt_frame._${reg}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this validate_hex_bitmap_reg %P $reg" \
+ -font $entry_font \
+ ]
+ set bit_in_particular_regs($reg) $bits
+
+ # Show and register created memory cell
+ grid $entry -row $row -column 13 -padx 5
+ add_entry $entry
+ $this add_sfr_entry $addr $entry
+
+ # Set entry event bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+ }
+
+ # Finalize entry event bindings for IE and IP
+ bind $interrupt_frame._IP_e <Key-Up> "
+ focus $interrupt_frame._IE_e
+ $interrupt_frame._IE_e icursor \[$interrupt_frame._IP_e index insert\]"
+ bind $interrupt_frame._IE_e <Key-Down> "
+ focus $interrupt_frame._IP_e
+ $interrupt_frame._IP_e icursor \[$interrupt_frame._IE_e index insert\]"
+
+ ## FRAME 1
+ set frame1 [frame $right_f.frame1]
+ pack $frame1 -side left -anchor nw -padx 2
+
+ # FRAME 1 - TOP
+ set frame1_top [frame $frame1.frame1_top]
+ pack $frame1_top -anchor nw
+
+ # FRAME 1 - TOP - LEFT
+ set frame1_top_left [frame $frame1_top.frame1_top_left]
+ pack $frame1_top_left -anchor nw -side left
+
+ # FRAME 1 - TOP - RIGHT
+ set frame1_top_right [frame $frame1_top.frame1_top_right]
+ pack $frame1_top_right -anchor nw -side right -padx 5
+
+ # FRAME 1 - BOTTOM
+ set frame1_bottom [frame $frame1.frame1_bottom]
+ pack $frame1_bottom -anchor nw
+
+ ## Create entries for registers P0..P4
+ # Create num. base headers
+ set col 1
+ foreach txt {BIN HEX} {
+ incr col
+ grid [label $frame1_top_left._${txt}_l \
+ -text $txt -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row 0 -column $col
+ }
+ # Create register binary and hexadecimal entries (P0..P3)
+ set row 0 ;# Grid row
+ set regs {} ;# Port registers
+ set addrs {} ;# Register addresses
+ set stips {} ;# Status bar tips
+ foreach reg {P0 P1 P2 P3 P4} addr {128 144 160 176 192} stip {0 1 2 3 4} {
+ if {[$this get_feature_avaliable [string tolower $reg]]} {
+ lappend regs $reg
+ lappend addrs $addr
+ lappend stips [mc "SFR 0x%s: Latch of port %s" [symb_name_to_hex_addr $reg] $stip]
+ }
+ }
+ foreach reg $regs addr $addrs stip $stips {
+ incr row ;# Increment grid row
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $frame1_top_left._${reg}_l
+
+ # Create register name labels
+ grid [label $frame1_top_left._${reg}_l \
+ -text "$reg:" -fg $name_color -pady 0 \
+ -font $bitfont \
+ ] -row $row -column 1
+ setStatusTip -widget $frame1_top_left._${reg}_l -text $stip
+
+ # Create binary entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg}_bin {11111111}
+ set entry0 [ttk::entry $frame1_top_left._Pxx${row}_bin_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg}_bin \
+ -width 8 \
+ -validate key \
+ -validatecommand "$this sim_eval_Px $reg bin %P" \
+ -font $entry_font \
+ ]
+
+ # Show and register created memory cell
+ grid $entry0 -row $row -column 2
+ add_entry $entry0
+ $this add_sfr_entry $addr $entry0
+
+ # Set entry event bindings
+ bind $entry0 <FocusIn> "$this unmark_entry $addr"
+ setStatusTip -widget $entry0 -text $stip
+ if {$row != 1} {
+ bind $entry0 <Key-Up> "
+ $frame1_top_left._Pxx[expr {$row-1}]_bin_e icursor \[$entry0 index insert\]
+ focus $frame1_top_left._Pxx[expr {$row-1}]_bin_e"
+ }
+ if {$row != 4} {
+ bind $entry0 <Key-Down> "
+ $frame1_top_left._Pxx[expr {$row+1}]_bin_e icursor \[$entry0 index insert\]
+ focus $frame1_top_left._Pxx[expr {$row+1}]_bin_e"
+ }
+
+ # Create hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {FF}
+ set entry1 [ttk::entry $frame1_top_left._Pxx${row}_hex_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this sim_eval_Px $reg hex %P" \
+ -font $entry_font \
+ ]
+
+ # Show and register created memory cell
+ grid $entry1 -row $row -column 3
+ add_entry $entry1
+ $this add_sfr_entry $addr $entry1
+
+ # Set entry event bindings
+ bind $entry1 <Motion> {help_window_show %X %Y}
+ bind $entry1 <Leave> {Sbar {}; help_window_hide}
+ bind $entry1 <FocusIn> "$this unmark_entry $addr"
+ bind $entry1 <Enter> "$this create_help_window_ram $reg; Sbar -freeze {$stip}"
+ if {$row != 1} {
+ bind $entry1 <Key-Up> "
+ $frame1_top_left._Pxx[expr {$row-1}]_hex_e icursor \[$entry1 index insert\]
+ focus $frame1_top_left._Pxx[expr {$row-1}]_hex_e"
+ }
+ if {$row != 4} {
+ bind $entry1 <Key-Down> "
+ $frame1_top_left._Pxx[expr {$row+1}]_hex_e icursor \[$entry1 index insert\]
+ focus $frame1_top_left._Pxx[expr {$row+1}]_hex_e"
+ }
+ bind $entry0 <Key-Right> \
+ "Simulator_GUI::sim_entry_right $entry0 $entry1"
+ bind $entry1 <Key-Left> \
+ "Simulator_GUI::sim_entry_left $entry1 $entry0"
+ }
+
+ ### Create bottom frame widgets (PCON SCON)
+ ## Create register bitmaps
+ # - PCON
+ if {[$this get_feature_avaliable pof]} {
+ set POF {POF}
+ set pof_statusTip {Power Off Flag}
+ set pof_tooltip {Power-Off Flag\nCleared to recognize next reset type.\nSet by hardware when VCC rises from 0 to its nominal voltage. Can also be set by software.}
+ } {
+ set POF {-}
+ set pof_statusTip {Not implemented}
+ set pof_tooltip {Not implemented}
+ }
+ if {[$this get_feature_avaliable gf1]} {
+ set GF1 {GF1}
+ set gf1_statusTip {General purpose flag bit}
+ set gf1_tooltip {General purpose Flag\nCleared by user for general purpose usage.\nSet by user for general purpose usage.}
+ } {
+ set GF1 {-}
+ set gf1_statusTip {Not implemented}
+ set gf1_tooltip {Not implemented}
+ }
+ if {[$this get_feature_avaliable gf0]} {
+ set GF0 {GF0}
+ set gf0_statusTip {General purpose flag bit}
+ set gf0_tooltip {General purpose Flag\nCleared by user for general purpose usage.\nSet by user for general purpose usage.}
+ } {
+ set GF0 {-}
+ set gf0_statusTip {Not implemented}
+ set gf0_tooltip {Not implemented}
+ }
+ if {[$this get_feature_avaliable pd]} {
+ set PD {PD}
+ set pd_statusTip {Power down bit}
+ set pd_tooltip {Power-Down mode bit\nCleared by hardware when reset occurs.\nSet to enter power-down mode.}
+ } {
+ set PD {-}
+ set pd_statusTip {Not implemented}
+ set pd_tooltip {Not implemented}
+ }
+ if {[$this get_feature_avaliable idl]} {
+ set IDL {IDL}
+ set idl_statusTip {Idle mode bit}
+ set idl_tooltip {Idle mode bit\nCleared by hardware when interrupt or reset occurs.\nSet to enter idle mode.}
+ } {
+ set IDL {-}
+ set idl_statusTip {Not implemented}
+ set idl_tooltip {Not implemented}
+ }
+ if {[$this get_feature_avaliable uart]} {
+ set SMOD1 {SMOD}
+ set smod1_statusTip {Double baud rate bit}
+ set smod1_tooltip {Serial port Mode bit 1 for UART\nSet to select double baud rate in mode 1, 2 or 3.}
+ if {[$this get_feature_avaliable smod0]} {
+ append SMOD1 {1}
+ set SMOD0 {SMOD0}
+ set smod0_statusTip {Frame Error Select}
+ set smod0_tooltip {Frame Error Select. When SMOD0 = 0, SCON.7 is SM0. When SMOD0 = 1, SCON.7 is FE.\nNote that FE will be set after a frame error\nregardless of the state of SMOD0.}
+ } {
+ set SMOD0 {-}
+ set smod0_statusTip {Not implemented}
+ set smod0_tooltip {Not implemented}
+ }
+ } {
+ set SMOD1 {-}
+ set smod1_statusTip {Not implemented}
+ set smod1_tooltip {Not implemented}
+ set SMOD0 {-}
+ set smod0_statusTip {Not implemented}
+ set smod0_tooltip {Not implemented}
+ }
+ if {[$this get_feature_avaliable pwm]} {
+ set PWMEN {PWMEN}
+ set pwmen_stip {Pulse Width Modulation Enable}
+ set pwmen_ttip {Pulse Width Modulation Enable. When PWMEN = 1, Timer 0 and Timer 1 are\nconfigured as an 8-bit PWM counter with 8-bit auto-reload prescaler.\nThe PWM outputs on T1 (P3.5).}
+ } {
+ set PWMEN {-}
+ set pwmen_stip {Not implemented}
+ set pwmen_ttip {Not implemented}
+ }
+ create_bitmap_register $frame1_bottom 1 PCON [list $SMOD1 $SMOD0 $PWMEN $POF $GF1 $GF0 $PD $IDL] 1 [list \
+ $smod1_statusTip \
+ $smod0_statusTip \
+ $pwmen_stip \
+ $pof_statusTip \
+ $gf1_statusTip \
+ $gf0_statusTip \
+ $pd_statusTip \
+ $idl_statusTip \
+ ] {SFR 0x87: Power control register} [list \
+ $smod1_tooltip \
+ $smod0_tooltip \
+ $pwmen_ttip \
+ $pof_tooltip \
+ $gf1_tooltip \
+ $gf0_tooltip \
+ $pd_tooltip \
+ $idl_tooltip \
+ ]
+ # - SCON
+ if {[$this get_feature_avaliable uart]} {
+ create_bitmap_register $frame1_bottom 2 SCON {SM0 SM1 SM2 REN TB8 RB8 TI RI} 1 {
+ {Bit address: 0x9F -- Serial Port mode specifier}
+ {Bit address: 0x9E -- Serial Port mode specifier}
+ {Bit address: 0x9D -- Enables the multiprocessor communication feature}
+ {Bit address: 0x9C -- Enable/Disable reception}
+ {Bit address: 0x9B -- The 9th bit that will be transmitted in modes 2 and 3}
+ {Bit address: 0x9A -- Receiver Bit 8}
+ {Bit address: 0x99 -- Transmit interrupt flag}
+ {Bit address: 0x98 -- Receive interrupt flag}
+ } {SFR 0x98: Serial port control register} {
+ {Serial port Mode bit 0\nRefer to SM1 for serial port mode selection.\nSMOD0 must be cleared to enable access to the SM0 bit}
+ {Serial port Mode bit 1\nSM0\tSM1\tMode\tDescription\t\tBaud Rate\n0\t0\t0\tShift Register\tFCPU PERIPH/6\n0\t1\t1\t8-bit UART\tVariable\n1\t0\t2\t9-bit UART\tFCPU PERIPH /32 or /16\n1\t1\t3\t9-bit UART\tVariable}
+ {Serial port Mode 2 bit / Multiprocessor Communication Enable bit\nClear to disable multiprocessor communication feature.\nSet to enable multiprocessor communication feature in mode 2 and 3, and eventually mode 1. This bit should be\ncleared in mode 0}
+ {Reception Enable bit\nClear to disable serial reception.\nSet to enable serial reception.}
+ {Transmitter Bit 8 / Ninth bit to transmit in modes 2 and 3.\no transmit a logic 0 in the 9th bit.\nSet to transmit a logic 1 in the 9th bit.}
+ {Receiver Bit 8 / Ninth bit received in modes 2 and 3\nCleared by hardware if 9th bit received is a logic 0.\nSet by hardware if 9th bit received is a logic 1.\nIn mode 1, if SM2 = 0, RB8 is the received stop bit. In mode 0 RB8 is not used.}
+ {Transmit Interrupt flag\nClear to acknowledge interrupt.\nSet by hardware at the end of the 8th bit time in mode 0 or at the beginning of the stop bit in the other modes.}
+ {Receive Interrupt flag\nClear to acknowledge interrupt.\nSet by hardware at the end of the 8th bit time in mode 0, see Figure 2-26. and Figure 2-27. in the other modes.}
+ }
+
+ # Create bit FE (Frame error)
+ if {[$this get_feature_avaliable smod0]} {
+ set FE_frm [frame $frame1_bottom._SCON_SM0_FE_frm]
+
+ grid forget $Simulator_panel_parent._SCON_SM0
+ grid $FE_frm -row 2 -column 2
+
+ $Simulator_panel_parent._SCON_SM0 configure -padx 0 -bd 0
+ bind $Simulator_panel_parent._SCON_SM0 <Button-1> "$this sim_invert SM0 0 SCON 1"
+ bind $Simulator_panel_parent._SCON_SM0 <ButtonRelease-3> "$this bit_popup_menu SM0 0 SCON 1 %X %Y"
+
+ set label [label $Simulator_panel_parent._SCON_FE \
+ -text {FE} -fg $off_color -cursor hand1 \
+ -bd 0 -font $bitfont -pady 0 -padx 0 \
+ ]
+ pack $label -in $FE_frm -side left
+ pack [label $Simulator_panel_parent._SCON_SM0_FE_slash_label \
+ -text {|} -font $bitfont -padx 0 -bd 0 \
+ ] -in $FE_frm -side left
+ pack $Simulator_panel_parent._SCON_SM0 -in $FE_frm -side left
+
+
+ setStatusTip -widget $label -text {Bit address: 0x9F -- Framing Error bit}
+ bind $label <Enter> {+%W configure -font $::Simulator_GUI::bitfont_under}
+ bind $label <Leave> {+%W configure -font $::Simulator_GUI::bitfont}
+ DynamicHelp::add $label -text [subst {Clear to reset the error state, not cleared by a valid stop bit.\nSet by hardware when an invalid stop bit is detected.\nSMOD0 must be set to enable access to the FE bit}]
+
+ # Register bit label
+ bind $label <Button-1> "$this sim_invert FE 0 SCON 1"
+ bind $label <ButtonRelease-3> "$this bit_popup_menu FE 0 SCON 1 %X %Y"
+ set ::Simulator_GUI::ENV${obj_idx}_SFR(FE) 0
+ }
+ }
+
+ # Create BITMAP//HEX vertical separator
+ grid [ttk::separator $frame1_bottom._PCON_SCON_sep \
+ -orient vertical \
+ ] \
+ -row 1 \
+ -column 11 \
+ -rowspan 2 \
+ -sticky ns
+
+ # Create hexadecimal entries for registers: PCON SCON
+ set row 0 ;# Grid row
+ foreach reg {PCON SCON} \
+ addr {135 152} \
+ bits [list [list $SMOD1 $SMOD0 $PWMEN $POF $GF1 $GF0 $PD $IDL] {- SM1 SM2 REN TB8 RB8 TI RI}] \
+ stip {
+ {SFR 0x87: Power control register}
+ {SFR 0x98: Serial port control register}
+ } {
+ incr row ;# Increment grid row
+ if {$reg == {SCON} && ![$this get_feature_avaliable uart]} {
+ continue
+ }
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $Simulator_panel_parent._${reg}_l
+
+ # Create register name labels
+ grid [label $frame1_bottom._${reg}_hex_l \
+ -text {HEX} -fg $small_color -font $smallfont \
+ ] -row $row -column 12
+ setStatusTip -widget $frame1_bottom._${reg}_hex_l -text [mc $stip]
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $frame1_bottom._${reg}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this validate_hex_bitmap_reg %P $reg" \
+ -font $entry_font \
+ ]
+ set bit_in_particular_regs($reg) $bits
+
+ # Show and register created memory cell
+ grid $entry -row $row -column 13
+ add_entry $entry
+ $this add_sfr_entry $addr $entry
+
+ # Set entry event bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+ }
+
+ # Finalize entry event bindings for SCON and PCON
+ bind $frame1_bottom._SCON_e <Key-Up> "
+ focus $frame1_bottom._PCON_e
+ $frame1_bottom._PCON_e icursor \[$frame1_bottom._SCON_e index insert\]"
+ bind $frame1_bottom._PCON_e <Key-Down> "
+ focus $frame1_bottom._SCON_e
+ $frame1_bottom._SCON_e icursor \[$frame1_bottom._PCON_e index insert\]"
+
+
+ # FRAME 1 - TOP - RIGHT - 0 (DTPR SP // Clock | SBUF // PC)
+ set frame1_top_right_0 [frame $frame1_top_right.frame1_top_right_0]
+ pack $frame1_top_right_0 -anchor nw
+
+ # Create label "DPTR:"
+ if {
+ [$this get_feature_avaliable {ddp}]
+ &&
+ ![$this get_feature_avaliable {hddptr}]
+ } then {
+ set text {DPTR0:}
+ } else {
+ set text {DPTR:}
+ }
+ grid [label $frame1_top_right_0._DPTR_l \
+ -text $text -fg $name_color -pady 0 \
+ -font $bitfont \
+ ] -row 2 -column 0
+
+ # Create label "Hex"
+ grid [label $frame1_top_right_0._SP_SBUF_l \
+ -text {HEX} -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row 1 -column 5
+
+ # Create hexadecimal entries for registers: DP0H DP0L
+ set col 0 ;# Grid column
+ foreach reg {DPH DPL} addr {131 130} \
+ stip {
+ {SFR 0x83: Data pointer register}
+ {SFR 0x82: Data pointer register}
+ } {
+ incr col ;# Increment grid column
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $frame1_top_right_0._DPTR_l
+
+ # Create register name label
+ grid [label $frame1_top_right_0._${reg}_l \
+ -text $reg -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row 1 -column $col
+ setStatusTip -widget $frame1_top_right_0._${reg}_l -text [mc $stip]
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $frame1_top_right_0._${reg}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this entry_2_hex_validate_and_sync %P $reg" \
+ -font $entry_font \
+ ]
+
+ # Show and register created memory cell
+ grid $entry -row 2 -column $col
+ add_entry $entry
+ $this add_sfr_entry $addr $entry
+
+ # Set entry event bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+ }
+
+ # Finalize entry event bindings for DPH and DPL
+ bind $frame1_top_right_0._DPH_e <Key-Right> \
+ "Simulator_GUI::sim_entry_right $frame1_top_right_0._DPH_e $frame1_top_right_0._DPL_e"
+ bind $frame1_top_right_0._DPL_e <Key-Left> \
+ "Simulator_GUI::sim_entry_left $frame1_top_right_0._DPL_e $frame1_top_right_0._DPH_e"
+ if {[$this get_feature_avaliable {ddp}]} {
+ bind $frame1_top_right_0._DPH_e <Key-Down> "
+ $frame1_top_right_0._DP1H_e icursor \[$frame1_top_right_0._DPH_e index insert\]
+ focus $frame1_top_right_0._DP1H_e"
+ bind $frame1_top_right_0._DPL_e <Key-Down> "
+ $frame1_top_right_0._DP1L_e icursor \[$frame1_top_right_0._DPL_e index insert\]
+ focus $frame1_top_right_0._DP1L_e"
+ }
+
+ # Create vertical separator (DPTR + Clock)|(SP + SBUF)
+ if {[$this get_feature_avaliable {ddp}]} {set row 3} {set row 2}
+ grid [ttk::separator $frame1_top_right_0._SP_sep \
+ -orient vertical \
+ ] \
+ -row 2 \
+ -column 3 \
+ -rowspan $row \
+ -padx 1 \
+ -sticky ns
+
+ # Create label "SP:"
+ grid [label $frame1_top_right_0._SP_l \
+ -text {SP:} -fg $name_color -pady 0 \
+ -font $bitfont \
+ ] -row 2 -column 4 -sticky w
+ setStatusTip -widget $frame1_top_right_0._SP_l -text {SFR 0x81: Stack pointer}
+
+ # Create hexadecimal entry for register: SP
+ set ::Simulator_GUI::ENV${obj_idx}_SP {07}
+ set entry [ttk::entry $frame1_top_right_0._SP_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_SP \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this entry_2_hex_validate_and_sync %P SP" \
+ -font $entry_font \
+ ]
+
+ # Show and register created memory cell (SP)
+ grid $entry -row 2 -column 5 -sticky w
+ add_entry $entry
+ $this add_sfr_entry 129 $entry
+
+ # Register SP SFR
+ lappend sf_registers [list 129 {SP}]
+ lappend sf_register_labels $frame1_top_right_0._SP_l
+
+ # Set entry event bindings (SP)
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide}
+ bind $entry <FocusIn> "$this unmark_entry 129"
+ bind $entry <Enter> "$this create_help_window_ram SP; Sbar -freeze {SFR 0x81: Stack pointer}"
+
+ # Create DPTR1
+ if {[$this get_feature_avaliable {ddp}] && ![$this get_feature_avaliable {hddptr}]} {
+
+ # Create label "DPTR1:"
+ grid [label $frame1_top_right_0._DPTR1_l \
+ -text {DPTR1:} -fg $name_color -pady 0 \
+ -font $bitfont \
+ ] -row 3 -column 0
+
+ # Create hexadecimal entries for registers: DP1H DP1L
+ set col 0 ;# Grid column
+ foreach reg {DP1H DP1L} addr {133 132} \
+ stip {
+ {SFR 0x85: Data pointer register}
+ {SFR 0x84: Data pointer register}
+ } {
+ incr col ;# Increment grid column
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $frame1_top_right_0._DPTR1_l
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $frame1_top_right_0._${reg}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this entry_2_hex_validate_and_sync %P $reg" \
+ -font $entry_font \
+ ]
+
+ # Show and register created memory cell
+ grid $entry -row 3 -column $col
+ add_entry $entry
+ $this add_sfr_entry $addr $entry
+
+ # Set entry event bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+ }
+
+ # Finalize entry event bindings for DPH and DPL
+ bind $frame1_top_right_0._DP1H_e <Key-Right> \
+ "Simulator_GUI::sim_entry_right $frame1_top_right_0._DP1H_e $frame1_top_right_0._DP1L_e"
+ bind $frame1_top_right_0._DP1L_e <Key-Left> \
+ "Simulator_GUI::sim_entry_left $frame1_top_right_0._DP1L_e $frame1_top_right_0._DP1H_e"
+ bind $frame1_top_right_0._DP1H_e <Key-Up> "
+ $frame1_top_right_0._DPH_e icursor \[$frame1_top_right_0._DP1H_e index insert\]
+ focus $frame1_top_right_0._DPH_e"
+ bind $frame1_top_right_0._DP1L_e <Key-Up> "
+ $frame1_top_right_0._DPL_e icursor \[$frame1_top_right_0._DP1L_e index insert\]
+ focus $frame1_top_right_0._DPL_e"
+
+ set row 4
+ } {
+ set row 3
+ }
+
+ # Create label "Clock:"
+ grid [label $frame1_top_right_0._CLOCK_l \
+ -text [mc "Clock:"] -fg $name_nr_color -pady 0 \
+ -font $bitfont \
+ ] -row $row -column 0 -sticky w
+ setStatusTip -widget $frame1_top_right_0._CLOCK_l -text [mc "Processor clock in kHz"]
+
+ # Create hexadecimal entry for created entry: Clock
+ set ::Simulator_GUI::ENV${obj_idx}_CLOCK {}
+ set entry [ttk::entry $frame1_top_right_0._CLOCK_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_CLOCK \
+ -font $entry_font \
+ -width 6 \
+ -validate all \
+ -validatecommand "$this clock_validate %P" \
+ ]
+ setStatusTip -widget $entry -text [mc "Processor clock in kHz"]
+
+ # Show and register created entry (Clock)
+ grid $entry -row $row -column 1 -columnspan 2
+ add_entry $entry
+
+ # Set default value for created entry (Clock)
+ set ::Simulator_GUI::ENV${obj_idx}_CLOCK [$this cget -P_option_clock]
+ clock_validate [$this cget -P_option_clock]
+
+ ## Create SBUF registers
+ set row 2
+ foreach reg {SBUFR SBUFT} \
+ addr {153 409} \
+ regname {{SBUF R} {SBUF T}} \
+ stip {
+ {SFR 0x99: Serial Data Buffer - RECEIVE buffer}
+ {SFR 0x99: Serial Data Buffer - TRANSMIT buffer}
+ } \
+ {
+ incr row
+
+ # Create label "SBUF X:"
+ if {[$this get_feature_avaliable uart]} {
+ set label [label $frame1_top_right_0._${reg}_l \
+ -text "${regname}:" -fg $name_color \
+ -font $bitfont -pady 0 \
+ ]
+ grid $label -row $row -column 4
+ setStatusTip -widget $label -text $stip
+
+
+ # Create hexadecimal entry for memory cell: SBUF
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $frame1_top_right_0._${reg}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this entry_2_hex_validate_and_sync %P ${reg}" \
+ -font $entry_font \
+ ]
+
+ # Show and register created memory cell (SBUF X)
+ grid $entry -row $row -column 5
+ add_entry $entry
+ $this add_sfr_entry $addr $entry
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $frame1_top_right_0._${reg}_l
+
+ # Set entry event bindings (SBUF X)
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+ }
+ }
+
+ incr row
+ # Create label "PC:" and button "Go to line"
+ set stip [mc "Program counter"]
+ set pc_lbl_but_frm [frame $frame1_top_right_0._PC_lbl_but]
+ pack [label $pc_lbl_but_frm._PC_l \
+ -text {PC:} -fg $name_nr_color \
+ -font $bitfont \
+ ] -side left
+ setStatusTip -widget $pc_lbl_but_frm._PC_l -text $stip
+ set set_pc_by_line_button [ttk::button $pc_lbl_but_frm._PC_but \
+ -image ::ICONS::16::2_rightarrow \
+ -command "::X::__simulator_set_PC_by_line" \
+ -style Flat.TButton \
+ ]
+ pack $set_pc_by_line_button -side right -after $pc_lbl_but_frm._PC_l
+ DynamicHelp::add $set_pc_by_line_button \
+ -text [mc "Set PC (Program Counter) acording to\nline number in source code"]
+ add_entry $pc_lbl_but_frm._PC_but
+ setStatusTip -widget $set_pc_by_line_button \
+ -text [mc "Set PC by line number"]
+ grid $pc_lbl_but_frm -row $row -column 0 -sticky w
+
+ # Create frame for PC-hex (label and entry)
+ set frame1_top_right_0_0 [frame $frame1_top_right_0.frame1_top_right_0_0]
+ grid $frame1_top_right_0_0 -row $row -column 1 -columnspan 2
+
+ # Create small label "HEX"
+ grid [label $frame1_top_right_0_0._PC_hex_l \
+ -text [mc "HEX"] -fg $small_color \
+ -font $smallfont \
+ ] -row 1 -column 1
+
+ # Create hexadecimal entry for PC-hex
+ set ::Simulator_GUI::ENV${obj_idx}_PC_hex {00}
+ set entry [ttk::entry $frame1_top_right_0_0._PC_hex_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_PC_hex \
+ -width 4 \
+ -validate key \
+ -validatecommand "$this sim_eval_PC hex %P" \
+ -font $entry_font \
+ ]
+ setStatusTip -widget $frame1_top_right_0_0._PC_hex_e -text $stip
+
+ # Show and register created entry (PC - hex)
+ grid $entry -row 1 -column 2
+ add_entry $entry
+ $this add_sfr_entry PC $entry
+
+ # Set entry event bindings (PC - hex)
+ bind $entry <FocusIn> "$this unmark_entry PC"
+
+ # Create frame for PC-dec (label and entry)
+ set frame1_top_right_0_1 [frame $frame1_top_right_0.frame1_top_right_0_1]
+ grid $frame1_top_right_0_1 -row $row -column 4 -columnspan 2
+
+ # Create small label "DEC"
+ grid [label $frame1_top_right_0_1._PC_dec_l \
+ -text [mc "DEC"] -fg $small_color -font $smallfont \
+ ] -row 1 -column 1
+
+ # Create hexadecimal entry for PC-dec
+ set ::Simulator_GUI::ENV${obj_idx}_PC_dec {0}
+ set entry [ttk::entry $frame1_top_right_0_1._PC_dec_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_PC_dec \
+ -width 5 \
+ -validate key \
+ -validatecommand "$this sim_eval_PC dec %P" \
+ -font $entry_font \
+ ]
+ setStatusTip -widget $frame1_top_right_0_1._PC_dec_e -text $stip
+
+ # Show and register created entry (PC - dec)
+ grid $entry -row 1 -column 2
+ add_entry $entry
+ $this add_sfr_entry PC $entry
+
+ # Set entry event bindings (PC - dec)
+ bind $entry <FocusIn> "$this unmark_entry PC"
+
+
+ # FRAME 1 - TOP - RIGHT - 1 (Time)
+ set frame1_top_right_1 [frame $frame1_top_right.frame1_top_right_1]
+ pack $frame1_top_right_1 -anchor nw
+
+ # Create label "Time:"
+ grid [label $frame1_top_right_1._TIME_l \
+ -text [mc "Time:"] -fg $name_nr_color -pady 0 \
+ -font $bitfont \
+ ] -row 1 -column 0 -sticky w
+ setStatusTip -widget $frame1_top_right_1._TIME_l -text [mc "Overall time"]
+
+ # Create entry widget for "Time"
+ set ::Simulator_GUI::ENV${obj_idx}_TIME {}
+ set entry [ttk::entry $frame1_top_right_1._TIME_e \
+ -style TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_TIME \
+ -state readonly \
+ -font [font create -size -12 -family $::DEFAULT_FIXED_FONT] \
+ ]
+ setStatusTip -widget $frame1_top_right_1._TIME_e -text [mc "Overall time"]
+
+ # Show entry widget "Time"
+ grid $entry -row 1 -column 1 -sticky we
+
+ # Create left bottom frame (Timer 2, ...)
+ set bottom_left_frame [frame $main_bottom_frame.bottom_left]
+ pack $bottom_left_frame -side left -anchor nw
+
+ # Create bottom left - top frame (above T2)
+ set bottom_left_bottom_frame [frame $bottom_left_frame.bottom]
+ pack $bottom_left_bottom_frame -anchor nw
+ set bottom_left_bottom_row 0 ;# Overall number of rows in this part of the panel
+ set bottom_left_bottom_trow 0 ;# Row in grid
+
+ # Create controls related to Timer/Couter 2
+ if {[$this get_feature_avaliable t2]} {
+ incr bottom_left_bottom_row 4
+ set t2_frame [frame $bottom_left_frame.timers_f]
+ pack $t2_frame
+
+ # Create frame for hexadecimal entries: TH1 TL1 TH0 TL0
+ set timers_values_f [frame $t2_frame.timers_values_f]
+ pack $timers_values_f
+
+ # Create hexadecimal entries for registers: TH1 TL1 TH0 TL0
+ set col 0 ;# Grid column
+ foreach reg {TH2 TL2 RCAP2H RCAP2L} addr {205 204 203 202} \
+ stip {
+ {SFR 0xCD: Part of 16-bit counting register for Timer/Counter 2}
+ {SFR 0xCC: Part of 16-bit counting register for Timer/Counter 2}
+ {SFR 0xCB: Part of 16-bit capture register for Timer/Counter 2}
+ {SFR 0xCA: Part of 16-bit capture register for Timer/Counter 2}
+ } {
+ incr col ;# Increment grid column
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg ]
+ lappend sf_register_labels $timers_values_f._${reg}_l
+
+ # Create register name label
+ grid [label $timers_values_f._${reg}_l \
+ -text $reg -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row 1 -column $col
+ setStatusTip -widget $timers_values_f._${reg}_l -text [mc $stip]
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $timers_values_f._Txx${col}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -validatecommand "$this validate_Txx $reg %P" \
+ -font $entry_font \
+ -validate key \
+ -width 2 \
+ ]
+
+ # Show and register created memory cell
+ grid $entry -row 2 -column $col
+ add_entry $entry
+ $this add_sfr_entry $addr $entry
+
+ # Set entry event bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+ bind $entry <Key-Right> \
+ "Simulator_GUI::sim_entry_right $entry $timers_values_f._Txx[expr {$col+1}]_e"
+ if {$col != {1}} {
+ bind $entry <Key-Left> \
+ "Simulator_GUI::sim_entry_left $entry $timers_values_f._Txx[expr {$col-1}]_e"
+ }
+ }
+
+ # Create decimal entries for timers
+ foreach reg {T2 RCAP2} addresses {{205 204} {203 202}} \
+ stip {
+ {SFR 0xCC..0xCD: 16-bit counting register for Timer/Counter 2}
+ {SFR 0xCA..0xCB: 16-bit capture register for Timer/Counter 2}
+ } {
+ incr col ;# Increment grid column
+
+ # Create register name label
+ grid [label $timers_values_f._${reg}_l \
+ -text $reg -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row 1 -column $col
+ setStatusTip -widget $timers_values_f._${reg}_l -text [mc $stip]
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {0}
+ set entry [ttk::entry $timers_values_f._Txx${col}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 5 \
+ -validate key \
+ -validatecommand "$this validate_Txx $reg %P" \
+ -font $entry_font \
+ ]
+ setStatusTip -widget $timers_values_f._Txx${col}_e -text $stip
+
+ # Show and register created memory cell
+ grid $entry -row 2 -column $col
+ add_entry $entry
+
+ # Set entry event bindings
+ bind $entry <Key-Right> \
+ "Simulator_GUI::sim_entry_right $entry $timers_values_f._Txx[expr {$col+1}]_e"
+ bind $entry <Key-Left> \
+ "Simulator_GUI::sim_entry_left $entry $timers_values_f._Txx[expr {$col-1}]_e"
+ foreach addr $addresses {
+ $this add_sfr_entry $addr $entry
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ }
+ }
+
+ # Create frame for registers: T2CON T2MOD (bitmaps)
+ set timers_frame_reg [frame $t2_frame.timers_reg_f]
+ pack $timers_frame_reg -anchor nw
+ # Create T2CON and T2MOD bitmaps
+ create_bitmap_register $timers_frame_reg 1 T2CON {TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2} 1 {
+ {Bit address: 0xCF -- Timer 2 overflow flag}
+ {Bit address: 0xCE -- Timer 2 external flag}
+ {Bit address: 0xCD -- Receive clock enable}
+ {Bit address: 0xCC -- Transmit clock enable}
+ {Bit address: 0xCB -- Timer 2 external enable}
+ {Bit address: 0xCA -- Start/Stop control for Timer 2}
+ {Bit address: 0xC9 -- Timer or counter select for Timer 2}
+ {Bit address: 0xC8 -- Capture/Reload select}
+ } {SFR 0xC8: Timer/Counter 2 control register} {
+ {Timer 2 overflow Flag\nTF2 is not set if RCLK=1 or TCLK = 1.\nMust be cleared by software.\nSet by hardware on timer 2 overflow.}
+ {Timer 2 External Flag\nSet when a capture or a reload is caused by a negative transition on T2EX pin if EXEN2=1.\nSet to cause the CPU to vector to timer 2 interrupt routine when timer 2 interrupt is enabled.\nMust be cleared by software.}
+ {Receive Clock bit\nClear to use timer 1 overflow as receive clock for serial port in mode 1 or 3.\nSet to use timer 2 overflow as receive clock for serial port in mode 1 or 3.}
+ {Transmit Clock bit\nClear to use timer 1 overflow as transmit clock for serial port in mode 1 or 3.\nSet to use timer 2 overflow as transmit clock for serial port in mode 1 or 3.}
+ {Timer 2 External Enable bit\nClear to ignore events on T2EX pin for timer 2 operation.\nSet to cause a capture or reload when a negative transition on T2EX pin is\ndetected, if timer 2 is not used to clock the serial port.}
+ {Timer 2 Run control bit\nClear to turn off timer 2.\nSet to turn on timer 2.}
+ {Timer/Counter 2 select bit\nClear for timer operation (input from internal clock system: FOSC).\nSet for counter operation (input from T2 input pin).}
+ {Timer 2 Capture/Reload bit\nIf RCLK=1 or TCLK=1, CP/RL2# is ignored and timer is forced to auto-reload on timer 2 overflow.\nClear to auto-reload on timer 2 overflows or negative transitions on T2EX pin if EXEN2=1.\nSet to capture on negative transitions on T2EX pin if EXEN2=1.}
+ }
+
+ if {[$this get_feature_avaliable t2mod]} {
+ create_bitmap_register $timers_frame_reg 2 T2MOD {- - - - - - T2OE DCEN} 1 {
+ {Reserved}
+ {Reserved}
+ {Reserved}
+ {Reserved}
+ {Reserved}
+ {Reserved}
+ {Timer 2 Output Enable bit}
+ {Down Counter Enable bit}
+ } {SFR 0xC9: Timer/Counter 2 mode control register} {
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ {Timer 2 Output Enable bit\nClear to program P1.0/T2 as clock input or I/O port.\nSet to program P1.0/T2 as clock output.}
+ {Down Counter Enable bit\nClear to disable timer 2 as up/down counter.\nSet to enable timer 2 as up/down counter.}
+ }
+ }
+
+ # Create hexadecimal entries for registers: TCON TMOD
+ foreach reg {T2CON T2MOD} \
+ addr {200 201} \
+ bits {{TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2} {- - - - - - T2OE DCEN}} \
+ stip {
+ {SFR 0xC8: Timer/Counter 2 control register}
+ {SFR 0xC9: Timer/Counter 2 mode control register}
+ } {
+ incr col ;# Increment grid column
+
+ if {$reg == {T2MOD} && ![$this get_feature_avaliable t2mod]} {
+ continue
+ }
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $Simulator_panel_parent._${reg}_l
+
+ # Create register name label
+ grid [label $timers_values_f._${reg}_hex_l \
+ -text $reg -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row 1 -column $col
+ setStatusTip -widget $timers_values_f._${reg}_hex_l -text [mc $stip]
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {0}
+ set entry [ttk::entry $timers_values_f._Txx${col}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this validate_hex_bitmap_reg %P $reg" \
+ -font $entry_font \
+ ]
+ set bit_in_particular_regs($reg) $bits
+
+ # Show and register created memory cell
+ grid $entry -row 2 -column $col
+ $this add_sfr_entry $addr $entry
+ add_entry $entry
+
+ # Set entry event bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+ if {$reg != {TMOD}} {
+ bind $entry <Key-Right> \
+ "Simulator_GUI::sim_entry_right $entry $timers_values_f._Txx[expr {$col+1}]_e"
+ }
+ bind $entry <Key-Left> \
+ "Simulator_GUI::sim_entry_left $entry $timers_values_f._Txx[expr {$col-1}]_e"
+ }
+ }
+
+ # Create middle bottom frame
+ set bottom_middle_frame [frame $main_bottom_frame.bottom_middle_frame]
+ pack $bottom_middle_frame -side left -anchor nw
+ set bottom_middle_row 0 ;# Row in grid
+
+ # Registers: AUXR, AUXR1, ACSR, EECON, SPCR, SPSR, WDTCON. IPH, SPCR
+ if {[$this get_feature_avaliable t2]} {
+ set pt2h {PT2H}
+ set pt2h_stip {Defines the Timer 2 interrupt priority level}
+ set pt2h_ttip {Timer 2 interrupt priority bit}
+ } {
+ set pt2h {-}
+ set pt2h_stip {Not implemented}
+ set pt2h_ttip {Not implemented}
+ }
+ if {[$this get_feature_avaliable uart]} {
+ set psh {PSH}
+ set psh_stip {Defines the Serial Port interrupt priority level}
+ set psh_ttip {Serial Port interrupt priority bit}
+ } {
+ set psh {-}
+ set psh_stip {Not implemented}
+ set psh_ttip {Not implemented}
+ }
+ if {[$this get_feature_avaliable acomparator]} {
+ set pch {PCH}
+ set pch_stip {Defines the comparator interrupt priority level}
+ set pch_ttip {Comparator Interrupt Priority bit}
+ } {
+ set pch {-}
+ set pch_stip {Not implemented}
+ set pch_ttip {Not implemented}
+ }
+ if {[$this get_feature_avaliable pwdex]} {
+ set PWDEX {PWDEX}
+ set pwdex_stip {Power-down Exit Mode}
+ set pwdex_ttip {Power-down Exit Mode. When PWDEX = 1, wake up from Power-down is externally controlled.\nWhen PWDEX = 0, wake up from Power-down is internally timed.}
+ } {
+ set PWDEX {-}
+ set pwdex_stip {Not implemented}
+ set pwdex_ttip {Not implemented}
+ }
+ if {[lindex [$this cget -procData] 8]} {
+ set EXTRAM {EXTRAM}
+ set extram_statustip {Internal/External RAM access using MOVX}
+ set extram_tooltip {Internal/External RAM access using MOVX @ Ri/@DPTR\nEXTRAM\tOperating Mode\n0\tInternal ERAM (00H-FFH) access using MOVX @ Ri/@DPTR\n1\tExternal data memory access}
+ } elseif {[$this get_feature_avaliable intelpe]} {
+ set EXTRAM {IPE}
+ set extram_statustip {Intel_Pwd_Exit}
+ set extram_tooltip {When set, this bit configures the interrupt driven exit from power-down\nto resume execution on the rising edge of the interrupt signal. When\nthis bit is cleared, the execution resumes after a self-timed interval\n(nominal 2 ms) referenced from the falling edge of the interrupt signal.}
+ } else {
+ set EXTRAM {-}
+ set extram_statustip {Reserved for future expansion}
+ set extram_tooltip {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ }
+ if {
+ [$this get_feature_avaliable wdtcon] ||
+ ![$this get_feature_avaliable wtd] ||
+ ![$this get_feature_avaliable auxrdisrto]
+ } then {
+ set DISRTO {-}
+ set disrto_stip {Reserved for future expansion}
+ set disrto_ttip {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ } else {
+ set DISRTO {DISRTO}
+ set disrto_stip {Disable/Enable Reset out}
+ set disrto_ttip {Disable/Enable Reset out\nDISRTO\tOperating Mode\n0\tReset pin is driven High after WDT times out\n1\tReset pin is input only}
+ }
+ if {
+ [$this get_feature_avaliable wdtcon] ||
+ ![$this get_feature_avaliable wtd] ||
+ ![$this get_feature_avaliable auxrwdidle]
+ } then {
+ set WDIDLE {-}
+ set wdidle_stip {Reserved for future expansion}
+ set wdidle_ttip {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ } else {
+ set WDIDLE {WDIDLE}
+ set wdidle_stip {Disable/Enable WDT in IDLE mode}
+ set wdidle_ttip {Disable/Enable WDT in IDLE mode\nWDIDLE\tOperating Mode\n0\tWDT continues to count in IDLE mode\n1\tWDT halts counting in IDLE mode}
+ }
+ if {[$this get_feature_avaliable ao]} {
+ set DISALE {AO}
+ } {
+ set DISALE {DISALE}
+ }
+ if {[$this get_feature_avaliable auxr1gf3]} {
+ set GF3 {GF3}
+ set gf3_ttip {General purpose user flag}
+ set gf3_stip {General purpose user flag}
+ } {
+ set GF3 {-}
+ set gf3_ttip {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.}
+ set gf3_stip {Reserved for future expansion}
+ }
+ set left__right 0 ;# Packe left (1) or right (0)
+ set row 0 ;# Grid row
+ foreach reg {AUXR AUXR1 ACSR EECON SPCR SPSR WDTCON WDTPRG IPH CLKREG } \
+ addr {142 162 151 150 213 170 167 167 183 143 } \
+ cg_left {0 1 1 0 0 1 0 1 1 1 } \
+ bits [list \
+ [list - - - $WDIDLE $DISRTO - $EXTRAM $DISALE] \
+ [list - - - - $GF3 - - DPS] \
+ [list - - - CF CEN CM2 CM1 CM0] \
+ [list - - EELD EEMWE EEMEN DPS RDYBSY WRTINH] \
+ [list SPIE SPE DORD MSTR CPOL CPHA SPR1 SPR0] \
+ [list SPIF WCOL LDEN - - - DISSO ENH] \
+ [list PS2 PS1 PS0 WDIDLE DISRTO HWDT WSWRST WDTEN] \
+ [list T4 T3 T2 T1 T0 S2 S1 S0] \
+ [list - $pch $pt2h $psh PT1H PX1H PT0H PX0H] \
+ [list - - - - - - $PWDEX X2] \
+ ] stip {
+ {SFR 0x8E: Auxillary Register}
+ {SFR 0xA2: Auxillary Register 1}
+ {SFR 0x97: Analog Comparator Control and Status Register}
+ {SFR 0x96: Data EEPROM Control Register}
+ {SFR 0xD5: SPI Control Register}
+ {SFR 0xAA: SPI Status Register}
+ {SFR 0xA7: Watchdog Control Register}
+ {SFR 0xA7: Watchdog Prescaler Control Register}
+ {SFR 0xB7: Interrupt Priority High Register}
+ {SFR 0x8F: Clock Register}
+ } {
+ if {$cg_left && $bottom_middle_row > $bottom_left_bottom_row} {
+ set left__right 1
+ set target_frame $bottom_left_bottom_frame
+ } {
+ set left__right 0
+ set target_frame $bottom_middle_frame
+ }
+
+ switch -- $reg {
+ {IPH} {
+ if {![$this get_feature_avaliable iph]} {
+ continue
+ }
+ create_bitmap_register $target_frame $row $reg $bits 1 [list \
+ {Not implemented} \
+ $pch_stip \
+ $pt2h_stip \
+ $psh_stip \
+ {Defines the Timer 1 interrupt priority level} \
+ {Defines External Interrupt 1 priority level} \
+ {Defines the Timer 0 interrupt priority level} \
+ {Defines the External Interrupt 0 priority level} \
+ ] $stip [list \
+ {Not implemented} \
+ $pch_ttip \
+ $pt2h_ttip \
+ $psh_ttip \
+ {Timer 1 interrupt priority bit} \
+ {External interrupt 1 priority bit} \
+ {Timer 0 interrupt priority bit} \
+ {External interrupt 0 priority bit} \
+ ]
+ }
+ {CLKREG} {
+ if {[$this get_feature_avaliable clkreg]} {
+ set reg {CLKREG}
+ } elseif {[$this get_feature_avaliable ckcon]} {
+ set reg {CKCON}
+ } else {
+ continue
+ }
+
+ create_bitmap_register $target_frame $row $reg $bits 1 [list \
+ {Not implemented} \
+ {Not implemented} \
+ {Not implemented} \
+ {Not implemented} \
+ {Not implemented} \
+ {Not implemented} \
+ $pwdex_stip \
+ {X2 mode flag} \
+ ] $stip [list \
+ {Not implemented} \
+ {Not implemented} \
+ {Not implemented} \
+ {Not implemented} \
+ {Not implemented} \
+ {Not implemented} \
+ $pwdex_ttip \
+ {When X2 = 0, the frequency (at XTAL1 pin) is internally divided by 2 before it is used as the device system frequency.\nWhen X2 = 1, the divide by 2 is no longer used and the XTAL1 frequency becomes the device system frequency. This\nenables the user to use a 6 MHz crystal instead of a 12 MHz crystal in order to reduce EMI.} \
+ ]
+ }
+ {EECON} {
+ if {![lindex [$this cget -procData] 32]} {
+ continue
+ }
+ create_bitmap_register $target_frame $row $reg $bits 1 {
+ {Not implemented}
+ {Not implemented}
+ {EEPROM data memory load enable bit}
+ {EEPROM data memory write enable bit}
+ {Internal EEPROM access enable}
+ {Data pointer register select}
+ {RDY/BSY (Ready/Busy) flag for the data EEPROM memory (read-only)}
+ {Write Inhibit (read-only)}
+ } $stip {
+ {Not implemented}
+ {Not implemented}
+ {EEPROM data memory load enable bit. Used to implement Page Mode Write. A MOVX\ninstruction writing into the data EEPROM will not initiate the programming cycle\nif this bit is set, rather it will just load data into the volatile data buffer\nof the data EEPROM memory. Before the last MOVX, reset this bit and the data\nEEPROM will program all the bytes previously loaded on the same page of the\naddress given by the last MOVX instruction.}
+ {EEPROM data memory write enable bit. Set this bit to 1 before initiating byte\nwrite to on-chip EEPROM with the MOVX instruction. User software should set\nthis bit to 0 after EEPROM write is completed.}
+ {Internal EEPROM access enable. When EEMEN = 1, the MOVX instruction with DPTR\nwill access on-chip EEPROM instead of external data memory if the address used\nis less than 2K. When EEMEN = 0 or the address used is ≥ 2K,}
+ {MOVX with DPTR accesses external data memory.\nData pointer register select. DPS = 0 selects the first bank of data pointer\nregister, DP0, and DPS = 1 selects the second bank, DP1.}
+ {RDY/BSY (Ready/Busy) flag for the data EEPROM memory. This is a read-only bit\nwhich is cleared by hardware during the programming cycle of the on-chip EEPROM.\nIt is also set by hardware when the programming is completed. Note that RDY/BSY\nwill be cleared long after the completion of the MOVX instruction which has\ninitiated the programming cycle.}
+ {WRTINH (Write Inhibit) is a READ-ONLY bit which is cleared by hardware when Vcc is\ntoo low for the programming cycle of the on-chip EEPROM to be executed. When this\nbit is cleared, an ongoing programming cycle will be aborted or a new programming\ncycle will not start.}
+ }
+
+ # Set read-only registers
+ set bits [lreplace $bits 6 6 -]
+ bind $Simulator_panel_parent._EECON_RDYBSY <Button-1> {break}
+ bind $Simulator_panel_parent._EECON_RDYBSY <ButtonRelease-3> {break}
+ }
+ {WDTCON} {
+ if {![$this get_feature_avaliable wdtcon] || [$this get_feature_avaliable wdtprg]} {
+ continue
+ }
+ set psx_tooltip {Prescaler bits for the watchdog timer (WDT). When all three bits are cleared\nto 0, the watchdog timer has a nominal period of 16K machine cycles,\n(i.e. 16 ms at a XTAL frequency of 12 MHz in normal mode or 6 MHz in x2 mode).\nWhen all three bits are set to 1, the nominal period is 2048K machine cycles,\n(i.e. 2048 ms at 12 MHz clock frequency in normal mode or 6 MHz in x2 mode).}
+
+ create_bitmap_register $target_frame $row $reg $bits 1 [list \
+ {Prescaler bit for the watchdog timer} \
+ {Prescaler bit for the watchdog timer} \
+ {Prescaler bit for the watchdog timer} \
+ {Enable/disable the Watchdog Timer in IDLE mode} \
+ {Enable/disable the WDT-driven Reset Out} \
+ {Hardware mode select for the WDT} \
+ {Watchdog software reset bit} \
+ {Watchdog software enable bit} \
+ ] $stip [list \
+ $psx_tooltip \
+ $psx_tooltip \
+ $psx_tooltip \
+ {Enable/disable the Watchdog Timer in IDLE mode. When WDIDLE = 0, WDT\ncontinues to count in IDLE mode. When WDIDLE = 1, WDT freezes while\nthe device is in IDLE mode.} \
+ {Enable/disable the WDT-driven Reset Out (WDT drives the RST pin). When\nDISRTO = 0, the RST pin is driven high after WDT times out and the entire\nboard is reset. When DISRTO = 1, the RST pin remains only as an input and the\nWDT resets only the microcontroller internally after WDT times out.} \
+ {Hardware mode select for the WDT. When HWDT = 0, the WDT can be turned on/off\nby simply setting or clearing WDTEN in the same register (this is the software\nmode for WDT). When HWDT = 1, the WDT has to be set by writing the sequence\n1EH/E1H to the WDTRST register (with address 0A6H) and after being set in this\nway, WDT cannot be turned off except by reset, warm or cold (this is the hardware\nmode for WDT). To prevent the hardware WDT from resetting the entire device,\nthe same sequence 1EH/E1H must be written to the same WDTRST SFR before the\ntimeout interval.} \
+ {Watchdog software reset bit. If HWDT = 0 (i.e. WDT is in software controlled mode),\nwhen set by software, this bit resets WDT. After being set by software, WSWRST is\nreset by hardware during the next machine cycle. If HWDT = 1, this bit has no effect,\nand if set by software, it will not be cleared by hardware.} \
+ {Watchdog software enable bit. When HWDT = 0 (i.e. WDT is in software-controlled mode),\nthis bit enables WDT when set to 1 and disables WDT when cleared to 0 (it does not\nreset WDT in this case, but just freezes the existing counter state). If HWDT = 1, this\nbit is READ-ONLY and reflects the status of the WDT (whether it is running or not).} \
+ ]
+ }
+ {WDTPRG} {
+ if {![$this get_feature_avaliable wdtprg] || [$this get_feature_avaliable wdtcon]} {
+ continue
+ }
+ set t_stip {Reserved}
+ set t_ttip {Do not try to set or clear this bit}
+ set s_stip {WDT Time-out select bit}
+ set s_ttip {Prescaler bits for the watchdog timer (WDT). When all three bits are cleared\nto 0, the watchdog timer has a nominal period of 16K machine cycles,\n(i.e. 16 ms at a XTAL frequency of 12 MHz in normal mode or 6 MHz in x2 mode).\nWhen all three bits are set to 1, the nominal period is 2048K machine cycles,\n(i.e. 2048 ms at 12 MHz clock frequency in normal mode or 6 MHz in x2 mode).}
+
+ create_bitmap_register $target_frame $row $reg $bits 1 [list \
+ $t_stip $t_stip $t_stip $t_stip $t_stip $s_stip $s_stip $s_stip \
+ ] $stip [list \
+ $t_ttip $t_ttip $t_ttip $t_ttip \
+ $t_ttip $s_ttip $s_ttip $s_ttip \
+ ]
+
+ # Set read-only registers
+ set bits {- - - - - S2 S1 S0}
+ foreach bit {T0 T1 T2 T3 T4} {
+ bind $Simulator_panel_parent._${reg}_${bit} <Button-1> {break}
+ bind $Simulator_panel_parent._${reg}_${bit} <ButtonRelease-3> {break}
+ }
+ }
+ {SPSR} {
+ if {![$this get_feature_avaliable spi]} {
+ continue
+ }
+ create_bitmap_register $target_frame $row $reg $bits 1 {
+ {SPI interrupt flag}
+ {Write collision flag}
+ {Load enable}
+ {Not implemented}
+ {Not implemented}
+ {Not implemented}
+ {Disable slave output bit}
+ {Enhanced SPI mode select bit}
+ } $stip {
+ {SPI interrupt flag. When a serial transfer is complete, the SPIF bit is set and an interrupt is generated if SPIE = 1 and ES\n= 1. The SPIF bit is cleared by reading the SPI status register followed by reading/writing the SPI data register.}
+ {When ENH = 0: Write collision flag. The WCOL bit is set if the SPI data register is written during a data transfer. During\ndata transfer, the result of reading the SPDR register may be incorrect, and writing to it has no effect. The WCOL bit (and\nthe SPIF bit) are cleared by reading the SPI status register followed by reading/writing the SPI data register.\nWhen ENH = 1: WCOL works in Enhanced mode as Tx Buffer Full. Writing during WCOL = 1 in enhanced mode will\noverwrite the waiting data already present in the Tx Buffer. In this mode, WCOL is no longer reset by the SPIF reset but\nis reset when the write buffer has been unloaded into the serial shift register.}
+ {Load enable for the Tx buffer in enhanced SPI mode.\nWhen ENH is set, it is safe to load the Tx Buffer while LDEN = 1 and WCOL = 0. LDEN is high during bits 0 - 3 and is low\nduring bits 4 - 7 of the SPI serial byte transmission time frame.}
+ {Not implemented}
+ {Not implemented}
+ {Not implemented}
+ {Disable slave output bit.\nWhen set, this bit causes the MISO pin to be tri-stated so more than one slave device can share the same interface with\na single master. Normally, the first byte in a transmission could be the slave address and only the selected slave should\nclear its DISSO bit.}
+ {Enhanced SPI mode select bit. When ENH = 0, SPI is in normal mode, i.e. without write double buffering.\nWhen ENH = 1, SPI is in enhanced mode with write double buffering. The Tx buffer shares the same address with the\nSPDR register.}
+ }
+ }
+ {SPCR} {
+ if {![$this get_feature_avaliable spi]} {
+ continue
+ }
+ create_bitmap_register $target_frame $row $reg $bits 1 [list \
+ {SPI interrupt enable} \
+ {SPI enable} \
+ {Data order} \
+ {Master/slave select} \
+ {Clock polarity} \
+ {Clock phase} \
+ {SPI clock rate select} \
+ {SPI clock rate select} \
+ ] $stip [list \
+ {SPI interrupt enable.\nThis bit, in conjunction with the ES bit in the IE register,\nenables SPI interrupts: SPIE = 1 and ES = 1 enable SPI interrupts. SPIE = 0 disables SPI interrupts.} \
+ {SPI enable. SPI = 1 enables the SPI channel and connects\nSS, MOSI, MISO and SCK to pins P1.4, P1.5, P1.6, and P1.7.\nSPI = 0 disables the SPI channel.} \
+ {Data order. DORD = 1 selects LSB first data transmission.\nDORD = 0 selects MSB first data transmission.} \
+ {Master/slave select. MSTR = 1 selects Master SPI mode.\nMSTR = 0 selects slave SPI mode.} \
+ {Clock polarity. When CPOL = 1, SCK is high when idle. When CPOL = 0,\nSCK of the master device is low when not transmitting. Please refer to\nfigure on SPI clock phase and polarity control.} \
+ {Clock phase. The CPHA bit together with the CPOL bit controls the\nclock and data relationship between master and slave. Please refer\nto figure on SPI clock phase and polarity control.} \
+ {SPI clock rate select.\nThese two bits control the SCK rate of the device configured as master.\nSPR1 and SPR0 have no effect on the slave. The relationship between SCK and the\noscillator frequency, FOSC., is as follows:\n SPR1\tSPR0\tSCK\n 0\t0\tf/4 (f/2 in x2mode)\n 0\t1\tf/16 (f/8 in x2 mode)\n 1\t0\tf/64 (f/32 in x2 mode)\n 1\t1\tf/128 (f/64 in x2 mode)} \
+ {SPI clock rate select.\nThese two bits control the SCK rate of the device configured as master.\nSPR1 and SPR0 have no effect on the slave. The relationship between SCK and the\noscillator frequency, FOSC., is as follows:\n SPR1\tSPR0\tSCK\n 0\t0\tf/4 (f/2 in x2mode)\n 0\t1\tf/16 (f/8 in x2 mode)\n 1\t0\tf/64 (f/32 in x2 mode)\n 1\t1\tf/128 (f/64 in x2 mode)} \
+ ]
+ }
+ {ACSR} {
+ if {![$this get_feature_avaliable acomparator]} {
+ continue
+ }
+ set CMx_tooltip {Comparator Interrupt Mode\n 2 1 0\tInterrupt Mode\n--- --- ---\t---------------------------------------\n 0 0 0\tNegative (Low) level\n 0 0 1\tPositive edge\n 0 1 0\tToggle with debounce\n 0 1 1\tPositive edge with debounce\n 1 0 0\tNegative edge\n 1 0 1\tToggle\n 1 1 0\tNegative edge with debounce\n 1 1 1\tPositive (High) level}
+ create_bitmap_register $target_frame $row $reg $bits 1 {
+ {Not implemented}
+ {Not implemented}
+ {Not implemented}
+ {Comparator Interrupt}
+ {Comparator Enable}
+ {Comparator Interrupt Mode}
+ {Comparator Interrupt Mode}
+ {Comparator Interrupt Mode}
+ } $stip [list \
+ {Not implemented} \
+ {Not implemented} \
+ {Not implemented} \
+ {Comparator Interrupt Flag. Set when the comparator output meets the conditions specified by the CM \[2:0\] bits and CEN\nis set. The flag must be cleared by software. The interrupt may be enabled/disabled by setting/clearing bit 6 of IE.} \
+ {Comparator Enable. Set this bit to enable the comparator. Clearing this bit will force the comparator output low and\nprevent further events from setting CF.} \
+ $CMx_tooltip $CMx_tooltip $CMx_tooltip \
+ ]
+ }
+ {AUXR1} {
+ if {
+ (![$this get_feature_avaliable ddp] || [$this get_feature_avaliable wdtcon])
+ && ![$this get_feature_avaliable auxr1gf3]
+ } then {
+ continue
+ }
+ create_bitmap_register $target_frame $row $reg $bits 1 [list \
+ {Reserved for future expansion} \
+ {Reserved for future expansion} \
+ {Reserved for future expansion} \
+ {Reserved for future expansion} \
+ $gf3_stip \
+ {Reserved for future expansion} \
+ {Reserved for future expansion} \
+ {Data Pointer Register Select} \
+ ] $stip [list \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ $gf3_ttip \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ {DPS\tData Pointer Register Select\n0\tSelects DPTR Registers DP0L, DP0H\n1\tSelects DPTR Registers DP1L, DP1H\n} \
+ ]
+ }
+ {AUXR} {
+ if {![$this get_feature_avaliable auxr]} {
+ continue
+ }
+ create_bitmap_register $target_frame $row $reg $bits 1 [list \
+ {Reserved for future expansion} \
+ {Reserved for future expansion} \
+ {Reserved for future expansion} \
+ $wdidle_stip \
+ $disrto_stip \
+ {Reserved for future expansion} \
+ $extram_statustip \
+ {Disable/Enable ALE} \
+ ] $stip [list \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ $wdidle_ttip \
+ $disrto_ttip \
+ {Reserved\nThe value read from this bit is indeterminate. Do not set this bit.} \
+ $extram_tooltip \
+ {Disable/Enable ALE\nDISALE\tOperating Mode\n0\tALE is emitted at a constant rate of 1/6 the oscillator frequency\n1\tALE is active only during a MOVX or MOVC instruction} \
+ ]
+ }
+ }
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $Simulator_panel_parent._${reg}_l
+
+ # Create register name labels
+ grid [label $target_frame._${reg}_hex_l \
+ -text {HEX} -fg $small_color \
+ -font $smallfont -pady 0 \
+ ] -row $row -column 12
+ setStatusTip -widget $target_frame._${reg}_hex_l -text [mc $stip]
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $target_frame._${reg}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -width 2 \
+ -validate key \
+ -validatecommand "$this validate_hex_bitmap_reg %P $reg" \
+ -font $entry_font \
+ ]
+ set bit_in_particular_regs($reg) $bits
+
+ if {$reg != {EECON}} {
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ } {
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {03}
+ }
+
+ # Show and register created memory cell
+ grid $entry -row $row -column 13 -padx 5
+ add_entry $entry
+ $this add_sfr_entry $addr $entry
+
+ # Set entry event bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ bind $entry <Enter> "$this create_help_window_ram $reg; Sbar -freeze {[mc $stip]}"
+
+ # Incerement row pointer
+ incr row
+ if {$left__right} {
+ incr bottom_left_bottom_row
+ incr bottom_left_bottom_trow
+ } {
+ incr bottom_middle_row
+ }
+ }
+ # Create vertical separator
+ if {$bottom_middle_row} {
+ if {$bottom_left_bottom_row} {
+ pack [ttk::separator $main_bottom_frame._sep0 -orient vertical] \
+ -side left -fill y -padx 5 -before $bottom_middle_frame
+ }
+ }
+
+ set bottom_right_frame [frame $main_bottom_frame.bottom_right_frame]
+ pack $bottom_right_frame -side left -anchor nw
+ set bottom_right_present 0
+
+ # Create bottom right register frame
+ set bottom_right_reg_frame [frame $bottom_right_frame.regs]
+ pack $bottom_right_reg_frame -anchor nw
+
+ # Create bottom right special function frame
+ set bottom_right_spec_frame [frame $bottom_right_frame.spec]
+ pack $bottom_right_spec_frame -anchor nw -fill both
+
+ ## Create watchdog timer controls
+ if {[$this get_feature_avaliable wtd]} {
+ set bottom_right_present 1
+ set watchdog_frame [frame $bottom_right_frame.watchdog_frame]
+ pack $watchdog_frame -anchor nw -before $bottom_right_reg_frame
+
+ pack [label $watchdog_frame._WatchDog_l \
+ -text [mc "Watchdog:"] -fg $name_nr_color \
+ -anchor w -pady 0 -font $bitfont \
+ ] -side left
+ setStatusTip -widget $watchdog_frame._WatchDog_l -text [mc "Watchdog timer"]
+
+ # Create ON/OFF switch
+ set watchdog_onoff_switch [label $watchdog_frame.on_off_switch \
+ -text [mc "OFF"] -fg $off_color -pady 0 \
+ -bd 1 -cursor hand1 -font [font create \
+ -family $::DEFAULT_FIXED_FONT -size -12 \
+ -weight bold \
+ ] \
+ ]
+ setStatusTip -widget $watchdog_onoff_switch -text [mc "Watchdog timer ON/OFF switch"]
+ bind $watchdog_onoff_switch <Button-1> "$this simulator_invert_wtd_onoff_switch"
+ pack $watchdog_onoff_switch -side left -padx 2
+
+ # Create entryBox for watchdog prescaler
+ if {[$this get_feature_avaliable wdtcon] || [$this get_feature_avaliable wdtprg]} {
+ # Create hexadecimal entry for created entry: WatchDog
+ set ::Simulator_GUI::ENV${obj_idx}_WatchDogP {00}
+ set wdt_prescaler_entry [ttk::entry $watchdog_frame._WatchDogP_e\
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_WatchDogP \
+ -font $entry_font \
+ -width 2 \
+ -validate all \
+ -validatecommand "$this watchdog_prescaler_validate %P" \
+ ]
+ set ::Simulator_GUI::ENV${obj_idx}_WatchDogP {00}
+
+ # Show and register created entry (WatchDog)
+ pack $wdt_prescaler_entry -side left
+ setStatusTip -widget $wdt_prescaler_entry -text [mc "Watchdog Prescaler (0-7 bits)"]
+ add_entry $wdt_prescaler_entry
+ }
+
+ # Create hexadecimal entry for created entry: WatchDog
+ set ::Simulator_GUI::ENV${obj_idx}_WatchDog {00}
+ set watchdog_entry [ttk::entry $watchdog_frame._WatchDog_e \
+ -style Simulator_watchdogEntry_0.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_WatchDog \
+ -font $entry_font \
+ -width 4 \
+ -validate all \
+ -validatecommand "$this watchdog_validate %P" \
+ ]
+
+ # Show and register created entry (WatchDog)
+ pack $watchdog_entry -side left
+ setStatusTip -widget $watchdog_entry -text [mc "Watchdog timer"]
+ add_entry $watchdog_entry
+
+ # Set default value for created entry (WatchDog)
+ set ::Simulator_GUI::ENV${obj_idx}_WatchDog {0000}
+
+ set wtd_clear_button [ttk::button $watchdog_frame.clear_button \
+ -image ::ICONS::16::clear_left \
+ -command "
+ set ::Simulator_GUI::ENV${obj_idx}_WatchDog {0000}
+ $this simulator_setWatchDogTimer 0
+ " \
+ -state disabled \
+ -style Flat.TButton \
+ ]
+ DynamicHelp::add $watchdog_frame.clear_button \
+ -text [mc "Reset Watchdog"]
+ pack $wtd_clear_button -side left
+ setStatusTip -widget $wtd_clear_button \
+ -text [mc "Reset watchdog timer"]
+ }
+
+ set row 0
+ set col 0
+ foreach reg {SADEN SADDR SPDR WDTRST } \
+ addr {185 169 134 166 } \
+ feature {euart euart spi wtd } \
+ stip {
+ {SFR 0xB9: Used to define which bits in the SADDR are to be used}
+ {SFR 0xA9: Define the slave's address}
+ {SFR 0x86: SPI Data Register}
+ {SFR 0xA6: Watchdog reset}
+ } {
+ if {![$this get_feature_avaliable $feature]} {
+ continue
+ }
+ if {$col >= 4} {
+ set col 0
+ incr row
+ }
+ set bottom_right_present 1
+
+
+ # Register this SFR
+ lappend sf_registers [list $addr $reg]
+ lappend sf_register_labels $bottom_right_reg_frame._${reg}_l
+
+ # Create register label
+ grid [label $bottom_right_reg_frame._${reg}_l \
+ -text "${reg}:" -fg $name_color \
+ -anchor w -pady 0 -font $bitfont \
+ ] -column $col -row $row -sticky w
+ incr col
+ setStatusTip -widget $bottom_right_reg_frame._${reg}_l -text [mc $stip]
+
+ # Create register hexadecimal entry
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+ set entry [ttk::entry $bottom_right_reg_frame._${reg}_e \
+ -style Simulator.TEntry \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_${reg} \
+ -validatecommand "$this entry_2_hex_validate_and_sync %P ${reg}"\
+ -font $entry_font \
+ -validate key \
+ -width 2 \
+ ]
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+
+ # Show the entry
+ grid $entry -column $col -row $row -sticky w
+ incr col 2
+ # Register register entry for disabling/enabling
+ $this add_sfr_entry $addr $entry
+ add_entry $entry
+ # Set entry default value
+ set ::Simulator_GUI::ENV${obj_idx}_${reg} {00}
+
+ # Set entry bindings
+ bind $entry <Motion> {help_window_show %X %Y}
+ bind $entry <Leave> {help_window_hide; Sbar {}}
+ bind $entry <Enter> "$this create_help_window_ram ${reg}; Sbar -freeze {[mc $stip]}"
+ bind $entry <FocusIn> "$this unmark_entry $addr"
+ }
+ grid columnconfigure $bottom_right_reg_frame 2 -minsize 5
+
+ set bottom_right_bottom_frame [frame $bottom_right_frame.bottom]
+ pack $bottom_right_bottom_frame -anchor nw
+
+ if {$bottom_middle_row && $bottom_right_present} {
+ pack [ttk::separator $main_bottom_frame._sep1 -orient vertical] \
+ -side left -fill y -padx 5 -before $bottom_right_frame
+ }
+
+ # Create parts of special functions frame
+ if {[lindex [$this cget -procData] 32]} {
+ simulator_GUI_cancel_write_to_eeprom
+ }
+
+ ## Finalize panel initialization
+ set disable_validation 0 ;# Enable entries validations
+ # Sort lists of SFRs
+ set len [llength $sf_registers]
+ for {set j 1} {$j < $len} {incr j} {
+ for {set i 1; set k 0} {$i < $len} {incr i; incr k} {
+ if {
+ [string compare \
+ [lindex $sf_registers [list $i 1]] \
+ [lindex $sf_registers [list $k 1]] \
+ ] < 0
+ } then {
+ set tmp [lindex $sf_registers $i]
+ lset sf_registers $i [lindex $sf_registers $k]
+ lset sf_registers $k $tmp
+
+ set tmp [lindex $sf_register_labels $i]
+ lset sf_register_labels $i [lindex $sf_register_labels $k]
+ lset sf_register_labels $k $tmp
+ }
+ }
+ }
+
+ $this Simulator_first_sync
+ sim_disable
+ }
+
+ ## Show EEPROM write progress indicator
+ # @return void
+ public method simulator_GUI_invoke_write_to_eeprom {} {
+ if {!$gui_initialized} {return}
+
+ # Create EEPROM indicator frame and horizonatl separator above it
+ set eeprom_operation_frame [frame $bottom_right_spec_frame.frame]
+ pack [ttk::separator $eeprom_operation_frame.sep] -fill x -pady 1
+
+ ## Create top frame
+ set top [frame $eeprom_operation_frame.top]
+ # Create label "Writing to EEPROM"
+ grid [label $top.lbl -text [mc "Writing to EEPROM"] -pady 0] \
+ -sticky we -row 0 -column 0
+ # Create button "Finalize"
+ grid [ttk::button $top.but_finalize \
+ -style Flat.TButton \
+ -image ::ICONS::16::2rightarrow \
+ -command "$this simulator_finalize_write_to_eeprom" \
+ ] -sticky e -row 0 -column 1 -padx 2
+ DynamicHelp::add $top.but_finalize \
+ -text [mc "Finalize data EEPROM write cycle"]
+ setStatusTip -widget $top.but_finalize -text [mc "Finalize write cycle"]
+ # Create button "Cancel"
+ grid [ttk::button $top.but_cancel \
+ -style Flat.TButton \
+ -image ::ICONS::16::button_cancel \
+ -command "$this simulator_cancel_write_to_eeprom" \
+ ] -sticky e -row 0 -column 2
+ DynamicHelp::add $top.but_cancel \
+ -text [mc "Cancel data EEPROM write cycle"]
+ setStatusTip -widget $top.but_cancel -text [mc "Cancel write cycle"]
+ grid columnconfigure $top 0 -weight 1
+
+ pack $top -fill x
+
+ # Create progress bar
+ set ::Simulator_GUI::ENV${obj_idx}_EEPROM_prg 0
+ set eeprom_progressbar [ttk::progressbar \
+ $eeprom_operation_frame.progressbar \
+ -mode determinate \
+ -orient horizontal \
+ -maximum 100 \
+ -variable ::Simulator_GUI::ENV${obj_idx}_EEPROM_prg \
+ ]
+ setStatusTip -widget $eeprom_progressbar -text [mc "EEPROM write cycle progress"]
+ pack $eeprom_progressbar -fill x
+
+ # Pack indicator frame
+ pack $eeprom_operation_frame -fill x -anchor nw -expand 1
+ }
+
+ ## Hide EEPROM write progress indicator
+ # @return void
+ public method simulator_GUI_cancel_write_to_eeprom {} {
+ if {!$gui_initialized} {return}
+
+ set ::Simulator_GUI::ENV${obj_idx}_EEPROM_prg 1
+ if {[winfo exists $eeprom_operation_frame]} {
+ destroy $eeprom_operation_frame
+ }
+ }
+
+ ## Set data EEPROM write progress value in %
+ # @parm Int value - New progress value in percents minus one (1..101)
+ # @return void
+ public method simulator_WTE_prg_set {value} {
+ if {!$gui_initialized} {return}
+
+ if {$value < 1} {
+ set value 1
+ }
+ set ::Simulator_GUI::ENV${obj_idx}_EEPROM_prg $value
+ if {$value <= 20} {
+ set clr {#FF0000}
+ } elseif {$value <= 40} {
+ set clr {#FF8800}
+ } elseif {$value <= 60} {
+ set clr {#FFFF00}
+ } elseif {$value <= 80} {
+ set clr {#88FF00}
+ } elseif {$value <= 100} {
+ set clr {#00FF00}
+ } else {
+ simulator_GUI_cancel_write_to_eeprom
+ return
+ }
+
+ $eeprom_progressbar configure -fg $clr
+ }
+
+ ## Adjust watchdog on/off switch acording to current state
+ # @return void
+ public method simulator_evaluate_wtd_onoff_switch {} {
+ if {!$gui_initialized} {return}
+
+ if {[$this simulator_isWatchDogTimerRuning]} {
+ $watchdog_onoff_switch configure -text [mc "ON "] -fg $on_color
+ } {
+ $watchdog_onoff_switch configure -text [mc "OFF"] -fg $off_color
+ }
+ }
+
+ ## Invert watchdog on/off flag
+ # @return void
+ public method simulator_invert_wtd_onoff_switch {} {
+ if {!$gui_initialized} {return}
+
+ if {!$sim_enabled} {return}
+ if {[$this simulator_isWatchDogTimerRuning]} {
+ $this simulator_startStopWatchDogTimer 0
+ } {
+ $this simulator_startStopWatchDogTimer 1
+ }
+ simulator_evaluate_wtd_onoff_switch
+ }
+
+ ## Validate content of watchdog prescaler entry box
+ # @parm String content - String to validate
+ # @return Bool - result
+ public method watchdog_prescaler_validate {content} {
+ # Validate content
+ if {![string is xdigit $content]} {
+ return 0
+ }
+ if {$content == {}} {
+ set content 0
+ }
+ set dec_value [expr "0x$content"]
+ if {$dec_value >= [$this simulator_getWatchDogPrescalerSize]} {
+ return 0
+ }
+
+ # Synchronize with engine
+ $this simulator_setWatchDogPrescalerValue $dec_value
+ return 1
+ }
+
+ ## Validate content of watchdog entry
+ # @parm String content - String to validate
+ # @return Bool - result
+ public method watchdog_validate {content} {
+ # Validate content
+ if {![string is xdigit $content]} {
+ return 0
+ }
+ if {$content == {}} {
+ set content 0
+ }
+ set dec_value [expr "0x$content"]
+ if {$dec_value > 8191} {
+ return 0
+ }
+
+ # Adjust clear button
+ catch {
+ if {!$dec_value || !$sim_enabled} {
+ $wtd_clear_button configure -state disabled
+ } {
+ $wtd_clear_button configure -state normal
+ }
+ }
+
+ # Adjust entry background color
+ if {$dec_value < 7000} {
+ $watchdog_entry configure -style Simulator_watchdogEntry_0.TEntry
+ } elseif {$dec_value < 7500} {
+ $watchdog_entry configure -style Simulator_watchdogEntry_1.TEntry
+ } else {
+ $watchdog_entry configure -style Simulator_watchdogEntry_2.TEntry
+ }
+
+ # Synchronize with engine
+ $this simulator_setWatchDogTimer $dec_value
+ return 1
+ }
+
+ ## Validate content of an entry widget related to timer registers (TH0 TL0 TH1 TL1 T0 T1)
+ # @parm String registerName - ID of the validated entry (one of {TH0 TL0 TH1 TL1 T0 T1})
+ # @parm String content - New content of the entry
+ # @return Bool - result
+ public method validate_Txx {registerName content} {
+ if {$disable_validation} {return 1}
+
+ # This function cannot run multithreaded
+ if {$sync_Txx_in_progress} {
+ return 1
+ } {
+ set sync_Txx_in_progress 1
+ }
+
+ # Determinate content length and normalize content (empty string == 0)
+ set content_len [string length $content]
+ if {$content_len == 0} {
+ set content 0
+ }
+
+ # Validation of T0, T1, T2 or RCAP2
+ if {[lsearch {T0 T1 T2 RCAP2} $registerName] != -1} {
+ # Check for maximal length (5 characters)
+ if {$content_len > 5} {
+ set sync_Txx_in_progress 0
+ return 0
+ }
+
+ # Check for allowed characters (decimal digits)
+ if {![string is digit $content]} {
+ set sync_Txx_in_progress 0
+ return 0
+ }
+
+ # Check for maximal value
+ if {$content > 0xFFFF} {
+ set sync_Txx_in_progress 0
+ return 0
+ }
+
+ # Determinate hexadecimal representation of the given value
+ set hex [NumSystem::dec2hex $content]
+ set hex_len [string length $hex]
+ if {$hex_len < 4} {
+ set hex "[string repeat {0} [expr {4 - $hex_len}]]$hex"
+ }
+ set hex_h [string range $hex 0 1]
+ set hex_l [string range $hex 2 3]
+
+ # Synchronize with TH0 and TL0 and engine
+ switch -- $registerName {
+ {T0} {
+ set regHigh {TH0}
+ set regLow {TL0}
+ }
+ {T1} {
+ set regHigh {TH1}
+ set regLow {TL1}
+ }
+ {T2} {
+ set regHigh {TH2}
+ set regLow {TL2}
+ }
+ {RCAP2} {
+ set regHigh {RCAP2H}
+ set regLow {RCAP2L}
+ }
+ }
+
+ # Fill THx and TLx entries
+ set ::Simulator_GUI::ENV${obj_idx}_${regHigh} $hex_h
+ set ::Simulator_GUI::ENV${obj_idx}_${regLow} $hex_l
+
+ # Synchronize with engine
+ if {!$disable_sync} {
+ # THx
+ set addr [symb_name_to_hex_addr $regHigh]
+ help_window_update [list $addr {SFR}] $content
+ set addr [expr "0x$addr"]
+ set dec_val [expr "0x$hex_h"]
+ $this setSfr $addr $hex_h
+ $this sfr_watches_sync $addr $dec_val
+ $this sfrmap_map_sync $addr $dec_val
+ $this cvarsview_sync I $addr
+
+ # TLx
+ set addr [symb_name_to_hex_addr $regLow]
+ help_window_update [list $addr {SFR}] $content
+ set addr [expr "0x$addr"]
+ set dec_val [expr "0x$hex_l"]
+ $this setSfr $addr $hex_l
+ $this sfr_watches_sync $addr $dec_val
+ $this sfrmap_map_sync $addr $dec_val
+ $this cvarsview_sync I $addr
+ }
+
+ # Validation of THx, TLx or RCAPxL, RCAPxH
+ } {
+ # Check for corrent value
+ if {![entry_2_hex_validate $content]} {
+ set sync_Txx_in_progress 0
+ return 0
+ }
+
+ ## Determinate vaiable of Tx entry and low-order and high-order bytes of Tx
+ # TH0 or TL0
+ if {$registerName == {TH0} || $registerName == {TL0}} {
+ set hex_h [subst "\$::Simulator_GUI::ENV${obj_idx}_TH0"]
+ set hex_l [subst "\$::Simulator_GUI::ENV${obj_idx}_TL0"]
+ set target_var "::Simulator_GUI::ENV${obj_idx}_T0"
+ # TH1 or TL1
+ } elseif {$registerName == {TH1} || $registerName == {TL1}} {
+ set hex_h [subst "\$::Simulator_GUI::ENV${obj_idx}_TH1"]
+ set hex_l [subst "\$::Simulator_GUI::ENV${obj_idx}_TL1"]
+ set target_var "::Simulator_GUI::ENV${obj_idx}_T1"
+ # TH2 or TL2
+ } elseif {$registerName == {TH2} || $registerName == {TL2}} {
+ set hex_h [subst "\$::Simulator_GUI::ENV${obj_idx}_TH2"]
+ set hex_l [subst "\$::Simulator_GUI::ENV${obj_idx}_TL2"]
+ set target_var "::Simulator_GUI::ENV${obj_idx}_T2"
+ # RCAP2H or RCAP2L
+ } elseif {$registerName == {RCAP2H} || $registerName == {RCAP2L}} {
+ set hex_h [subst "\$::Simulator_GUI::ENV${obj_idx}_RCAP2H"]
+ set hex_l [subst "\$::Simulator_GUI::ENV${obj_idx}_RCAP2L"]
+ set target_var "::Simulator_GUI::ENV${obj_idx}_RCAP2"
+ }
+
+ # Overwrite low/high byte with the new content
+ switch -- $registerName {
+ {TH0} {set hex_h $content}
+ {TH1} {set hex_h $content}
+ {TH2} {set hex_h $content}
+ RCAP2H {set hex_h $content}
+ {TL0} {set hex_l $content}
+ {TL1} {set hex_l $content}
+ {TL2} {set hex_l $content}
+ RCAP2L {set hex_l $content}
+ }
+
+ # Synchronize with engine
+ if {!$disable_sync} {
+ set addr [symb_name_to_hex_addr $registerName]
+ help_window_update [list $addr {SFR}] $content
+ set addr [expr "0x$addr"]
+ set dec_val [expr "0x$content"]
+ $this setSfr $addr $content
+ $this sfr_watches_sync $addr $dec_val
+ $this sfrmap_map_sync $addr $dec_val
+ $this cvarsview_sync I $addr
+ }
+
+ # Normalize low-order value
+ if {[string length $hex_l] == 1} {
+ set hex_l "0$hex_l"
+ }
+
+ # Set Tx
+ set $target_var [expr "0x${hex_h}${hex_l}"]
+ }
+
+ # Validation complete
+ set sync_Txx_in_progress 0
+ return 1
+ }
+
+ ## Force bitmap register validation enable
+ # @return void
+ public method simulator_force_bitmap_hex_validation_ena {} {
+ set bitmap_hex_validation_ena 1
+ }
+
+ ## Informs simulator UI about change of SMOD0 bit
+ # This function will then adjust content of register SCON to fit
+ # possibly new value of bit SCON.7 (FE/SM0)
+ # @return void
+ public method simulator_gui_SMOD0_changed {} {
+ set scon [subst "\$::Simulator_GUI::ENV${obj_idx}_SCON"]
+ if {$scon == {}} {
+ set scon 0
+ }
+ set scon [expr {"0x$scon" & 0x7F}]
+ if {[$this get_SMOD0]} {
+ if {[subst "\$::Simulator_GUI::ENV${obj_idx}_SFR(FE)"]} {
+ set scon [expr {$scon | 0x80}]
+ }
+ } {
+ if {[subst "\$::Simulator_GUI::ENV${obj_idx}_SFR(SM0)"]} {
+ set scon [expr {$scon | 0x80}]
+ }
+ }
+ set scon [format %X $scon]
+ if {[string length $scon] == 1} {
+ set scon "0$scon"
+ }
+ set ::Simulator_GUI::ENV${obj_idx}_SCON $scon
+ validate_hex_bitmap_reg $scon SCON
+ }
+
+ ## Validate hexadecimal regiter entry with interconnected with a bitmap
+ # @parm String value - Hexadeciaml value to validate
+ # @parm String registerName - Register ID
+ # @return Bool - result
+ public method validate_hex_bitmap_reg {value registerName} {
+ # This function cannot run multithreaded
+ if {$bitmap_hex_validation_ena} {
+ set bitmap_hex_validation_ena 0
+ } {
+ return 1
+ }
+
+ # Check for allowed length and normalize value (empty string == 0)
+ set valueLen [string length $value]
+ if {$valueLen == 0} {
+ set value 0
+ } elseif {$valueLen > 2} {
+ set bitmap_hex_validation_ena 1
+ return 0
+ }
+ # Check for allowed characters
+ if {![regexp {^[0-9A-Fa-f]*$} $value]} {
+ set bitmap_hex_validation_ena 1
+ return 0
+ }
+
+
+ set bitList $bit_in_particular_regs($registerName)
+
+ # Determinate list 8 bits of binary represenatation of the new content
+ set bin [NumSystem::hex2bin $value]
+ set bin_len [string length $bin]
+ if {$bin_len < 8} {
+ set bin "[string repeat {0} [expr {8 - $bin_len}]]$bin"
+ }
+ set bits [split $bin {}]
+
+ # Adjust bit list for special registers
+ switch -- $registerName {
+ SCON {
+ if {[$this get_SMOD0]} {
+ lset bitList 0 FE
+ } {
+ lset bitList 0 SM0
+ }
+ }
+ }
+
+ # Synchronize with register bitmap
+ set i -1 ;# Bit number
+ foreach bitName $bitList {
+ incr i
+
+ # Skip empty bits
+ if {$bitName == {-}} {continue}
+
+ # Determinate bit label color
+ set bitVal [lindex $bits $i]
+ if {$bitVal} {
+ set color $on_color
+ } {
+ set color $off_color
+ }
+
+ # Set bit value and label color
+ set ::Simulator_GUI::ENV${obj_idx}_SFR($bitName) $bitVal
+ $Simulator_panel_parent._${registerName}_$bitName configure -fg $color
+ }
+
+ # Synchronize with Right panel and engine
+ if {!$disable_sync} {
+ set addr [symb_name_to_hex_addr $registerName]
+ help_window_update [list $addr {SFR}] $value
+ set addr [expr "0x$addr"]
+ set dec_val [expr "0x$value"]
+ $this setSfr $addr $value
+ $this sfr_watches_sync $addr $dec_val
+ $this sfrmap_map_sync $addr $dec_val
+ $this cvarsview_sync I $addr
+ }
+
+ # Success
+ set bitmap_hex_validation_ena 1
+ return 1
+ }
+
+ ## Create register bitmap
+ # @parm Widget parent - parent GUI component (some frame)
+ # @parm Int row - Row in grid (for geometry manager)
+ # @parm String name - Register name (for label)
+ # @parm List bit_list - List of bit names
+ # @parm String hex_reg - Has hexadecimal entry (for procedure sim_invert)
+ # @parm List s_tips - List of status bar tips for bit lables
+ # @parm String stip - Status tip for regster label
+ # @parm List tooltips - List of tooltips for each bit
+ # @return void
+ private method create_bitmap_register {parent row name bit_list hex_reg s_tips stip tooltips} {
+ # Create register label
+ grid [label $Simulator_panel_parent._${name}_l \
+ -text "[mc $name]:" -fg $name_color \
+ -anchor w -pady 0 -font $bitfont \
+ ] -row $row -column 1 -in $parent -sticky w
+ setStatusTip -widget $Simulator_panel_parent._${name}_l -text $stip
+
+ set col 1 ;# Bit label column (2..9)
+ set bitNum -1 ;# Bit number (0..7)
+ set Idx 0 ;# Bit index (1..8)
+ # Create bit map
+ foreach bit $bit_list sTip $s_tips tooltip $tooltips {
+ incr col
+ incr bitNum
+
+ # Handle empty bits
+ if {$bit == {-}} {
+ set color {#000000}
+ incr Idx
+ set idx $Idx
+ set cursor {left_ptr}
+ } {
+ set color $off_color
+ set cursor {hand1}
+ set idx {}
+ }
+
+ # Create bit label
+ set label [label $Simulator_panel_parent._${name}_${bit}${idx} \
+ -text $bit -fg $color -cursor $cursor \
+ -bd 1 -font $bitfont -pady 0 \
+ ]
+ setStatusTip -widget $label -text [mc $sTip]
+ if {$bit != {-}} {
+ bind $label <Enter> {+%W configure -font $::Simulator_GUI::bitfont_under}
+ bind $label <Leave> {+%W configure -font $::Simulator_GUI::bitfont}
+ }
+ DynamicHelp::add $label -text [subst [mc $tooltip]]
+ grid $label -row $row -column $col -in $parent
+
+ # Skip registration of empty bits
+ if {$bit == {-}} {continue}
+
+ # Register bit label
+ bind $label <Button-1> "$this sim_invert $bit $bitNum $name $hex_reg"
+ bind $label <ButtonRelease-3> "$this bit_popup_menu $bit $bitNum $name $hex_reg %X %Y"
+ set ::Simulator_GUI::ENV${obj_idx}_SFR($bit) 0
+ }
+ }
+
+ ## Invokes bit popup menu
+ # @parm String bit - Bit name
+ # @parm Int bitNum - Bit number
+ # @parm String name - Register name
+ # @parm String hex_reg - Register name for procedure sim_invert
+ # @parm Int X - Horizontal position of the mouse pointer
+ # @parm Int X - Vertical position of the mouse pointer
+ # @return void
+ public method bit_popup_menu {bit bitNum name hex_reg X Y} {
+ set bit_popup_menu_args [list $bit $bitNum $name $hex_reg]
+ tk_popup $bitmenu $X $Y
+ }
+
+ ## Procedure for bit popup menu -- set bit to $bool
+ # @parm Bool bool - New bit value
+ # @parm void
+ public method bit_popup_menu_setto {bool} {
+ if {!$sim_enabled} {return}
+ if {$bool != [subst "\$::Simulator_GUI::ENV${obj_idx}_SFR([lindex $bit_popup_menu_args 0])"]} {
+ eval "sim_invert $bit_popup_menu_args"
+ }
+ }
+
+ ## Validate content of Program Counter (PC) entry
+ # @parm String num_base - Numeric base of the entry (one of {hex dec})
+ # @parm String content - String to validate
+ # @return Bool - result
+ public method sim_eval_PC {num_base content} {
+
+ # This function cannot run multithreaded
+ if {$sync_PC_in_progress} {
+ return 1
+ } {
+ set sync_PC_in_progress 1
+ }
+
+ # Determinate content length and normalize content (empty string == 0)
+ set content_len [string length $content]
+ if {$content_len == 0} {
+ set content 0
+ }
+
+ # Validate and synchronize
+ switch -- $num_base {
+ {hex} { ;# From hexadecimal
+
+ # Check for allowed length
+ if {$content_len > 4} {
+ set sync_PC_in_progress 0
+ return 0
+ }
+ # Check for allowed characters
+ if {![regexp {^[0-9A-Fa-f]*$} $content]} {
+ set sync_PC_in_progress 0
+ return 0
+ }
+
+ # Synchronize with decimal entry
+ set dec [expr "0x$content"]
+ set ::Simulator_GUI::ENV${obj_idx}_PC_dec $dec
+ }
+ {dec} { ;# From decimal
+
+ # Check for allowed length
+ if {$content_len > 5} {
+ set sync_PC_in_progress 0
+ return 0
+ }
+ # Check for allowed characters
+ if {![regexp {^[0-9]*$} $content]} {
+ set sync_PC_in_progress 0
+ return 0
+ } elseif {$content > 65535} {
+ set sync_PC_in_progress 0
+ return 0
+ }
+
+ # Synchronize with hexadecimal entry
+ set hex [NumSystem::dec2hex $content]
+ set hex_len [string length $hex]
+ if {$hex_len < 4} {
+ set hex "[string repeat {0} [expr {4 - $hex_len}]]$hex"
+ }
+ set ::Simulator_GUI::ENV${obj_idx}_PC_hex $hex
+
+ # Determinate decimal representation
+ set dec $content
+ }
+ }
+
+ # Synchronize with engine
+ if {!$disable_sync} {
+ $this setPC $dec
+ set lineNum [$this simulator_getCurrentLine]
+ if {$lineNum != {}} {
+ $this move_simulator_line $lineNum
+ } {
+ $this editor_procedure {} unset_simulator_line {}
+ }
+ }
+
+ # Success
+ set sync_PC_in_progress 0
+ return 1
+ }
+
+ ## Validate content of P0..P3 hexadecimal/binary entry
+ # @parm String register - Register ID (eg. 'P2')
+ # @parm String num_base - Numberic base of the entry (one of {hex bin})
+ # @parm String content - String to validate
+ # @return Bool - result
+ public method sim_eval_Px {register num_base content} {
+
+ # This function cannot run multithreaded
+ if {$sync_Px_in_progress} {
+ return 1
+ } {
+ set sync_Px_in_progress 1
+ }
+
+ # If content is an empty string -> abort
+ set content_len [string length $content]
+ if {$content_len == 0} {
+ set sync_Px_in_progress 0
+ return 1
+ }
+
+ # Synchronize with the other register
+ switch -- $num_base {
+ {hex} { ;# With bin
+ # Check for allowed length
+ if {$content_len > 2} {
+ set sync_Px_in_progress 0
+ return 0
+ }
+ # Check for allowed characters
+ if {![regexp {^[0-9A-Fa-f]*$} $content]} {
+ set sync_Px_in_progress 0
+ return 0
+ }
+
+ # Determinate binary representation
+ set bin [NumSystem::hex2bin $content]
+ set bin_len [string length $bin]
+ if {$bin_len < 8} {
+ set bin "[string repeat {0} [expr {8 - $bin_len}]]$bin"
+ }
+
+ # Synchronize
+ set ::Simulator_GUI::ENV${obj_idx}_${register}_bin $bin
+ set hex $content
+ }
+ {bin} { ;# With hex
+ # Check for allowed length
+ if {$content_len > 8} {
+ set sync_Px_in_progress 0
+ return 0
+ }
+ # Check for allowed characters
+ if {![regexp {^[01]*$} $content]} {
+ set sync_Px_in_progress 0
+ return 0
+ }
+
+ # Determinate hexadecimal representation
+ set hex [NumSystem::bin2hex $content]
+ if {[string length $hex] == 1} {
+ set hex "0$hex"
+ }
+
+ # Synchronize
+ set ::Simulator_GUI::ENV${obj_idx}_${register} $hex
+ }
+ }
+
+ # Syncronize with right panel and engine
+ if {!$disable_sync} {
+ set addr [symb_name_to_hex_addr $register]
+ help_window_update [list $addr {SFR}] $hex
+ set addr [expr "0x$addr"]
+ set dec_val [expr "0x$hex"]
+ $this setSfr $addr $hex
+ $this sfr_watches_sync $addr $dec_val
+ $this sfrmap_map_sync $addr $dec_val
+ $this cvarsview_sync I $addr
+ }
+
+ # Successfull
+ set sync_Px_in_progress 0
+ return 1
+ }
+
+ ## Validate content of some entry widget of A or B register
+ # @parm String register - Register ID ('A' or 'B')
+ # @parm String num_base - Numberic base (one of {hex dec bin oct char})
+ # @parm String content - String to validate
+ # @return Bool - result
+ public method sim_eval_AB {register num_base content} {
+ if {$disable_validation} {return 1}
+
+ # This function cannot run multithreaded
+ if {$sync_AB_in_progress} {
+ return 1
+ } {
+ set sync_AB_in_progress 1
+ }
+
+ # If empty string -> abort
+ if {[string length $content] == 0} {
+ set sync_AB_in_progress 0
+ return 1
+ }
+
+ # Determinate maximum length acording to numeric base
+ switch -- $num_base {
+ {hex} {set max_len 2}
+ {dec} {set max_len 3}
+ {bin} {set max_len 8}
+ {oct} {set max_len 3}
+ {char} {set max_len 1}
+ default {
+ set sync_AB_in_progress 0
+ return 0
+ }
+ }
+
+ # Check for allowed length
+ if {[string bytelength $content] > $max_len} {
+ set sync_AB_in_progress 0
+ return 0
+ }
+
+ # Check for allowed characters and determinate binary representation
+ switch -- $num_base {
+ {hex} {
+ # Check for allowed characters
+ set content [string toupper $content]
+ if {![regexp {^[0-9A-Fa-f]*$} $content]} {
+ set sync_AB_in_progress 0
+ return 0
+ }
+ # Determinate binary representation
+ set bin [NumSystem::hex2bin $content]
+ }
+ {dec} {
+ # Check for allowed characters
+ if {![regexp {^[0-9]*$} $content]} {
+ set sync_AB_in_progress 0
+ return 0
+ }
+ # Determinate binary representation
+ set bin [NumSystem::dec2bin $content]
+ }
+ {bin} {
+ # Check for allowed characters
+ if {![regexp {^[01]*$} $content]} {
+ set sync_AB_in_progress 0
+ return 0
+ }
+ set bin $content
+ }
+ {oct} {
+ # Check for allowed characters
+ if {![regexp {^[0-7]*$} $content]} {
+ set sync_AB_in_progress 0
+ return 0
+ }
+ # Determinate binary representation
+ set bin [NumSystem::oct2bin $content]
+ }
+ {char} {
+ # Determinate binary representation
+ set bin [NumSystem::ascii2bin $content]
+ if {$bin == {}} {
+ set sync_AB_in_progress 0
+ return 0
+ }
+ }
+ }
+
+ # Determinate other numerical representations
+ set hex [NumSystem::bin2hex $bin]
+ set dec [NumSystem::bin2dec $bin]
+ set oct [NumSystem::bin2oct $bin]
+
+ # Check for allowed range
+ if {$dec > 255 || $dec < 0} {
+ set sync_AB_in_progress 0
+ return 0
+ }
+
+ # Normalize binary value
+ set bin_len [string length $bin]
+ if {$bin_len < 8} {
+ set bin "[string repeat {0} [expr {8 - $bin_len}]]$bin"
+ }
+ # Determinate character representation
+ if {$dec > 31 && $dec < 127} {
+ set char [subst "\\u00$hex"]
+ } {
+ set char {}
+ }
+
+ # Synchronize with other entries
+ foreach base {hex dec bin oct char} {
+ if {$base == $num_base} {continue}
+ set ::Simulator_GUI::ENV${obj_idx}_${register}_$base [subst "\$$base"]
+ }
+
+ # Synchronize with Right panel and Engine
+ if {!$disable_sync} {
+ # Register A
+ if {$register == {A}} {
+ $this setSfr 224 $hex
+ set dec_val [expr "0x$hex"]
+ $this sfr_watches_sync 224 $dec_val
+ $this sfrmap_map_sync 224 $dec_val
+ # Register B
+ } {
+ $this setSfr 240 $hex
+ set dec_val [expr "0x$hex"]
+ $this sfr_watches_sync 240 $dec_val
+ $this sfrmap_map_sync 240 $dec_val
+ }
+ }
+
+ # Successful ...
+ set sync_AB_in_progress 0
+ return 1
+ }
+
+ ## Create help window for active bank registers (R0..R7)
+ # @parm Int R_index - number of the register (0..7)
+ # @return void
+ public method create_help_window_Rx {R_index} {
+ # Determinate true register address (decimal)
+ set RS0 [subst "\$::Simulator_GUI::ENV${obj_idx}_SFR(RS0)"]
+ set RS1 [subst "\$::Simulator_GUI::ENV${obj_idx}_SFR(RS1)"]
+ if {$RS0} {incr R_index 8}
+ if {$RS1} {incr R_index 16}
+
+ # Create help window
+ create_help_window_ram $R_index
+ }
+
+ ## Set value for the given bit in the given register
+ # This function bypasses connection to register which the bit belongs to
+ # @parm Bool bool - New bit value
+ # @parm String reg - Bit register (register name not address)
+ # @parm String bit - Bit name (not address)
+ # @return void
+ public method sim_GUI_bit_set_clear {bool reg bit} {
+ if {!$gui_initialized} {return}
+
+ if {$bool} {
+ $Simulator_panel_parent._${reg}_${bit} configure -fg $on_color
+ } {
+ $Simulator_panel_parent._${reg}_${bit} configure -fg $off_color
+ }
+ }
+
+ ## Invert bit in register bitmap
+ # @parm String bitName - Bit name (eg. 'EA')
+ # @parm Int bitNumber - Bit number (eg. '7')
+ # @parm String registerName - Register name (eg. 'IE')
+ # @parm Bool hex_reg - Bitmap is connected to hexadecimal entry
+ # @return void
+ public method sim_invert {bitName bitNumber registerName hex_reg} {
+ if {!$gui_initialized} {return}
+ set decVal_increment 0
+
+ # Simulator must be engaged
+ if {!$sim_enabled} {return}
+
+ # Determinate bit boolean value
+ set bitBoolVal [subst "\$::Simulator_GUI::ENV${obj_idx}_SFR($bitName)"]
+
+ # Determinate bit decimal and hexadecimal value
+ set addr [symb_name_to_hex_addr $registerName]
+ set addr [expr "0x$addr"]
+ set decVal 0
+ set bitDecVal 0
+ set bitmap_hex_validation_ena 0
+ if {$hex_reg} {
+ set decVal [expr "0x[subst "\$::Simulator_GUI::ENV${obj_idx}_${registerName}"]"]
+ } {
+ set decVal [$this getSfrDEC $addr]
+ }
+ switch -- $bitNumber {
+ 7 {set bitDecVal 1}
+ 6 {set bitDecVal 2}
+ 5 {set bitDecVal 4}
+ 4 {set bitDecVal 8}
+ 3 {set bitDecVal 16}
+ 2 {set bitDecVal 32}
+ 1 {set bitDecVal 64}
+ 0 {set bitDecVal 128}
+ }
+
+ # Change label color and decimal value
+ if {$bitBoolVal} {
+ $Simulator_panel_parent._${registerName}_$bitName configure -fg $off_color
+ set decVal_increment -$bitDecVal
+ } {
+ $Simulator_panel_parent._${registerName}_$bitName configure -fg $on_color
+ set decVal_increment $bitDecVal
+ }
+
+ # Handle very special bits
+ switch -- $bitName {
+ FE {
+ if {![$this get_SMOD0]} {
+ set decVal_increment 0
+ $this sim_engine_set_FE [expr {!$bitBoolVal}]
+ }
+ }
+ SM0 {
+ if {[$this get_SMOD0]} {
+ set decVal_increment 0
+ $this sim_engine_set_SM0 [expr {!$bitBoolVal}]
+ }
+ }
+ }
+ incr decVal $decVal_increment
+
+ # Set new bit value
+ set ::Simulator_GUI::ENV${obj_idx}_SFR($bitName) [expr {!$bitBoolVal}]
+
+ ## Synchronize
+ set hexVal [format %X $decVal]
+ if {[string length $hexVal] == 1} {
+ set hexVal "0$hexVal"
+ }
+ # With hexadecimal entry
+ if {$hex_reg} {
+ set ::Simulator_GUI::ENV${obj_idx}_${registerName} $hexVal
+ }
+ # With Right panel and Engine
+ if {!$disable_sync} {
+ $this setSfr $addr $hexVal
+ $this Simulator_sync_sfr $addr
+ }
+ set bitmap_hex_validation_ena 1
+
+ # If the bit is one of {RS0 RS1} -> change current register bank
+ if {$bitName == {RS0} || $bitName == {RS1}} {
+ sim_switch_bank
+ }
+ }
+
+ ## Translate register symbolic name to hexadecimal address
+ # @parm String regName - Register name (eg. 'PSW')
+ # @return String - hexadecimal address (eg. 'D0') or void
+ public method symb_name_to_hex_addr {regName} {
+ switch -- $regName {
+ {A_hex} {return E0}
+ {B_hex} {return F0}
+ {A} {return E0}
+ {B} {return F0}
+ {P0} {return 80}
+ {P1} {return 90}
+ {P2} {return A0}
+ {P3} {return B0}
+ {P4} {return C0}
+ {DPH} {return 83}
+ {DPL} {return 82}
+ {DP1H} {return 85}
+ {DP1L} {return 84}
+ {SBUFR} {return 99}
+ {SBUFT} {return 199}
+ {SCON} {return 98}
+ {TH1} {return 8D}
+ {TL1} {return 8B}
+ {TH0} {return 8C}
+ {TL0} {return 8A}
+ {TCON} {return 88}
+ {TMOD} {return 89}
+ {PCON} {return 87}
+ {IE} {return A8}
+ {IP} {return B8}
+ {SP} {return 81}
+ {PSW} {return D0}
+ {Acc} {return E0}
+ {T2CON} {return C8}
+ {T2MOD} {return C9}
+ RCAP2L {return CA}
+ RCAP2H {return CB}
+ {TL2} {return CC}
+ {TH2} {return CD}
+ {AUXR1} {return A2}
+ WDTRST {return A6}
+ {AUXR} {return 8E}
+ CLKREG {return 8F}
+ CKCON {return 8F}
+ ACSR {return 97}
+ IPH {return B7}
+ SADDR {return A9}
+ SADEN {return B9}
+ SPCR {return D5}
+ SPSR {return AA}
+ SPDR {return 86}
+ WDTCON {return A7}
+ WDTPRG {return A7}
+ EECON {return 96}
+ }
+ }
+
+ ## Translate hexadecimal address to register symbolic name
+ # @parm String regName - Register hexadecimal address (eg. '8C')
+ # @return String - Register name (eg. 'TH0') or void
+ public method to_hex_addr_symb_name {hex} {
+ switch -- $hex {
+ {E0} {return A_hex}
+ {F0} {return B_hex}
+ {E0} {return A}
+ {F0} {return B}
+ {80} {return P0}
+ {90} {return P1}
+ {A0} {return P2}
+ {B0} {return P3}
+ {C0} {return P4}
+ {83} {return DPH}
+ {82} {return DPL}
+ {85} {return DP1H}
+ {84} {return DP1L}
+ {99} {return SBUFR}
+ {199} {return SBUFT}
+ {98} {return SCON}
+ {8D} {return TH1}
+ {8C} {return TH0}
+ {8B} {return TL1}
+ {8A} {return TL0}
+ {89} {return TMOD}
+ {88} {return TCON}
+ {87} {return PCON}
+ {A8} {return IE}
+ {B8} {return IP}
+ {81} {return SP}
+ {D0} {return PSW}
+ {E0} {return Acc}
+ {C8} {return T2CON}
+ {C9} {return T2MOD}
+ {CA} {return RCAP2L}
+ {CB} {return RCAP2H}
+ {CC} {return TL2}
+ {CD} {return TH2}
+ {A2} {return AUXR1}
+ {A6} {return WDTRST}
+ {8E} {return AUXR}
+ {97} {return ACSR}
+ {B7} {return IPH}
+ {A9} {return SADDR}
+ {B9} {return SADEN}
+ {D5} {return SPCR}
+ {AA} {return SPSR}
+ {86} {return SPDR}
+ {96} {return EECON}
+ {8F} {
+ if {[$this get_feature_avaliable ckcon]} {
+ return {CKCON}
+ } {
+ return {CLKREG}
+ }
+ }
+ {A7} {
+ if {[$this get_feature_avaliable wdtcon]} {
+ return {WDTCON}
+ } {
+ return {WDTPRG}
+ }
+ }
+ }
+ }
+
+ ## Switch active register bank (Current bank number is based on bits SFR(RS0) SFR(RS1))
+ # @return void
+ public method sim_switch_bank {} {
+ if {!$gui_initialized} {return}
+
+ # Determinate bank offset
+ set bnk [$this getBank]
+ set index [expr {$bnk * 8}]
+
+ # Synchronize active bank register entries
+ for {set i 0} {$i < 8} {incr i} {
+ set value [subst "\$::Simulator_GUI::ENV${obj_idx}_DATA([expr {$index + $i}])"]
+ set ::Simulator_GUI::ENV${obj_idx}_R$i $value
+ }
+ }
+
+ ## Validate content of R0..R7 entry
+ # @parm String number - String to validate
+ # @parm Int idx - Register index
+ # @return Bool - result
+ public method entry_Rx_validate {number idx} {
+
+ # Check for enabled validations
+ if {$disable_validation} {return 1}
+
+ # This function cannot run multithreaded
+ if {!$Rx_validation_ena} {return 1}
+ set Rx_validation_ena 0
+
+ # Validate entry content
+ set result [entry_2_hex_validate $number]
+ # Synchronize
+ if {$result} {
+ # Determinate address
+ if {$number == {}} {set number 0}
+ set bnk [$this getBank]
+ incr idx [expr {$bnk * 8}]
+
+ # Synchronize with low RAM
+ set ::Simulator_GUI::ENV${obj_idx}_DATA($idx) $number
+ $hexeditor setValue $idx [expr "0x$number"]
+ $this setData $idx $number
+
+ # Update help window
+ set hex_addr [format "%X" $idx]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ }
+ $this rightPanel_watch_sync $hex_addr
+ help_window_update $hex_addr $number
+ $this cvarsview_sync E $idx
+ }
+
+ # Successul ...
+ set Rx_validation_ena 1
+ return $result
+ }
+
+ ## Validate and synchronize SFR entry
+ # @parm String number - String to validate
+ # @parm String reg - Register name (eg. 'PSW')
+ # @return Bool - result
+ public method entry_2_hex_validate_and_sync {number reg} {
+ # Validate
+ set result [entry_2_hex_validate $number]
+ # Synchronize
+ if {$result && [string length $number] && !$disable_sync} {
+ set hex_addr [symb_name_to_hex_addr $reg]
+ set dec_addr [expr "0x$hex_addr"]
+ $this setSfr $dec_addr $number
+ set dec_val [expr "0x$number"]
+ $this sfr_watches_sync $dec_addr $dec_val
+ $this sfrmap_map_sync $dec_addr $dec_val
+ help_window_update [list $hex_addr {SFR}] $number
+ $this cvarsview_sync I $dec_addr
+ }
+ # Done ...
+ return $result
+ }
+
+ ## Synchronize content low ram register entry 0..31 (first four banks)
+ # @parm Int addr - Register address
+ # @parm String number - String to validate
+ # @return Bool - result
+ private method entry_bank_reg_sync {addr number} {
+ # Check for enabled validations
+ if {$disable_validation} {return 1}
+
+ if {!$Rx_validation_ena} {
+ if {!$disable_sync} {
+ $this setData $addr $number
+ $this rightPanel_watch_sync [format "%X" $addr]
+ }
+ return 1
+ }
+ set Rx_validation_ena 0
+
+ # Synchronize with Rx
+ if {$number == {}} {set number 0}
+ set bnk [expr {$addr / 8}]
+ set idx [expr {$addr % 8}]
+ if {$bnk == [$this getBank]} {
+ set ::Simulator_GUI::ENV${obj_idx}_R${idx} $number
+ }
+
+ # Synchronize with Right panel and Engine
+ if {!$disable_sync} {
+ $this setData $addr $number
+ set hex_addr [format "%X" $addr]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ }
+ $this rightPanel_watch_sync $hex_addr
+ $this stack_monitor_sync $addr
+ help_window_update $hex_addr $number
+ $this cvarsview_sync E $addr
+ }
+
+ # Done
+ set Rx_validation_ena 1
+ return 1
+ }
+
+ ## Synchronize content of entry in hex view of low RAM (addr: 0x20..0x7F)
+ # @parm Int addr - Register adddress (32..127)
+ # @parm String number - String to validate
+ # @return Bool - result
+ public method entry_idata_reg_sync {addr number} {
+ # Check for enabled validations
+ if {$disable_validation} {return 1}
+
+ # Synchronize with engine (and other)
+ if {!$disable_sync} {
+ # Synchronize with engine
+ $this setData $addr $number
+ # Determinate hexadecimal representation of the content
+ set hex_addr [format "%X" $addr]
+ if {[string length $hex_addr] == 1} {
+ set hex_addr "0$hex_addr"
+ }
+ # Synchronize with the Right Panel
+ $this Simulator_sync_reg $addr
+ }
+
+ return 1
+ }
+
+ ## Validate content of general hexadecimal entry for 2 digits
+ # @parm String number - string to validate
+ # @return Bool - result
+ proc entry_2_hex_validate {number} {
+ if {[string length $number] > 2} {return 0}
+ if {[regexp {^[0-9A-Fa-f]*$} $number]} {return 1}
+ return 0
+ }
+
+ ## Create RAM help window
+ # @parm String addr -
+ # XXh (hexadecimal eg. A5h) -
+ # 4 digits == XDATA
+ # 3 digits == EDATA
+ # 2 digits == IDATA (not SFR)
+ # Dot and 2 digits == Bit in IDATA or SFR
+ # DD (decimal eg. 224) - IDATA memory only
+ # SSS (string eg. PSW) - SFR only
+ # @return void
+ public method create_help_window_ram args {
+ set addr [lindex $args 0] ;# Register address
+
+ catch {destroy ${::HELPWINDOW}}
+ set ::HELPWINDOW {}
+
+ ## Hexadecimal address
+ # 4 digits == XDATA; 3 digits == EDATA; 2 digits == IDATA (not SFR)
+ if {[regexp {^[A-Fa-f0-9]+h$} $addr]} {
+ # Determinate address
+ set addr [string range $addr 0 {end-1}]
+ set addr_dec [expr "0x$addr"]
+ # Determinate value
+ set len [string length $addr]
+ if {$len < 3} {
+ if {![$this simulator_address_range I $addr_dec]} {return}
+ set val [$this getData $addr_dec]
+ } elseif {$len == 3} {
+ if {![$this simulator_address_range E $addr_dec]} {return}
+ set val [$this getEram $addr_dec]
+ } else {
+ if {![$this simulator_address_range X $addr_dec]} {return}
+ set val [$this getXdata $addr_dec]
+ }
+
+ # Decimal address (IDATA memory only)
+ } elseif {[string is digit $addr]} {
+ # Determinate value
+ set val [$this getData $addr]
+ # Determinate address
+ if {![$this simulator_address_range I $addr]} {return}
+ set addr [format "%X" $addr]
+ if {[string length $addr] == 1} {
+ set addr "0$addr"
+ }
+
+ # Bit
+ } elseif {[string index $addr 0] == {.}} {
+ set addr [string replace $addr end end]
+ set addr [string replace $addr 0 0]
+ set val [$this getBit [expr {"0x$addr"}]]
+ append addr { BIT}
+
+ # Register name (SFR only)
+ } else {
+ set val [subst "\$::Simulator_GUI::ENV${obj_idx}_$addr"]
+ set addr [symb_name_to_hex_addr $addr]
+ append addr { SFR}
+ }
+
+ # Create help window
+ create_help_window . $val $addr
+ }
+
+ ## Validate content of clock entry (frequency in kHz)
+ # @parm String number - string to validate
+ # @return Bool - result
+ public method clock_validate {number} {
+ # Check for allowed characters
+ if {![string is digit -strict $number]} {
+ return 0
+ }
+
+ # Check for allowed range
+ if {$number > 99999} {
+ return 0
+ }
+
+ # Synchronize
+ $this configure -P_option_clock $number ;# Project variable
+ $this setEngineClock $number ;# Set clock in simulator engine
+ $this Simulator_sync_clock ;# Rewrite time entry
+
+ # Done ...
+ return 1
+ }
+
+ ## Call haxeditor with the given arguments
+ # @parm String args - any arguments
+ # @return void
+ public method simulator_hexeditor {args} {
+ if {!$gui_initialized} {return}
+ eval "$hexeditor $args"
+ }
+
+ ## Binding for event CellValueChanged in hexeditor
+ # @parm Int address - Address of changed cell
+ # @parm Int value - New cell value
+ # @return void
+ public method simulator_hexedit_value_changed {address value} {
+ # Convert value to hexadecimal representation
+ set value [format %X $value]
+ if {[string length $value] == 1} {
+ set value "0$value"
+ }
+
+ # Synchronize
+ if {$address < 32} {
+ set ::Simulator_GUI::ENV${obj_idx}_DATA($address) $value
+ entry_bank_reg_sync $address $value
+ } {
+ entry_idata_reg_sync $address $value
+ }
+ }
+
+ ## Adjust scrollbar for scrollable area (simulator panel)
+ # @parm Char orient - Scrollbar orientation (one of {x y})
+ # @parm Float frac0 - 1st fraction
+ # @parm Float frac0 - 2nd fraction
+ # @return void
+ public method simulator_gui_scroll_set {orient frac0 frac1} {
+ if {$orient == {x}} {
+ set scrollbar $horizontal_scrollbar
+ } {
+ set scrollbar $vertical_scrollbar
+ }
+
+ # Hide scrollbar
+ if {$frac0 == 0 && $frac1 == 1} {
+ if {[winfo ismapped $scrollbar]} {
+ pack forget $scrollbar
+ update
+ }
+ # Show scrollbar
+ } {
+ if {![winfo ismapped $scrollbar]} {
+ if {$orient == {x}} {
+ pack $scrollbar -fill x -side top -before $scrollable_frame
+ } {
+ pack $scrollbar -fill y -side left
+ }
+ }
+ $scrollbar set $frac0 $frac1
+ update
+ }
+ }
+
+ ## Unset NS variables
+ # @return void
+ public method SimGUI_clean_up {} {
+ foreach var $entry_variables {
+ catch {
+ unset ::Simulator_GUI::ENV${obj_idx}_${var}
+ }
+ }
+ if {$gui_initialized} {
+ menu_Sbar_remove $bitmenu
+ }
+ }
+
+ ## Disable synchronization with simulator engine
+ # @return void
+ public method SimGUI_disable_sync {} {
+ set disable_sync 1
+ }
+
+ ## Enable synchronization with simulator engine
+ # @return void
+ public method SimGUI_enable_sync {} {
+ set disable_sync 0
+ }
+
+ ## Change image on button "Step over" (from "Pause" to "Goto" or backwards)
+ # @return void
+ public method invert_stepover_button {} {
+ if {!$gui_initialized || !$sim_enabled} {return}
+
+ # Determinate ID of the current image
+ set image [$ctrl_f.controls_quick_step cget -image]
+ # Change image
+ if {$image == {::ICONS::16::goto2}} {
+ $ctrl_f.controls_quick_step configure -image ::ICONS::16::player_pause
+ } {
+ $ctrl_f.controls_quick_step configure -image ::ICONS::16::goto2
+ }
+ }
+
+ ## Change image on button "Animate" (from "Pause" to "Right arrow" or backwards)
+ # @return void
+ public method invert_animate_button {} {
+ if {!$gui_initialized || !$sim_enabled} {return}
+
+ # Determinate ID of the current image
+ set image [$ctrl_f.controls_animate cget -image]
+ # Change image
+ if {$image == {::ICONS::16::1rightarrow}} {
+ $ctrl_f.controls_animate configure -image ::ICONS::16::player_pause
+ } {
+ $ctrl_f.controls_animate configure -image ::ICONS::16::1rightarrow
+ }
+ }
+
+ ## Change image on button "Run" (from "Pause" to "Double right arrow" or backwards)
+ # @return void
+ public method invert_run_button {} {
+ if {!$gui_initialized || !$sim_enabled} {return}
+
+ # Determinate ID of the current image
+ set image [$ctrl_f.controls_run cget -image]
+ # Change image
+ if {$image == {::ICONS::16::2rightarrow}} {
+ $ctrl_f.controls_run configure -image ::ICONS::16::player_pause
+ } {
+ $ctrl_f.controls_run configure -image ::ICONS::16::2rightarrow
+ }
+ }
+
+ ## Set state of button "StepBack" on simulator control panel
+ # @return void
+ public method stepback_button_set_ena {bool} {
+ if {!$gui_initialized} {return}
+
+ if {$bool} {
+ set state {normal}
+ } {
+ set state {disabled}
+ }
+ $ctrl_f.controls_stepback configure -state $state
+ }
+
+ ## Disable simulator control panel (shoud be called after simulator engine disengagement)
+ # @return void
+ public method sim_disable {} {
+ if {!$gui_initialized} {return}
+
+ set sim_enabled 0 ;# Clear enabled flag
+
+ # Set icon bar to default state
+ $ctrl_f.controls_start_stop configure -image ::ICONS::16::launch
+ $ctrl_f.controls_run configure -image ::ICONS::16::2rightarrow
+ $ctrl_f.controls_animate configure -image ::ICONS::16::1rightarrow
+ $ctrl_f.controls_quick_step configure -image ::ICONS::16::goto2
+ $ctrl_f.controls_reset configure -state disabled
+ $ctrl_f.controls_stepback configure -state disabled
+ $ctrl_f.controls_step configure -state disabled
+ $ctrl_f.controls_quick_step configure -state disabled
+ $ctrl_f.controls_animate configure -state disabled
+ $ctrl_f.controls_run configure -state disabled
+
+ # Disable all register entries
+ foreach wdg $entries {
+ $wdg configure -state readonly
+ }
+ # Disable hex editor
+ $hexeditor setDisabled 1
+
+ # Disable wathdog clear button
+ if {[winfo exists $wtd_clear_button]} {
+ $wtd_clear_button configure -state disabled
+ }
+
+ $set_pc_by_line_button configure -state disabled
+
+ # Disable bit popup menu
+ $bitmenu entryconfigure [::mc "Set to 1"] -state disabled
+ $bitmenu entryconfigure [::mc "Set to 0"] -state disabled
+ }
+
+ ## Enable simulator control panel (shoud be called after simulator engine engagement)
+ # @return void
+ public method sim_enable {} {
+ if {!$gui_initialized} {CreateSimulatorGUI}
+
+ set sim_enabled 1 ;# Set enabled flag
+
+ # Set icon bar to enabled state
+ $ctrl_f.controls_start_stop configure -image ::ICONS::16::exit
+ $ctrl_f.controls_reset configure -state normal
+ $ctrl_f.controls_step configure -state normal
+ $ctrl_f.controls_quick_step configure -state normal
+ $ctrl_f.controls_animate configure -state normal
+ $ctrl_f.controls_run configure -state normal
+
+ # Enable all register entries
+ foreach wdg $entries {
+ $wdg configure -state normal
+ }
+ # Enable hex editor
+ $hexeditor setDisabled 0
+ $hexeditor focus_left_view
+
+ $set_pc_by_line_button configure -state normal
+
+ # Enable bit popup menu
+ $bitmenu entryconfigure [::mc "Set to 1"] -state normal
+ $bitmenu entryconfigure [::mc "Set to 0"] -state normal
+ }
+
+ ## Add entry widget to list of entries which need to be disabled when simulator engine is down
+ # @parm Widget widget - entry to add
+ # @return void
+ private method add_entry {widget} {
+ lappend entries $widget
+ }
+
+ ## Text output command for simulator engine
+ # @parm String text - text to display
+ # @return void
+ public method sim_txt_output {txt} {
+ tk_messageBox -title [mc "Simulator"] -type ok -message $txt
+ }
+
+ ## Focus on the given target entry widget if the current insertion index is equivalent to the end index
+ # @parm Widget this_entry - Current entry widget
+ # @parm Widget target_entry - Target entry widget
+ # @return void
+ proc sim_entry_right {this_entry target_entry} {
+ # Evaluate cursor position
+ if {[$this_entry index end] != [$this_entry index insert]} {
+ return
+ }
+ # Focus on target
+ $target_entry icursor 0
+ focus $target_entry
+ }
+
+ ## Focus on the given target entry widget if the current insertion index is equivalent to zero
+ # @parm Widget this_entry - Current entry widget
+ # @parm Widget target_entry - Target entry widget
+ # @return void
+ proc sim_entry_left {this_entry target_entry} {
+ # Evaluate cursor position
+ if {[$this_entry index insert] != 0} {return}
+ # Focus on target
+ $target_entry icursor end
+ focus $target_entry
+ }
+
+ ## Get list of avaliable SFRs
+ # @return List - {{dec_addr reg_name} ...}
+ public method simulator_get_sfrs {} {
+ if {!$gui_initialized} {CreateSimulatorGUI}
+ return $sf_registers
+ }
+
+ ## Highlight SFR label
+ # @parm Int index - Index in $sf_registers and $sf_register_labels
+ # @parm Bool bool - 1 == Highlight; 0 == Clear highlight
+ # @return void
+ public method simulator_reg_label_set_highlighted {index bool} {
+ # Determinate label widget
+ incr index -1
+ set widget [lindex $sf_register_labels $index]
+ if {$widget == {}} {
+ return
+ }
+
+ # Determinate new foreground and background color
+ if {$bool} {
+ if {[$widget cget -font] == $smallfont} {
+ set bg $small_color
+ } {
+ set bg $name_color
+ }
+ set fg {#FFFFFF}
+ } {
+ set bg {#EEEEEE}
+ if {[$widget cget -font] == $smallfont} {
+ set fg $small_color
+ } {
+ set fg $name_color
+ }
+ }
+
+ # Set new background and foreground color
+ $widget configure -bg $bg -fg $fg
+ }
+}
diff --git a/lib/simulator/stackmonitor.tcl b/lib/simulator/stackmonitor.tcl
new file mode 100755
index 0000000..8f83ab2
--- /dev/null
+++ b/lib/simulator/stackmonitor.tcl
@@ -0,0 +1,519 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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 PARTMCULAR 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# MCU stack monitor, a part of simulator GUI
+# --------------------------------------------------------------------------
+
+class StackMonitor {
+
+ ## COMMON
+ common push_value {} ;# String: Value to PUSH onto the stack by user
+ common count 0 ;# Int: Counter of intances
+ common geometry ${::CONFIG(STACK_MON_GEOMETRY)} ;# Geometry: Last window geometry
+ common collapsed ${::CONFIG(STACK_MON_COLLAPSED)};# Bool: Bottom bar hidden
+ # Font for the text widget representing the stack (bold)
+ common font0 [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ ]
+ # Font for the text widget representing the stack (normal)
+ common font1 [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight normal \
+ ]
+
+ ## PRIVATE
+ private variable dialog_opened 0 ;# Bool: Dialog window opened
+ private variable win ;# Widget: Dialog window
+ private variable obj_idx ;# Int: Object index
+ private variable enabled 0 ;# Bool: Monitor enabled
+ private variable addresses [list] ;#
+
+ private variable values_txt ;# Widget: Text widget representing the stack contents
+ private variable sp_val ;# Widget: Entry widget for SP
+ private variable col_exp_button ;# Widget: Button show/hide bottom bar (legend)
+ private variable clear_all_but ;# Widget: Button "Clear"
+ private variable push_but ;# Widget: Button "PUSH"
+ private variable pop_but ;# Widget: Button "POP"
+ private variable tool_frame ;# Widget: Frame with the bottom bar (legend)
+
+ constructor {} {
+ # Increment counter of object instances
+ incr count
+ set obj_idx $count
+ }
+
+ destructor {
+ # Close stack monitor window
+ stack_monitor_monitor_close
+ }
+
+
+ ## Invoke stack monitor window
+ # @return void
+ public method stack_monitor_invoke_dialog {} {
+ if {$dialog_opened} {
+ raise $win
+ return
+ }
+ set dialog_opened 1
+
+ # Create dialog window
+ set win [toplevel .stack_monitor$count -class {Interrupt monitor} -bg {#EEEEEE}]
+ incr count
+
+ # Create window frames (main frame and status bar, etc.)
+ set top_frame [frame $win.top_frame]
+ set bottom_frame [frame $win.bottom_frame]
+ set tool_frame [frame $win.tool_frame]
+
+ ## Create GUI part with the text widget representing the stack contents
+ set left_frame [frame $top_frame.left_frame -bd 1 -relief sunken]
+ # Text widget
+ set values_txt [text $left_frame.values_txt \
+ -width 27 -state disabled -cursor left_ptr \
+ -font $font0 -bd 0 -height 0 \
+ -yscrollcommand "$top_frame.scrollbar set" \
+ -highlightthickness 0 \
+ ]
+ # Header
+ pack [label $left_frame.header \
+ -font $font0 -width 27 \
+ -justify left -anchor w -background {#DDDDDD} \
+ -bd 0 -text [mc "Addr HH Dec Binary Oct A"] \
+ ]
+ pack $values_txt -fill y -expand 1
+ $values_txt tag configure tag_general -background {#CCCCFF}
+ $values_txt tag configure tag_subprog -background {#CCFFCC}
+ $values_txt tag configure tag_interrupt -background {#FFCCCC}
+ bind $values_txt <ButtonRelease-3> {break}
+ bind $values_txt <<Selection>> "false_selection $values_txt; break"
+ # Scrollbar
+ pack $left_frame -side left -fill y -expand 1
+ pack [ttk::scrollbar $top_frame.scrollbar \
+ -command "$values_txt yview" \
+ -orient vertical \
+ ] -side right -fill y -expand 1
+
+
+ ## Stack pointer
+ pack [label $bottom_frame.sp_lbl \
+ -text [mc "SP: "] \
+ ] -side left
+ # Create register hexadecimal entry
+ set sp_val [ttk::entry $bottom_frame.sp_val \
+ -validatecommand "$this entry_2_hex_validate_and_sync %P SP" \
+ -textvariable ::Simulator_GUI::ENV${obj_idx}_SP \
+ -font $::Simulator_GUI::entry_font \
+ -validate key \
+ -width 2 \
+ ]
+ DynamicHelp::add $sp_val -text [mc "Current stack pointer value"]
+ bindtags $sp_val [list $sp_val TEntry all .]
+ pack $sp_val -side left
+
+ ## Buttons ("Clear", "PUSH", "POP", etc.)
+ set clear_all_but [ttk::button $bottom_frame.clr_but \
+ -text [mc "Clear"] \
+ -command "$this stack_monitor_clear_all" \
+ -width 5 \
+ ]
+ pack $clear_all_but -side right
+ set push_but [ttk::button $bottom_frame.push_but \
+ -text [mc "PUSH"] \
+ -command "$this stack_monitor_manual_push" \
+ -width 5 \
+ ]
+ pack $push_but -side right
+ set pop_but [ttk::button $bottom_frame.pop_but \
+ -text [mc "POP"] \
+ -command "$this stack_monitor_manual_pop" \
+ -width 5 \
+ ]
+ pack $pop_but -side right
+ set col_exp_button [ttk::button $bottom_frame.expand_button \
+ -image ::ICONS::16::2downarrow \
+ -style Flat.TButton \
+ -command "$this stack_monitor_col_exp" \
+ -width 5 \
+ ]
+ DynamicHelp::add $sp_val -text [mc "Show/Hide tool bar"]
+ pack $col_exp_button -side right -padx 5
+
+ # Pack frames except for the bottom bar (with legend)
+ pack $top_frame -fill y -expand 1
+ pack $bottom_frame -anchor w -fill x
+
+ ## Create bottom bar (with legend)
+ pack [ttk::separator $tool_frame.sep -orient horizontal] -fill x
+ # Legend itself
+ pack [label $tool_frame.legent_lbl -text [mc "Legend:"]] -anchor w
+ pack [frame $tool_frame.lf] -fill y
+ pack [label $tool_frame.lf.gl1 -text [mc "General"] -font $font0 -bg {#CCCCFF}] -side left -fill y
+ pack [label $tool_frame.lf.sl1 -text [mc "Subprogram"] -font $font0 -bg {#CCFFCC}] -side left -fill y -padx 3
+ pack [label $tool_frame.lf.il1 -text [mc "Interrupt"] -font $font0 -bg {#FFCCCC}] -side left -fill y
+
+ # Show or keep the bottom bar hidden acording to previous session
+ if {!$collapsed} {
+ set collapsed [expr {!$collapsed}]
+ stack_monitor_col_exp
+ }
+ stack_monitor_set_enabled $enabled
+
+ # Set window attributes
+ wm iconphoto $win ::ICONS::16::kcmmemory_ST
+ wm title $win [mc "Stack - %s - MCU 8051 IDE" [string trim $this {:}]]
+ if {$geometry != {}} {
+ wm geometry $win $geometry
+ }
+ wm resizable $win 0 1
+ wm protocol $win WM_DELETE_WINDOW "$this stack_monitor_monitor_close"
+ bindtags $win [list $win Toplevel all .]
+ }
+
+ ## Close stack monitor window
+ # @return void
+ public method stack_monitor_monitor_close {} {
+ if {!$dialog_opened} {return}
+
+ set geometry [wm geometry $win]
+ set dialog_opened 0
+
+ if {[winfo exists $win]} {
+ destroy $win
+ }
+ }
+
+ ## Reset the stack monitor -- Clear all entries
+ # This should be called when the simulated MCU get reseted
+ # @return void
+ public method stack_monitor_reset {} {
+ if {!$dialog_opened} {return}
+
+ set addresses [list]
+
+ $values_txt configure -state normal
+ $values_txt delete 0.0 end
+ $values_txt configure -state disabled
+ }
+
+ ## Push a value on the MCU stack monitor
+ # In other words, this method informs the stack monitor that there was
+ #+ some value pushed on the MCU stack in simulator.
+ # This method should be called from simulator engine only.
+ # @parm Int addr - Address where the value is physicaly located
+ # @parm Int dec_val - Decimal representation of the pushed value
+ # @return void
+ public method stack_monitor_push {addr dec_val} {
+ # If the dialog is not opened then abort this
+ if {!$dialog_opened} {return}
+
+ # Adjust list of register addresses involved
+ lappend addresses $addr
+
+ # Convert address to two digits hexadecimal number
+ set str {}
+ set val [format {%X} $addr]
+ if {[string length $val] == 1} {
+ set val "0${val}"
+ }
+ append str { } $val { }
+ # Convert value to two digits hexadecimal number
+ set val [format {%X} $dec_val]
+ if {[string length $val] == 1} {
+ set val "0${val}"
+ }
+ # Convert value to three digits decimal number
+ append str $val { } [string repeat { } [expr {3 - [string length $dec_val]}]] $dec_val { }
+ # Convert value to eight digits binary number
+ set val [NumSystem::dec2bin $dec_val]
+ append str [string repeat {0} [expr {8 - [string length $val]}]] $val { }
+ # Convert value to three digits octal number
+ set val [NumSystem::dec2oct $dec_val]
+ append str [string repeat {0} [expr {3 - [string length $val]}]] $val { }
+ set val { }
+ # Convert value to one character long ASCII representation
+ if {$dec_val >= 0x20 && $dec_val <= 0x7E} {
+ set val [format %c $dec_val]
+ }
+ append str $val "\n"
+
+ # Show it to user
+ $values_txt configure -state normal
+ $values_txt insert 1.0 $str
+ $values_txt configure -state disabled
+ }
+
+ ## Mark a few most recent values as values of certain type
+ # @parm Int type -
+ # 0 - General
+ # 1 - Subprogram return address
+ # 2 - Interrupt routine return address
+ # @parm Int length - Number of bytes to mask
+ # @return void
+ public method stack_monitor_set_last_values_as {type length} {
+ if {!$dialog_opened} {return}
+
+ switch -- $type {
+ 0 {set tag {tag_general}}
+ 1 {set tag {tag_subprog}}
+ 2 {set tag {tag_interrupt}}
+ }
+
+ for {set i 1} {$i <= $length} {incr i} {
+ $values_txt tag add $tag $i.0 $i.4
+ }
+ }
+
+ ## Pop a value from the MCU stack monitor
+ # In other words, this method informs the stack monitor that there was
+ #+ some value poped from the MCU stack in simulator.
+ # @return void
+ public method stack_monitor_pop {} {
+ if {!$dialog_opened} {return}
+
+ set addresses [lreplace $addresses end end]
+
+ $values_txt configure -state normal
+ $values_txt delete 1.0 2.0
+ $values_txt configure -state disabled
+ }
+
+
+ ## Show or hide bottom panel with legend
+ # @return void
+ public method stack_monitor_col_exp {} {
+ set collapsed [expr {!$collapsed}]
+
+ if {$collapsed} {
+ set image 2downarrow
+ pack forget $tool_frame
+ } {
+ set image 2uparrow
+ pack $tool_frame -fill y -anchor nw
+ }
+
+ $col_exp_button configure -image ::ICONS::16::$image
+ }
+
+
+ ## Pop the last pushed value manually (do it also in the simulator)
+ # @return void
+ public method stack_monitor_manual_pop {} {
+ if {!$dialog_opened || !$enabled} {return}
+
+ # Decrement SP register
+ set sp [$this getSfrDEC 129]
+ if {!$sp} {return}
+ $this setSfr 129 [format {%x} [expr {$sp - 1}]]
+ $this Simulator_GUI_sync S 129
+
+ stack_monitor_pop
+ }
+
+
+ ## Push a value manually (do it also in the simulator)
+ # This method just pushes a value previously entered via the dialog
+ #+ intended for that purpose
+ # @return void
+ public method stack_monitor_manual_push_val {} {
+ # Retrieve the value from the dialog GUI
+ set value ${::StackMonitor::push_value}
+
+ # Check validity of the value
+ if {$value == {}} {
+ return
+ }
+ if {![string is xdigit $value]} {
+ return
+ }
+
+ # Convert it from hexadecimal to decimal
+ set value [expr "0x$value"]
+ if {$value > 255 || $value < 0} {
+ return
+ }
+
+ ## Push it on the MCU stack
+ set foo ${::Simulator::reverse_run_steps}
+ $this stack_push $value
+ $this Simulator_sync_reg [$this getSfrDEC 129]
+ stack_monitor_set_last_values_as 0 1
+ $this Simulator_GUI_sync S 129
+ set ::Simulator::reverse_run_steps $foo
+ }
+
+ ## Invoke dialog intended for pushing values on the stack
+ # @return void
+ public method stack_monitor_manual_push {} {
+ # Stack monitor must be opened and enabled ...
+ if {!$dialog_opened || !$enabled} {return}
+
+ # This dialog cannot be opened more than once at the time
+ if {[winfo exists .manual_push${obj_idx}]} {
+ raise .manual_push${obj_idx}
+ return
+ }
+
+ # Create toplevel window
+ set dlg [toplevel .manual_push${obj_idx} -class {Push value onto stack} -bg {#EEEEEE}]
+
+ # Create label, entryBox and horizontal separator
+ pack [label $dlg.lbl -text [mc "Push value onto stack (HEX)"]] -fill x -anchor w -padx 5
+ pack [ttk::entry $dlg.ent \
+ -width 3 \
+ -validate all \
+ -textvariable ::StackMonitor::push_value \
+ -validatecommand {apply {p {
+ if {[string length $p] > 2 || ![string is xdigit $p]} {
+ return 0
+ } else {
+ return 1
+ }
+ }} %P
+ }
+ ] -fill x -padx 10 -side left
+ bindtags $dlg.ent [list $dlg.ent TEntry $dlg $win all .]
+
+ bind $dlg.ent <Return> "$this stack_monitor_manual_push_val"
+ bind $dlg.ent <KP_Enter> "$this stack_monitor_manual_push_val"
+
+ # Create button frame
+ set buttonFrame [frame $dlg.buttonFrame]
+ pack [ttk::button $buttonFrame.ok \
+ -width 5 \
+ -text [mc "PUSH"] \
+ -compound left \
+ -image ::ICONS::16::down0 \
+ -command "$this stack_monitor_manual_push_val" \
+ ] -side left
+ pack [ttk::button $buttonFrame.cancel \
+ -width 5 \
+ -text [mc "Close"] \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -command "
+ grab release $dlg
+ destroy $dlg" \
+ ] -side left
+ pack $buttonFrame -side right -padx 5
+
+ # Set window attributes
+ wm iconphoto $dlg ::ICONS::16::kcmmemory_ST
+ wm title $dlg [mc "Push value onto stack."]
+ wm minsize $dlg 200 60
+ wm protocol $dlg WM_DELETE_WINDOW "
+ grab release $dlg
+ destroy $dlg"
+ raise $dlg
+ update
+ focus $dlg.ent
+ }
+
+
+ ## Clear contents of the monitor and do not affect simulator engine
+ # This method shoul be called on user request. It asks for confimation.
+ # @return void
+ public method stack_monitor_clear_all {} {
+ if {!$dialog_opened || !$enabled} {return}
+
+ # Confirmation
+ if {[tk_messageBox \
+ -type yesno \
+ -default yes \
+ -icon question \
+ -parent $win \
+ -title [mc "Confirmation"] \
+ -message [mc "Do you really want to clear the list without any effect in simulator engine ?"]
+ ] != {yes}} {
+ return
+ }
+
+ # Clear all
+ set addresses [list]
+ $values_txt configure -state normal
+ $values_txt delete 0.0 end
+ $values_txt configure -state disabled
+ }
+
+ ## Enable or disable the stack monitor
+ # When simulator get started or stopped this method should be used to
+ #+ inform the dialog about it
+ # @parm Bool bool - 1 == Enable; 0 == Disable
+ # @return void
+ public method stack_monitor_set_enabled {bool} {
+ set enabled $bool
+ if {!$dialog_opened} {return}
+
+ if {$enabled} {
+ set state {normal}
+ } {
+ set state {disabled}
+ }
+
+ $clear_all_but configure -state $state
+ $push_but configure -state $state
+ $pop_but configure -state $state
+ $sp_val configure -state $state
+ }
+
+ ## Synchronize the stack monitor with the simulator engine
+ # @parm Int addr - Address of register to synchronize
+ # @return void
+ public method stack_monitor_sync {addr} {
+ if {!$dialog_opened} {return}
+
+ # Determinate whether the specified address is involved in the stack
+ set idx [lsearch -ascii -exact $addresses $addr]
+ if {$idx == -1} {return}
+
+ # Get the new value of the register
+ set idx [expr {[llength $addresses] - $idx}]
+ set dec_val [$this getDataDEC $addr]
+
+ # Display the new value to the user ...
+ set val [format {%X} $dec_val]
+ if {[string length $val] == 1} {
+ set val "0${val}"
+ }
+ append str $val { } [string repeat { } [expr {3 - [string length $dec_val]}]] $dec_val { }
+ set val [NumSystem::dec2bin $dec_val]
+ append str [string repeat {0} [expr {8 - [string length $val]}]] $val { }
+ set val [NumSystem::dec2oct $dec_val]
+ append str [string repeat {0} [expr {3 - [string length $val]}]] $val { }
+ set val { }
+ if {$dec_val >= 0x20 && $dec_val <= 0x7E} {
+ set val [format %c $dec_val]
+ }
+ append str $val
+ $values_txt configure -state normal
+ $values_txt delete $idx.5 [list $idx.0 lineend]
+ $values_txt insert $idx.5 $str
+ $values_txt configure -state disabled
+ }
+}
diff --git a/lib/simulator/stopwatch.tcl b/lib/simulator/stopwatch.tcl
new file mode 100755
index 0000000..407cdd3
--- /dev/null
+++ b/lib/simulator/stopwatch.tcl
@@ -0,0 +1,702 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Stopwatch timer for MCU simulator
+# --------------------------------------------------------------------------
+
+class Stopwatch {
+ ## Class variables
+ common count 0 ;# Int: Counter of class instances
+ # List: Short names of stopwatch entries
+ common stats_keys {
+ US CC IC
+ IP PB IN
+ SC RT RI
+ BR
+ }
+ # List: Full names of stopwatch entries
+ common stats_names {
+ {Micro seconds} {Clock cycles} {Instruction cycles}
+ {Instructions passed} {Program bytes} {Interrupts}
+ {Subprogram calls} {RET} {RETI}
+ {Breakpoints}
+ }
+ # Normal font (for entry boxes)
+ common normal_font [font create \
+ -family Helvetica \
+ -size -12 -weight normal\
+ ]
+ # Bold font (for entry boxes)
+ common bold_font [font create \
+ -family Helvetica \
+ -size -12 -weight bold \
+ ]
+
+ ## Private varibales
+ private variable win ;# Widget: Dialog window
+ private variable obj_idx ;# Int: Current object number
+ private variable entryboxes ;# Array of Widget: Entry boxes
+ private variable clearbuttons ;# Array of Widget: Clear buttons
+ private variable dialog_opened 0 ;# Bool: 1 == Dialog opened; 0 == Dialog closed
+ private variable status_bar_lbl ;# Widget: Status bar label widget
+ private variable start_stop_button ;# Widget: Button "Start / Stop"
+ private variable label_stopped_lbl ;# Widget: Label "Stoppped"
+ private variable stopwatch_on 1 ;# Bool: Stopwatch running
+ private variable window_geometry {} ;# Geometry: Window geometry
+
+ constructor {} {
+ # Configure ttk styles
+ if {!$count} {
+ ttk::style configure Stopwatch.TEntry -fieldreadonlybackground {#F8F8F8}
+ ttk::style configure Stopwatch_Focused_D.TEntry -fieldbackground {#AAAAFF} -fieldreadonlybackground {#AAAAFF}
+ ttk::style configure Stopwatch_Focused_I.TEntry -fieldbackground {#DDDDFF} -fieldreadonlybackground {#DDDDFF}
+ }
+
+ # Increment counter of object instances
+ set obj_idx $count
+ incr count
+
+ # Restore configuration from the previous session
+ set i 0
+ set window_geometry [lindex ${::CONFIG(STOPWATCH_CONFIG)} $i]
+ incr i
+ set val [lindex ${::CONFIG(STOPWATCH_CONFIG)} $i]
+ if {![string is digit -strict $val]} {
+ set val 0
+ }
+ set ::Stopwatch::text_vars${obj_idx}(stop_sim) $val
+ incr i
+ foreach key $stats_keys {
+ set val [lindex ${::CONFIG(STOPWATCH_CONFIG)} $i]
+ if {![string is digit -strict $val]} {
+ set val 0
+ }
+ set ::Stopwatch::text_vars${obj_idx}($key,S) $val
+ incr i
+ }
+ }
+
+ destructor {
+ catch {
+ array unset ::Stopwatch::text_vars${obj_idx}
+ }
+ }
+
+ ## Close window
+ # @return void
+ public method stopwatch_close {} {
+ set window_geometry [wm geometry $win]
+ destroy $win
+ set dialog_opened 0
+ }
+
+ ## Open window
+ # @return void
+ public method stopwatch_invoke_dialog {} {
+ if {$dialog_opened} {return}
+ set win [toplevel .stopwatch$obj_idx -class {Stopwatch} -bg {#EEEEEE}]
+ set dialog_opened 1
+ set stopwatch_on 1
+
+ stopwatch_create_gui
+ stopwatch_refresh
+
+ bind $win <Control-Key-q> "destroy $win; break"
+ bindtags $win [list $win Toplevel all .]
+
+ wm title $win "[mc {Stopwatch}] - [string trim $this {:}] - MCU 8051 IDE"
+ wm iconphoto $win ::ICONS::22::history
+ wm protocol $win WM_DELETE_WINDOW "$this stopwatch_close"
+ catch {
+ wm geometry $win $window_geometry
+ }
+ }
+
+ ## Refresh window content (adjust to current simulator state)
+ # @return void
+ public method stopwatch_refresh {} {
+ if {!$dialog_opened} {return}
+
+ array set run_statistics [$this get_run_statistics]
+ set run_statistics(0) [expr {$run_statistics(0) / 1000}]
+ set i 0
+ set org_O 0
+ set stop_a 0
+ foreach key $stats_keys {
+ # Overall
+ set org_O [subst "\$::Stopwatch::text_vars${obj_idx}($key,O)"]
+ set ::Stopwatch::text_vars${obj_idx}($key,O) $run_statistics($i)
+
+ # Current
+ if {$stopwatch_on} {
+ incr ::Stopwatch::text_vars${obj_idx}($key,C) [expr {$run_statistics($i) - $org_O}]
+ set stop_a [subst "\$::Stopwatch::text_vars${obj_idx}($key,S)"]
+
+ # Conditional stop
+ if {$stop_a && $stop_a <= [subst "\$::Stopwatch::text_vars${obj_idx}($key,C)"]} {
+ stopwatch_start_stop
+ if {[subst "\$::Stopwatch::text_vars${obj_idx}(stop_sim)"]} {
+ if {[$this sim_run_in_progress]} {
+ $this sim_run
+ } elseif {[$this sim_anim_in_progress]} {
+ $this sim_animate
+ }
+ }
+ }
+ }
+ incr i
+ }
+ }
+
+ ## Create window GUI
+ # @return void
+ private method stopwatch_create_gui {} {
+
+ ## Create bottom frame (status bar)
+ set bottom_frame [frame $win.bottom_frame]
+ set status_bar_lbl [label $bottom_frame.status_lbl \
+ -anchor w -justify left \
+ ]
+ pack $status_bar_lbl -fill x -side left
+
+
+ ## Create toolbar
+ set top_frame [frame $win.top_frame]
+ # - Button "Start / Stop"
+ set button [ttk::button $top_frame.start_but \
+ -command "$this stopwatch_start_stop" \
+ -style ToolButton.TButton \
+ -image ::ICONS::22::player_pause \
+ ]
+ set start_stop_button $button
+ pack $button -side left -anchor w
+ DynamicHelp::add $top_frame.start_but -text ""
+ local_status_tip $top_frame.start_but [mc "Stop"]
+ # - Separator
+ pack [ttk::separator $top_frame.sep0 \
+ -orient vertical \
+ ] -side left -fill y -anchor w -padx 2
+ # - Button "Save as plain text"
+ set button [ttk::button $top_frame.save_but \
+ -command "$this stopwatch_save 1" \
+ -image ::ICONS::22::filesave \
+ -style ToolButton.TButton \
+ ]
+ pack $button -side left -anchor w
+ DynamicHelp::add $top_frame.save_but -text ""
+ local_status_tip $top_frame.save_but [mc "Save as plain text"]
+ # - Button "Save as XHTML"
+ set button [ttk::button $top_frame.export_but \
+ -command "$this stopwatch_save 0" \
+ -image ::ICONS::22::html \
+ -style ToolButton.TButton \
+ ]
+ pack $button -side left -anchor w
+ DynamicHelp::add $top_frame.export_but -text ""
+ local_status_tip $top_frame.export_but [mc "Save as XHTML"]
+ # - Separator
+ pack [ttk::separator $top_frame.sep1 \
+ -orient vertical \
+ ] -side left -fill y -anchor w -padx 2
+ # - Button "Close"
+ set button [ttk::button $top_frame.exit_but \
+ -command "$this stopwatch_close" \
+ -image ::ICONS::22::exit \
+ -style ToolButton.TButton \
+ ]
+ pack $button -side left -anchor w
+ DynamicHelp::add $top_frame.exit_but -text ""
+ local_status_tip $top_frame.exit_but [mc "Close window"]
+ # - Label "STOPPED"
+ set label_stopped_lbl [label $top_frame.label_stopped_lbl \
+ -font [font create \
+ -family {Helvetica} -size -21 -weight bold \
+ ] -text {STOPPED} -fg {#FF0000} -pady 0 \
+ ]
+
+ ## Create main frame
+ set main_frame [frame $win.main_frame]
+ # Create horizontal headers
+ grid [label $main_frame.lbl_h_0 \
+ -text [mc "Current"] \
+ ] -sticky we -row 0 -column 2
+ grid [ttk::button $main_frame.clr_C_but \
+ -image ::ICONS::16::clear_left_r \
+ -command "$this stopwatch_clear_all C" \
+ -style Flat.TButton \
+ ] -sticky w -row 0 -column 3
+ DynamicHelp::add $main_frame.clr_C_but \
+ -text [mc "Clear all"]
+ local_status_tip $main_frame.clr_C_but [mc "Clear all"]
+ grid [label $main_frame.lbl_h_1 \
+ -text [mc "Stop after"] \
+ ] -sticky we -row 0 -column 5
+ grid [ttk::button $main_frame.clr_S_but \
+ -style Flat.TButton \
+ -image ::ICONS::16::clear_left_r \
+ -command "$this stopwatch_clear_all S" \
+ ] -sticky w -row 0 -column 6
+ DynamicHelp::add $main_frame.clr_S_but \
+ -text [mc "Clear all"]
+ local_status_tip $main_frame.clr_S_but [mc "Clear all"]
+ grid [label $main_frame.lbl_h_2 \
+ -text [mc "Overall"] \
+ ] -sticky we -row 0 -column 8 -columnspan 2
+
+ # Create matrix of entryboxes (and vertical headers)
+ set row 1
+ foreach text $stats_names key $stats_keys {
+ # Vertical header
+ grid [label $main_frame.lbl_f_$row \
+ -text [mc $text] \
+ ] -sticky w -row $row -column 0
+
+ # Create 3 entryboxes and 2 clear buttons
+ set col 2
+ foreach tp {C S O} {
+ # Create clear button
+ if {$tp != {O}} {
+ set clearbuttons($key,$tp) [ttk::button $main_frame.clrbut_${key}_$tp \
+ -style Flat.TButton \
+ -image ::ICONS::16::clear_left \
+ -command "$this stopwatch_clear_entrybox $key $tp" \
+ ]
+ DynamicHelp::add $main_frame.clrbut_${key}_$tp \
+ -text [mc "Clear entrybox"]
+ }
+
+ # Clear entrybox
+ set entrybox [ttk::entry $main_frame.entry_${key}_$tp \
+ -validatecommand "$this stopwatch_entrybox_validator $key $tp %P" \
+ -textvariable ::Stopwatch::text_vars${obj_idx}($key,$tp) \
+ -style Stopwatch.TEntry \
+ -validate key \
+ -width 12 \
+ ]
+ bind $entrybox <Key-Up> "$this stopwatch_entry_key $key $tp up; break"
+ bind $entrybox <Key-Down> "$this stopwatch_entry_key $key $tp down; break"
+ bind $entrybox <Key-Left> "$this stopwatch_entry_key $key $tp left; break"
+ bind $entrybox <Key-Right> "$this stopwatch_entry_key $key $tp right; break"
+ bind $entrybox <Key-Tab> "$this stopwatch_entry_key $key $tp tab; break"
+ if {!$::MICROSOFT_WINDOWS} {
+ bind $entrybox <Key-ISO_Left_Tab> "$this stopwatch_entry_key $key $tp stab; break"
+ }
+ bind $entrybox <Key-Return> "$this stopwatch_entry_key $key $tp enter; break"
+ bind $entrybox <Key-KP_Enter> "$this stopwatch_entry_key $key $tp enter; break"
+ bind $entrybox <FocusIn> "$this stopwatch_entry_focus $key $tp 1"
+ bind $entrybox <FocusOut> "$this stopwatch_entry_focus $key $tp 0"
+ bindtags $entrybox [list $entrybox TEntry $win all .]
+
+ grid $entrybox -row $row -column $col -sticky we
+ set entryboxes($key,$tp) $entrybox
+ incr col
+
+ if {$tp == {O}} {
+ break
+ }
+
+ local_status_tip $clearbuttons($key,$tp) [mc "Clear"]
+ grid $clearbuttons($key,$tp) -row $row -column $col -sticky w
+ incr col 2
+ }
+
+ set ::Stopwatch::text_vars${obj_idx}($key,C) 0
+ set ::Stopwatch::text_vars${obj_idx}($key,O) 0
+ $entryboxes($key,O) configure -state readonly
+ incr row
+ }
+
+ # Create checkbutton "Stop simulation"
+ grid [checkbutton $main_frame.stop_sim_chb \
+ -variable ::Stopwatch::text_vars${obj_idx}(stop_sim) \
+ -text [mc "Stop simulation"] \
+ ] -row $row -column 5 -sticky w -columnspan 2
+
+ # Configure columns in main frame
+ grid columnconfigure $main_frame 1 -minsize 10
+ grid columnconfigure $main_frame 4 -minsize 10
+ grid columnconfigure $main_frame 7 -minsize 10
+
+
+ # Show dialog frames
+ pack $top_frame -anchor w -pady 5 -padx 5 -fill x
+ pack $main_frame -fill both -expand 1 -padx 10
+ pack $bottom_frame -fill x
+ }
+
+ ## Entybox event handler for <FocusIn> and <FocusOut>
+ # @parm String key - Short entry name (from list: $stats_keys)
+ # @parm Char type - Entry type (C == "Current"; S == "Stop after"; O == "Overall")
+ # @parm Bool focused - 1 == <FocusIn>; 0 == <FocusOut>
+ # @return void
+ public method stopwatch_entry_focus {key type focused} {
+ if {$focused} {
+ $entryboxes($key,C) configure -style Stopwatch_Focused_I.TEntry
+ $entryboxes($key,S) configure -style Stopwatch_Focused_I.TEntry
+ $entryboxes($key,$type) configure -style Stopwatch_Focused_D.TEntry
+ } {
+ $entryboxes($key,$type) selection clear
+ $entryboxes($key,C) configure -style TEntry
+ $entryboxes($key,S) configure -style TEntry
+ $entryboxes($key,$type) configure -style TEntry
+ }
+ }
+
+ ## Entybox event handler for <Key-Up>, <Key-Down>, <Key-Left>, <Key-Right>, <Key-Tab>,
+ #+ <Key-ISO_Left_Tab>, <Key-Return> and <Key-KP_Enter>
+ # @parm String ekey - Short entry name (from list: $stats_keys)
+ # @parm Char type - Entry type (C == "Current"; S == "Stop after"; O == "Overall")
+ # @parm String kkey - Key name (e.g. "down")
+ # @return void
+ public method stopwatch_entry_key {ekey type kkey} {
+ set entrybox $entryboxes($ekey,$type)
+ set insert [$entrybox index insert]
+ set y [lsearch -ascii -exact $stats_keys $ekey]
+ set max_y [llength $stats_keys]
+ incr max_y -1
+ switch -- $type {
+ C {set x 0}
+ S {set x 1}
+ O {set x 2}
+ }
+
+ $entrybox selection clear
+ switch -- $kkey {
+ {up} {
+ if {!$y} {
+ return
+ }
+ incr y -1
+ }
+ {down} {
+ if {$y == $max_y} {
+ return
+ }
+ incr y
+ }
+ {left} {
+ if {!$x || $insert} {
+ $entrybox icursor [expr {$insert-1}]
+ return
+ }
+ incr x -1
+ }
+ {right} {
+ if {($x == 2) || ($insert != [$entrybox index end])} {
+ $entrybox icursor [expr {$insert+1}]
+ return
+ }
+ incr x
+ }
+ {tab} {
+ if {$x == 2} {
+ return
+ }
+ incr x
+ }
+ {stab} {
+ if {!$x} {
+ return
+ }
+ incr x -1
+ }
+ {enter} {
+ if {$y == $max_y} {
+ return
+ }
+ incr y
+ }
+ }
+
+ set insert [expr {[$entrybox index end] - $insert}]
+ set entrybox $entryboxes([lindex $stats_keys $y],[lindex {C S O} $x])
+ $entrybox selection range 0 end
+ $entrybox icursor [expr {[$entrybox index end] - $insert}]
+ focus $entrybox
+ }
+
+ ## Set local status tip
+ # @parm Widget wdg - Target widget
+ # @parm String txt - Status tip text
+ # @return void
+ private method local_status_tip {wdg txt} {
+ bind $wdg <Enter> [list $status_bar_lbl configure -text $txt]
+ bind $wdg <Leave> [list $status_bar_lbl configure -text {}]
+ }
+
+ ## Validator procedure for all entryboxes in the dialog
+ # @parm String key - Short entry name (from list: $stats_keys)
+ # @parm Char type - Entry type (C == "Current"; S == "Stop after"; O == "Overall")
+ # @parm String string - Suggested content
+ # @return Bool - Validation result (1 == Allowed; 0 == Denied)
+ public method stopwatch_entrybox_validator {key type string} {
+ # Validate input string
+ if {[string length $string] > 19 || ![string is digit $string]} {
+ return 0
+ }
+
+ # Adjust foreground color for entrybox in column "Current"
+ if {$type == {C} && $string != {}} {
+ set max [subst "\$::Stopwatch::text_vars${obj_idx}($key,S)"]
+ if {$max && $string >= $max} {
+ $entryboxes($key,C) configure -fg {#FF0000} -font $bold_font
+ } {
+ $entryboxes($key,C) configure -fg {#000000} -font $normal_font
+ }
+ }
+
+ # Adjust clear button
+ if {$type == {C} || $type == {S}} {
+ if {$string != {} && $string != 0} {
+ $clearbuttons($key,$type) configure -state normal
+ } {
+ $clearbuttons($key,$type) configure -state disabled
+ }
+ }
+
+ return 1
+ }
+
+ ## Clear all entryboxes in the specified column
+ # @parm Char what - Entry type (C == "Current"; S == "Stop after"; O == "Overall")
+ # @return void
+ public method stopwatch_clear_all {what} {
+ foreach key $stats_keys {
+ set ::Stopwatch::text_vars${obj_idx}($key,$what) 0
+ }
+ }
+
+ ## Clear the specified entrybox
+ # @parm String key - Short entry name (from list: $stats_keys)
+ # @parm Char type - Entry type (C == "Current"; S == "Stop after"; O == "Overall")
+ # @return void
+ public method stopwatch_clear_entrybox {key type} {
+ set ::Stopwatch::text_vars${obj_idx}($key,$type) 0
+ }
+
+ ## Invoke file selection dialog to save content of stopwatch into a file
+ # @parm Bool text__html - File type (1 == Plain text; 0 == XHTML)
+ # @return void
+ public method stopwatch_save {text__html} {
+ # Determinate list of avaliable file extensions
+ if {$text__html} {
+ set filetypes [list \
+ [list [::mc "Text files"] {*.txt}] \
+ [list [::mc "All files"] {*}] \
+ ]
+ } {
+ set filetypes [list \
+ [list [::mc "HTML files"] {*.html}] \
+ [list [::mc "All files"] {*}] \
+ ]
+ }
+
+ # Invoke the file selection dialog
+ KIFSD::FSD ::fsd \
+ -title [mc "Save stopwatch state - MCU 8051 IDE"] \
+ -directory [$this cget -projectPath] \
+ -master $win -filetypes [mc $filetypes] \
+ -defaultmask 0 -multiple 0 \
+ -initialfile [string trim $this {:}]
+
+ # Open file after press of OK button
+ ::fsd setokcmd "
+ ::fsd deactivate
+ $this stopwatch_savefile_proc $text__html \
+ \[file normalize \[file join \
+ \[$this cget -ProjectDir\] \
+ \[::fsd get\] \
+ \]\]
+ "
+
+ # Activate the dialog
+ ::fsd activate
+ }
+
+ ## Save content of stopwatch into the specified file
+ # @parm Bool text__html - File type (1 == Plain text; 0 == XHTML)
+ # @parm String filename - Full name of the target file
+ # @return void
+ public method stopwatch_savefile_proc {text__html filename} {
+ # Adjust filename extension
+ if {![string length [file extension $filename]]} {
+ if {$text__html} {
+ append filename {.txt}
+ } {
+ append filename {.html}
+ }
+ }
+
+ # Create backup file
+ if {[file exists $filename] && [file isfile $filename]} {
+ # Ask user for overwrite existing file
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent $win \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $filename]]
+ ] != {yes}
+ } {
+ return
+ }
+ # Create a backup file
+ catch {
+ file rename -force $filename "$filename~"
+ }
+ }
+
+ # Open the specified file
+ if {[catch {
+ set file [open $filename w 420]
+ }]} {
+ tk_messageBox \
+ -parent . \
+ -type ok \
+ -icon warning \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to open file:\n'%s'" $filename]
+ return
+ }
+
+ # Save as plain text
+ if {$text__html} {
+ set text {}
+ append text [string repeat { } 33] "Current" \
+ [string repeat { } 10] "Stop after" \
+ [string repeat { } 13] "Overall"
+ puts $file $text
+ foreach text $stats_names key $stats_keys {
+ set text [mc $text]
+ append text [string repeat { } [expr {20 - [string length $text]}]]
+ foreach subkey {C S O} {
+ set val [subst "\$::Stopwatch::text_vars${obj_idx}($key,$subkey)"]
+ append text [string repeat { } [expr {20 - [string length $val]}]] $val
+ }
+ puts $file $text
+ }
+
+ puts $file "\nProject: [string trim $this {:}]"
+ puts $file "Date: [clock format [clock seconds] -format {%D}]"
+ puts $file "Generated by ${::APPNAME} ( http://mcu8051ide.sf.net )"
+
+ # Save as XHTML
+ } {
+ puts $file "<?xml version='1.0' encoding='utf-8' standalone='no'?>"
+ puts $file "<!DOCTYPE html PUBLIC"
+ puts $file "\t'-//W3C//DTD XHTML 1.1//EN'"
+ puts $file "\t'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'>"
+ puts $file "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en'>"
+ puts $file "<!--\n\tCreator: ${::APPNAME}\n\tDate: [clock format [clock seconds] -format {%D}]\n-->"
+ puts $file "\t<head>"
+ puts $file "\t\t<title>[string trim $this {:}] stopwatch state [clock format [clock seconds] -format {%D}]</title>"
+ puts $file "\t\t<meta http-equiv=\"Content-Type\" content=\"application/xhtml+xml; charset=UTF-8\" />"
+ puts $file "\t\t<meta name=\"Generator\" content=\"${::APPNAME}\" />"
+ puts $file "\t\t<style type=\"text/css\">"
+ puts $file "\t\t\t.sw_header {"
+ puts $file "\t\t\t\tfont-weight: normal;"
+ puts $file "\t\t\t}"
+ puts $file "\t\t\t.sw_C {"
+ puts $file "\t\t\t\tbackground-color: #FFEEEE;"
+ puts $file "\t\t\t\tfont-weight: bold;"
+ puts $file "\t\t\t\ttext-align: right;"
+ puts $file "\t\t\t}"
+ puts $file "\t\t\t.sw_S {"
+ puts $file "\t\t\t\tbackground-color: #EEFFEE;"
+ puts $file "\t\t\t\tfont-weight: bold;"
+ puts $file "\t\t\t\ttext-align: right;"
+ puts $file "\t\t\t}"
+ puts $file "\t\t\t.sw_O {"
+ puts $file "\t\t\t\tbackground-color: #EEEEFF;"
+ puts $file "\t\t\t\tfont-weight: bold;"
+ puts $file "\t\t\t\ttext-align: right;"
+ puts $file "\t\t\t}"
+ puts $file "\t\t</style>"
+ puts $file "\t</head>"
+ puts $file "\t<body>"
+ puts $file "\t\t<table style=\"border-width: 1px\">"
+ puts $file "\t\t\t<col /><col /><col /><col />"
+ puts $file "\t\t\t<thead>"
+ puts $file "\t\t\t\t<tr class=\"sw_header\"><th>&nbsp;</th><th>Current</th><th>Stop after</th><th>Overall</th></tr>"
+ puts $file "\t\t\t</thead>"
+ puts $file "\t\t\t<tbody>"
+ foreach text $stats_names key $stats_keys {
+ puts $file "\t\t\t\t<tr>"
+ puts $file "\t\t\t\t\t<td class=\"sw_header\">[mc $text]</td>"
+ foreach subkey {C S O} {
+ puts -nonewline $file "\t\t\t\t\t<td class=\"sw_$subkey\">"
+ puts -nonewline $file [subst "\$::Stopwatch::text_vars${obj_idx}($key,$subkey)"]
+ puts $file "</td>"
+ }
+ puts $file "\t\t\t\t</tr>"
+ }
+ puts $file "\t\t\t</tbody>"
+ puts $file "\t\t</table>"
+
+ puts $file "\t\t<p>"
+ puts $file "\t\t\tProject: <b>[string trim $this {:}]</b><br />"
+ puts $file "\t\t\tDate: <b>[clock format [clock seconds] -format {%D}]</b><br />"
+ puts $file "\t\t\tGenerated by ${::APPNAME} ( <a href=\"http://mcu8051ide.sf.net\">http://mcu8051ide.sf.net</a> )"
+ puts $file "\t\t</p>"
+
+ puts $file "\t</body>"
+ puts $file "</html>"
+ }
+
+ # Close target file
+ close $file
+ }
+
+ ## Enable / Disable stopwatch (swith between states ON and OFF)
+ # @return void
+ public method stopwatch_start_stop {} {
+ set stopwatch_on [expr {!$stopwatch_on}]
+
+ # Start
+ if {$stopwatch_on} {
+ $start_stop_button configure -image ::ICONS::22::player_pause
+ local_status_tip $start_stop_button [mc "Stop"]
+ pack forget $label_stopped_lbl
+ # Stop
+ } {
+ $start_stop_button configure -image ::ICONS::22::player_play
+ local_status_tip $start_stop_button [mc "Start"]
+ pack $label_stopped_lbl -side right -pady 0 -ipady 0
+ }
+ }
+
+ ## Get configuration list (for session save procedure)
+ # @return void
+ public method stopwatch_get_config {} {
+ set result $window_geometry
+ lappend result [subst "\$::Stopwatch::text_vars${obj_idx}(stop_sim)"]
+
+ foreach key $stats_keys {
+ lappend result [subst "\$::Stopwatch::text_vars${obj_idx}($key,S)"]
+ }
+
+ return $result
+ }
+}
diff --git a/lib/simulator/virtual_uart_term.tcl b/lib/simulator/virtual_uart_term.tcl
new file mode 100755
index 0000000..29f3199
--- /dev/null
+++ b/lib/simulator/virtual_uart_term.tcl
@@ -0,0 +1,646 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2010 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# UART monitor
+# -------------------------------------------------------------------------
+
+# LOAD PROGRAM ICONS
+# -----------------------------
+if {$argv0 != {./virtual_uart_term.tcl}} {
+ set D 0
+} {
+ set D 1
+}
+if {$D} {
+ package require Tk
+ package require img::png
+ package require Itcl
+ namespace import -force ::itcl::*
+ package require msgcat
+ namespace import -force ::msgcat::*
+ package require BWidget
+ set ::DEFAULT_FIXED_FONT {DejaVu Sans Mono}
+ set ::MICROSOFT_WINDOWS 0
+
+ set LIB_DIRNAME "/media/disk/mcu8051ide/lib"
+ source "$LIB_DIRNAME/lib/hexeditor.tcl"
+
+ foreach directory {16x16 22x22 32x32} ns {16 22 32} {
+ namespace eval ::ICONS::${ns} {}
+ foreach filename [glob "${::LIB_DIRNAME}/../icons/${directory}/*.png"] {
+ set filename [file normalize $filename]
+ set iconname [file tail $filename]
+ regexp {^\w+} $iconname iconname
+ if {[catch {
+ image create photo ::ICONS::${ns}::${iconname} -format png -file $filename
+ } result]} then {
+ puts stderr {}
+ puts -nonewline stderr $result
+ image create photo ::ICONS::${ns}::${iconname}
+ }
+ }
+ }
+
+ proc menuFactory {pattern path tearoff cmdPrefix shortcuts options} {
+
+ # Create menu widget
+ eval "menu $path -tearoff $tearoff $options"
+
+ # Iterate over menu definition list
+ foreach menuitem $pattern {
+ # Create array of options
+ for {set i 0} {$i < 9} {incr i} {
+ set menu($i) [lindex $menuitem $i]
+ }
+ # Determinate kind of operation
+ switch $menu(0) {
+ {command} {
+ # Item icon
+ if {$menu(5) != {}} {
+ set menu(5) "::ICONS::16::$menu(5)"
+ }
+
+ # Adjust accelerator value
+ set menu(2) $menu(2)
+
+ # Create menu command
+ $path add command \
+ -label [mc $menu(1)] \
+ -accelerator $menu(2) \
+ -underline $menu(3) \
+ -command "$cmdPrefix$menu(4)" \
+ -image $menu(5) -compound left
+
+ # Status bar tip
+ if {$menu(6) != {}} {
+ set itemIndex [$path index end]
+ menu_Sbar_add $path $itemIndex [mc $menu(6)]
+ bind $path <<MenuSelect>> "menu_Sbar $path \[%W index active\]"
+ bind $path <Leave> {Sbar {}}
+ }
+ }
+ {separator} {$path add separator}
+ {radiobutton} {
+ # Adjust command
+ if {$menu(5) != {}} {
+ set menu(5) "${cmdPrefix}$menu(5)"
+ }
+
+ # Adjust accelerator value
+ set menu(2) [adjust_menu_accelerator $menu(2)]
+
+ # Create radio button item
+ $path add radiobutton \
+ -label [mc $menu(1)] \
+ -accelerator $menu(2) \
+ -variable $menu(3) \
+ -value $menu(4) \
+ -command $menu(5) \
+ -underline $menu(6) \
+ -compound left \
+ -indicatoron 0 \
+ -image ::ICONS::raoff \
+ -selectimage ::ICONS::raon \
+ -selectcolor {#EEEEEE}
+
+ # Status bar tip
+ if {$menu(7) != {}} {
+ set itemIndex [$path index end]
+ menu_Sbar_add $path $itemIndex [mc $menu(7)]
+ bind $path <<MenuSelect>> "menu_Sbar $path \[%W index active\]"
+ bind $path <Leave> {Sbar {}}
+ }
+ }
+ {checkbutton} {
+ # Adjust command
+ if {$menu(7) != {}} {
+ set menu(7) "${cmdPrefix}$menu(7)"
+ }
+ # Adjust accelerator value
+ set menu(2) [adjust_menu_accelerator $menu(2)]
+
+ # Create checkbutton item
+ $path add checkbutton \
+ -label [mc $menu(1)] \
+ -accelerator $menu(2) \
+ -variable $menu(3) \
+ -onvalue $menu(4) \
+ -offvalue $menu(5) \
+ -underline $menu(6) \
+ -command $menu(7) \
+ -compound left \
+ -image ::ICONS::choff \
+ -indicatoron 0 \
+ -selectimage ::ICONS::chon \
+ -selectcolor {#EEEEEE}
+ # Status bar tip
+ if {$menu(8) != {}} {
+ set itemIndex [$path index end]
+ menu_Sbar_add $path $itemIndex [mc $menu(8)]
+ bind $path <<MenuSelect>> "menu_Sbar $path \[%W index active\]"
+ bind $path <Leave> {Sbar {}}
+ }
+ }
+ {cascade} {
+ # Adjust menu name
+ set menu(4) "$path$menu(4)"
+ # Create new menu for cascade
+ if {$menu(7) != {}} {
+ menuFactory $menu(7) $menu(4) $menu(5) $cmdPrefix $menu(6) $options
+ }
+ # Item icon
+ if {$menu(3) != {}} {
+ set menu(3) "::ICONS::16::$menu(3)"
+ }
+ # Add cascade to this menu
+ $path add cascade -label [mc $menu(1)] -underline $menu(2) \
+ -image $menu(3) -menu $menu(4) -compound left
+ }
+ {} {return}
+ default {
+ error "Menu creation failed -- unknown type: $menu(0)"
+ return -code 1
+ }
+ }
+ }
+ }
+
+ ttk::style theme use clam
+ # - ttk
+ set TTK_COMMON_BG {#E0E0E0}
+ ttk::style configure TFrame \
+ -background {#EEEEEE}
+
+ ttk::style configure TNotebook \
+ -background {#EEEEEE} \
+ -fieldbackground {red}
+ ttk::style map TNotebook \
+ -background [list \
+ active red \
+ pressed blue \
+ pressed green \
+ ]
+
+ font configure TkTextFont -family {helvetica} -size -12 -weight {normal}
+ font configure TkDefaultFont -family {helvetica} -size -12 -weight {normal}
+
+ ttk::style configure StringNotFound.TEntry \
+ -fieldbackground {#FFDDDD}
+ ttk::style configure StringFound.TEntry \
+ -fieldbackground {#DDFFDD}
+
+ ttk::style configure Simulator.TEntry
+ ttk::style map Simulator.TEntry \
+ -fieldbackground [list readonly {#F8F8F8}] \
+ -foreground [list readonly {#888888}]
+ ttk::style configure Simulator_HG.TEntry \
+ -foreground {#CC8800}
+ ttk::style configure Simulator_WhiteBg.TEntry \
+ -fieldbackground {#FFFFFF} \
+ -fielddisabledbackground {#FFFFFF}
+ ttk::style configure Simulator_WhiteBg_HG.TEntry \
+ -fieldbackground {#FFFFFF} \
+ -fielddisabledbackground {#FFFFFF} \
+ -foreground {#CC8800}
+ ttk::style configure Simulator_WhiteBg_Sel.TEntry \
+ -fieldbackground {#DDDDFF} \
+ -fielddisabledbackground {#DDDDFF}
+ ttk::style configure Simulator_WhiteBg_HG_Sel.TEntry \
+ -foreground {#CC8800} \
+ -fieldbackground {#DDDDFF} \
+ -fielddisabledbackground {#DDDDFF}
+
+ ttk::style configure Simulator_watchdogEntry_0.TEntry \
+ -fieldbackground {#88FF88} \
+ -fielddisabledbackground {#66DD66}
+ ttk::style map Simulator_watchdogEntry_0.TEntry \
+ -foreground [list readonly {#888888}]
+
+ ttk::style configure Simulator_watchdogEntry_1.TEntry \
+ -fieldbackground {#FFFF55} \
+ -fielddisabledbackground {#DDDD33}
+ ttk::style map Simulator_watchdogEntry_1.TEntry \
+ -foreground [list readonly {#888888}]
+
+ ttk::style configure Simulator_watchdogEntry_2.TEntry \
+ -fieldbackground {#FF5555} \
+ -fielddisabledbackground {#DD3333}
+ ttk::style map Simulator_watchdogEntry_2.TEntry \
+ -foreground [list readonly {#888888}]
+
+ ttk::style configure TLabelframe \
+ -background {#EEEEEE}
+ ttk::style configure TLabel \
+ -background {#EEEEEE}
+
+ ttk::style configure TButton \
+ -background $TTK_COMMON_BG \
+ -padding 0
+ ttk::style configure RedBg.TButton \
+ -padding 0
+ ttk::style map RedBg.TButton \
+ -background [list \
+ active {#FFBBBB} \
+ !active {#FF8888} \
+ ] \
+ -foreground [list \
+ active {#FF0000} \
+ !active {#000000} \
+ ]
+ ttk::style configure GreenBg.TButton \
+ -padding 0
+ ttk::style map GreenBg.TButton \
+ -background [list \
+ active {#BBFFBB} \
+ !active {#88FF88} \
+ ] \
+ -foreground [list \
+ active {#00FF00} \
+ !active {#000000} \
+ ]
+
+ ttk::style configure Flat.TButton \
+ -background {#EEEEEE} \
+ -padding 0 \
+ -borderwidth 1 \
+ -relief flat
+ ttk::style map Flat.TButton \
+ -relief [list active raised] \
+ -background [list disabled {#EEEEEE}]
+
+ ttk::style configure TMenubutton \
+ -padding 0 \
+ -background $TTK_COMMON_BG
+ ttk::style configure Flat.TMenubutton \
+ -padding 0 \
+ -background {#EEEEEE} \
+ -borderwidth 1 \
+ -relief flat
+ ttk::style map Flat.TMenubutton \
+ -relief [list active raised] \
+ -background [list disabled {#EEEEEE}]
+
+ ttk::style configure FlatWhite.TButton \
+ -padding 0 \
+ -background {#FFFFFF} \
+ -borderwidth 1 \
+ -relief flat
+ ttk::style map FlatWhite.TButton \
+ -relief [list active raised] \
+ -background [list disabled {#FFFFFF}]
+
+ ttk::style configure ToolButton.TButton \
+ -background {#EEEEEE} \
+ -padding 1 \
+ -borderwidth 1 \
+ -relief flat
+ ttk::style map ToolButton.TButton \
+ -relief [list active raised] \
+ -background [list disabled {#EEEEEE}]
+
+ ttk::style configure TCombobox \
+ -background $TTK_COMMON_BG \
+ -fieldfont [font create -family {helvetica} -size -12 -weight {normal}]
+ ttk::style map TCombobox \
+ -foreground [list disabled {#888888}] \
+ -fieldbackground [list \
+ readonly $TTK_COMMON_BG \
+ disabled {#EEEEEE} \
+ {!readonly !disabled} {#FFFFFF} \
+ ]
+
+ ttk::style configure TScrollbar \
+ -background $TTK_COMMON_BG \
+ -troughcolor {#F8F8F8}
+
+ ttk::style configure TScale \
+ -background $TTK_COMMON_BG
+ ttk::style map TScale \
+ -troughcolor [list \
+ disabled $TTK_COMMON_BG \
+ !disabled {#F8F8F8} \
+ ]
+
+ ttk::style configure TProgressbar \
+ -background $TTK_COMMON_BG \
+ -troughcolor {#F8F8F8}
+ wm withdraw .
+}
+
+class VirtualUartTerminal {
+ ## COMMON
+ common count 0 ;# Counter of intances
+ # Font: Big bold font
+ common bold_font [font create \
+ -family {helvetica} \
+ -size -12 -weight {bold} \
+ ]
+ # Font: Tiny normal font
+ common tiny_font [font create \
+ -family {helvetica} \
+ -size -9 -weight {normal} \
+ ]
+ # Font: Tiny bold font
+ common tiny_font_bold [font create \
+ -family {helvetica} \
+ -size -9 -weight {bold} \
+ ]
+ # Font: Normal font
+ common normal_font [font create \
+ -family {helvetica} \
+ -size -11 -weight {normal} \
+ ]
+ # Font: Also normal font, but a bit larger
+ common big_font [font create \
+ -family {helvetica} \
+ -size -12 -weight {normal} \
+ ]
+ # List of Int: Available baud rates for RS232
+ common available_baud_rates {
+ 50 75 110 134 150 200
+ 300 600 1200 1800 2400 4800
+ 9600 19200 38400 57600 115200 230400
+ 460800
+ }
+
+ ## PRIVATE
+ private variable dialog_opened 0 ;# Bool: Dialog window opened
+ private variable win ;# Widget: Dialog window
+ private variable status_bar_label ;# Widget: Status bar
+
+ private variable too_baud_conf {9600} ;# Int: Selected baud rate for communication
+ private variable too_parity_conf {n} ;# Char: Selected type of parity
+ private variable too_data_conf {8} ;# Int: Number of data bits
+ private variable too_stop_conf {1} ;# Int: Number of stop bits
+
+ constructor {} {
+ }
+
+ destructor {
+ }
+
+ ## Close interrupt monitor window and free its resources
+ # @return void
+ public method virtual_uart_termial_close {} {
+ if {!$dialog_opened} {
+ return
+ }
+
+ set geometry [wm geometry $win]
+ set dialog_opened 0
+ set in_progress_wdg {}
+ set in_progress_flg {}
+ set pending_flg {}
+ set intr_priorities {}
+ set avaliable_interrs {}
+
+ if {[winfo exists $win]} {
+ destroy $win
+ }
+ }
+
+ ## Invoke interrupt monitor window
+ # @return void
+ public method virtual_uart_termial_invoke_dialog {} {
+ set dialog_opened 1
+
+ # Create window
+ set win [toplevel .virtual_uart_term$count -class [mc "UART Monitor"] -bg {#EEEEEE}]
+ incr count
+
+ # Create status bar
+ set status_bar_label [label $win.status_bar_label -justify left -pady 0 -anchor w]
+ pack $status_bar_label -side bottom -fill x
+
+ # Create top frame
+ set top_frame [frame $win.top_frame]
+ create_top_frame $top_frame
+ pack $top_frame -fill x -anchor nw
+
+ # Create bottom frame
+ set bottom_frame [frame $win.bottom_frame]
+ create_bottom_frame $bottom_frame
+ pack $bottom_frame -fill x -anchor nw
+
+ # Configure window
+ wm title $win [mc "Virtual UART Terminal - MCU 8051 IDE"]
+ wm iconphoto $win ::ICONS::16::_blockdevice
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "$this virtual_uart_termial_close"
+ }
+
+ ## Set status bar tip for specified widget
+ # @parm Widget widget - Target widget
+ # @parm String text - Text of the stutus tip
+ # @return void
+ private method virtual_uart_termial_set_status_tip {widget text} {
+ bind $widget <Enter> "$status_bar_label configure -text {$text}"
+ bind $widget <Leave> "$status_bar_label configure -text {}"
+ }
+
+ ## Create top frame in the dialog window (connector_canvas (left) and configuration (right))
+ # @parm Widget target_frame - Parent frame
+ # @return void
+ private method create_top_frame {target_frame} {
+ #
+ ## FRAME: OUR MICROCONTROLLER
+ #
+
+ # Create labelframe
+ set our_mcu_frame [ttk::labelframe $target_frame.our_mcu_frame \
+ -padding 5 \
+ -labelwidget [label $target_frame.our_mcu_label \
+ -font $bold_font \
+ -compound left \
+ -text [mc "\"Our Microcontroller\""] \
+ -image ::ICONS::16::configure \
+ ] \
+ ]
+ pack [label $our_mcu_frame.l -text "AAAA"]
+ pack $our_mcu_frame -side left -fill x -expand 1 -padx 5
+
+
+ #
+ ## FRAME: THE OTHER DEVICE
+ #
+
+ # Create labelframe
+ set the_other_one_frame [ttk::labelframe \
+ $target_frame.the_other_one_frame \
+ -padding 5 \
+ -labelwidget [label $target_frame.too_label \
+ -font $bold_font \
+ -compound left \
+ -text [mc "Terminal configuration"] \
+ -image ::ICONS::16::configure \
+ ] \
+ ]
+ # - Baud rate
+ grid [label $the_other_one_frame.baud_lbl \
+ -text [mc "Baud rate"] \
+ ] -row 3 -column 1 -sticky w
+ set baud_cb [ttk::combobox $the_other_one_frame.baud_cb \
+ -state readonly \
+ -width 6 \
+ -exportselection 0 \
+ -values $available_baud_rates \
+ ]
+ bind $baud_cb <<ComboboxSelected>> \
+ "$this change_port_config b \[$the_other_one_frame.baud_cb get\]"
+ virtual_uart_termial_set_status_tip $baud_cb [mc "Connection speed in bps"]
+ grid $baud_cb -row 3 -column 2 -sticky w
+ $the_other_one_frame.baud_cb current [lsearch [$the_other_one_frame.baud_cb cget -values] $too_baud_conf]
+ # - Parity
+ grid [label $the_other_one_frame.parity_lbl \
+ -text [mc "Parity"] \
+ ] -row 4 -column 1 -sticky w
+ set parity_cb [ttk::combobox $the_other_one_frame.parity_cb \
+ -values {none odd even mark space} \
+ -state readonly \
+ -width 6 \
+ -exportselection 0 \
+ ]
+ bind $parity_cb <<ComboboxSelected>> \
+ "$this change_port_config p \[$the_other_one_frame.parity_cb get\]"
+ virtual_uart_termial_set_status_tip $parity_cb [mc "Parity"]
+ grid $parity_cb -row 4 -column 2 -sticky w
+ $the_other_one_frame.parity_cb current [lsearch {n o e m s} $too_parity_conf]
+ # - Data bits
+ grid [label $the_other_one_frame.data_lbl \
+ -text [mc "Data bits"] \
+ ] -row 5 -column 1 -sticky w
+ set data_cb [ttk::combobox $the_other_one_frame.data_cb \
+ -state readonly \
+ -width 1 \
+ -values {5 6 7 8} \
+ -exportselection 0 \
+ ]
+ bind $data_cb <<ComboboxSelected>> \
+ "$this change_port_config d \[$the_other_one_frame.data_cb get\]"
+ virtual_uart_termial_set_status_tip $data_cb [mc "Number of data bits"]
+ grid $data_cb -row 5 -column 2 -sticky w
+ $the_other_one_frame.data_cb current [lsearch [$the_other_one_frame.data_cb cget -values] $too_data_conf]
+ # - Stop bits
+ grid [label $the_other_one_frame.stop_lbl \
+ -text [mc "Stop bits"] \
+ ] -row 6 -column 1 -sticky w
+ set stop_cb [ttk::combobox $the_other_one_frame.stop_cb \
+ -state readonly \
+ -width 1 \
+ -values {1 2} \
+ -exportselection 0 \
+ ]
+ bind $stop_cb <<ComboboxSelected>> \
+ "$this change_port_config s \[$the_other_one_frame.stop_cb get\]"
+ virtual_uart_termial_set_status_tip $stop_cb [mc "Number of stop bits"]
+ grid $stop_cb -row 6 -column 2 -sticky w
+ $the_other_one_frame.stop_cb current [lsearch [$the_other_one_frame.stop_cb cget -values] $too_stop_conf]
+ pack $the_other_one_frame -side left -fill x -expand 1 -padx 5
+ }
+
+ ## Create bottom frame (hexadecimal editors)
+ # @parm Widget target_frame - Parent frame
+ # @return void
+ private method create_bottom_frame {target_frame} {
+ # Create headers ("Data to send", "Received data")
+ grid [label $target_frame.lbl_a \
+ -text [mc "Data to send"] \
+ -compound right \
+ -image ::ICONS::16::forward \
+ -padx 15 -font $bold_font \
+ ] -row 0 -column 1 -columnspan 2
+ grid [label $target_frame.lbl_b \
+ -text [mc "Received data"] \
+ -compound left \
+ -image ::ICONS::16::forward \
+ -padx 15 -font $bold_font \
+ ] -row 0 -column 3 -columnspan 2
+
+ # Create hexadecimal editors
+ set send_hexeditor [HexEditor #auto \
+ $target_frame.send_hexeditor 8 32 2 \
+ hex 1 1 5 256 \
+ ]
+ [$send_hexeditor getLeftView] configure -exportselection 0
+ $send_hexeditor bindSelectionAction "$this hexeditor_selection s"
+ grid $target_frame.send_hexeditor -row 1 -column 1 -columnspan 2
+
+ set receive_hexeditor [HexEditor #auto \
+ $target_frame.receive_hexeditor 8 32 2 \
+ hex 1 1 5 256 \
+ ]
+ [$send_hexeditor getLeftView] configure -exportselection 0
+ $receive_hexeditor bindSelectionAction "$this hexeditor_selection r"
+ grid $target_frame.receive_hexeditor -row 1 -column 3 -columnspan 2
+
+ # Create buttons "Send selected" and "Clear selected" in send part
+ set send_selected_button [ttk::button \
+ $target_frame.send_selected_button \
+ -text [mc "Send selected"] \
+ -image ::ICONS::16::forward \
+ -command "$this send_selected" \
+ -compound left \
+ -state disabled \
+ ]
+ set clear_selected_snd_button [ttk::button \
+ $target_frame.clear_selected_snd_button \
+ -text [mc "Clear selected"] \
+ -image ::ICONS::16::eraser \
+ -command "$this clear_selected_snd" \
+ -compound left \
+ -state disabled \
+ ]
+ virtual_uart_termial_set_status_tip $send_selected_button [mc "Send selected data"]
+ virtual_uart_termial_set_status_tip $clear_selected_snd_button [mc "Remove selected data"]
+ grid $send_selected_button -row 2 -column 1 -sticky we
+ grid $clear_selected_snd_button -row 2 -column 2 -sticky we
+
+ # Create buttons "Receive here" and "Clear selected" in reception part
+ set receive_here_button [ttk::button \
+ $target_frame.receive_here_button \
+ -text [mc "Receive here"] \
+ -image ::ICONS::16::down0 \
+ -command "$this receive_here" \
+ -compound left \
+ ]
+ set clear_selected_rec_button [ttk::button \
+ $target_frame.clear_selected_rec_button \
+ -text [mc "Clear selected"] \
+ -image ::ICONS::16::eraser \
+ -command "$this clear_selected_rec" \
+ -compound left \
+ -state disabled \
+ ]
+ virtual_uart_termial_set_status_tip $receive_here_button [mc "Receive data on current cursor position"]
+ virtual_uart_termial_set_status_tip $clear_selected_rec_button [mc "Remove selected data"]
+ grid $receive_here_button -row 2 -column 3 -sticky we
+ grid $clear_selected_rec_button -row 2 -column 4 -sticky we
+ }
+}
+
+if {$D} {
+ VirtualUartTerminal virtual_uart_term
+ virtual_uart_term virtual_uart_termial_invoke_dialog
+}
diff --git a/lib/utilities/asciichart.tcl b/lib/utilities/asciichart.tcl
new file mode 100755
index 0000000..01ac86e
--- /dev/null
+++ b/lib/utilities/asciichart.tcl
@@ -0,0 +1,752 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Interactive ASCII chart
+# --------------------------------------------------------------------------
+
+class AsciiChart {
+ common count 0 ;# Int: Counter of object instances
+ common ASCII_TABLE ;# Array of List: ASCII table
+ array set ASCII_TABLE {
+ 0 {NUL ^@ \\0 {Null character}}
+ 1 {SOH ^A {} {Start of Header}}
+ 2 {STX ^B {} {Start of Text}}
+ 3 {ETX ^C {} {End of Text}}
+ 4 {EOT ^D {} {End of Transmission}}
+ 5 {ENQ ^E {} {Enquiry}}
+ 6 {ACK ^F {} {Acknowledgment}}
+ 7 {BEL ^G \\a {Bell}}
+ 8 {BS ^H \\b {Backspace}}
+ 9 {HT ^I \\t {Horizontal Tab}}
+ 10 {LF ^J \\n {Line feed}}
+ 11 {VT ^K \\v {Vertical Tab}}
+ 12 {FF ^L \\f {Form feed}}
+ 13 {CR ^M \\r {Carriage return}}
+ 14 {SO ^N {} {Shift Out}}
+ 15 {SI ^O {} {Shift In}}
+ 16 {DLE ^P {} {Data Link Escape}}
+ 17 {DC1 ^Q {} {Device Control 1 (oft. XON)}}
+ 18 {DC2 ^R {} {Device Control 2}}
+ 19 {DC3 ^S {} {Device Control 3 (oft. XOFF)}}
+ 20 {DC4 ^T {} {Device Control 4}}
+ 21 {NAK ^U {} {Negative Acknowledgement}}
+ 22 {SYN ^V {} {Synchronous Idle}}
+ 23 {ETB ^W {} {End of Trans. Block}}
+ 24 {CAN ^X {} {Cancel}}
+ 25 {EM ^Y {} {End of Medium}}
+ 26 {SUB ^Z {} {Substitute}}
+ 27 {ESC ^[ \\e {Escape}}
+ 28 {FS ^\\ {} {File Separator}}
+ 29 {GS ^] {} {Group Separator}}
+ 30 {RS ^^ {} {Record Separator}}
+ 31 {US ^_ {} {Unit Separator}}
+ 127 {DEL ^? {} {Delete}}
+
+ 32 {{ }} 33 ! 34 \\\" 35 #
+ 36 $ 37 % 38 & 39 '
+ 40 ( 41 ) 42 * 43 +
+ 44 , 45 - 46 . 47 /
+ 48 0 49 1 50 2 51 3
+ 52 4 53 5 54 6 55 7
+ 56 8 57 9 58 : 59 ;
+ 60 < 61 = 62 > 63 ?
+ 64 @ 65 A 66 B 67 C
+ 68 D 69 E 70 F 71 G
+ 72 H 73 I 74 J 75 K
+ 76 L 77 M 78 N 79 O
+ 80 P 81 Q 82 R 83 S
+ 84 T 85 U 86 V 87 W
+ 88 X 89 Y 90 Z 91 [
+ 92 \\ 93 ] 94 ^ 95 _
+ 96 ` 97 a 98 b 99 c
+ 100 d 101 e 102 f 103 g
+ 104 h 105 i 106 j 107 k
+ 108 l 109 m 110 n 111 o
+ 112 p 113 q 114 r 115 s
+ 116 t 117 u 118 v 119 w
+ 120 x 121 y 122 z 123 \\\{
+ 124 | 125 \\\} 126 ~
+ }
+
+ private variable obj_idx ;# Int: Object index (for entrybox textvariables)
+ private variable selected_cell -1 ;# Int: Currently selected cell
+ private variable validation_ena 1 ;# Bool: EntryBox validation enabled
+ private variable win ;# Widget: Dialog window
+ private variable window_visible 0 ;# Bool: Visibility flag
+ private variable cells ;# Array of Widget: Chart cell frames
+ private variable vh_cells ;# Array of Widget: Vertical headers
+ private variable hh_cells ;# Array of Widget: Horizontal headers
+
+ private variable status_bar_lbl ;# Widget: Status bar
+ private variable char_ent ;# Widget: Entrybox "Character:"
+ private variable hex_addr_ent ;# Widget: Entrybox "Hexadecimal address:"
+ private variable dec_addr_ent ;# Widget: Entrybox "Decimal address:"
+ private variable oct_addr_ent ;# Widget: Entrybox "Octal address:"
+ private variable bin_addr_ent ;# Widget: Entrybox "Binary address:"
+ private variable caret_not_ent ;# Widget: Entrybox "Caret notation:"
+ private variable escape_seq_ent ;# Widget: Entrybox "C escape sequence:"
+
+ constructor {} {
+ # Configure local ttk styles
+ ttk::style configure AsciiChart_BlueFg.TEntry -foreground {#0000DD}
+ ttk::style configure AsciiChart_RedFg.TEntry -foreground {#DD0000}
+
+ # Create dialog window
+ set window_visible 1
+ set win [toplevel .asciichart$count -class {ASCII chart} -bg {#EEEEEE}]
+ set obj_idx $count
+ incr count
+
+ # Create dialog GUI
+ create_gui
+
+ # Set window event bindings
+ bind $win <Control-Key-q> "::itcl::delete object $this; break"
+ bindtags $win [list $win Toplevel all .]
+
+ # Set window parameters
+ wm iconphoto $win ::ICONS::16::math_matrix
+ wm title $win "ASCII chart - MCU 8051 IDE"
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "$this close_window"
+ }
+
+ destructor {
+ destroy $win
+ }
+
+ ## Determinate wheather the window is visble or not
+ # @return Bool - Visibility flag
+ public method is_visible {} {
+ return $window_visible
+ }
+
+ ## Close dialog window, but keep object
+ # @return void
+ public method close_window {} {
+ set window_visible 0
+ wm withdraw $win
+ }
+
+ ## Restore dialog window
+ # @return void
+ public method restore_window {} {
+ set window_visible 1
+ wm deiconify $win
+ raise $win .
+ }
+
+ ## Raise dialog window (insure than it is visible)
+ # @return void
+ public method raise_window {} {
+ if {!$window_visible} {return}
+ raise $win .
+ }
+
+ ## Create window GUI
+ # @return void
+ private method create_gui {} {
+ # Create bottom frame
+ set bottom_frame [frame $win.bottom_frame]
+ set status_bar_lbl [label $bottom_frame.status_bar_lbl -justify left -anchor w]
+ pack $status_bar_lbl -side left -fill x -in $bottom_frame
+ pack [ttk::button $bottom_frame.close_but \
+ -text "Exit" \
+ -command "$this close_window" \
+ -compound left \
+ -image ::ICONS::16::exit \
+ ] -side right -padx 5 -pady 5
+
+ ## Create main frame
+ set main_frame [frame $win.main_frame -bg {#DDDDDD}]
+ # Create vertical header
+ grid [frame $main_frame.top_right_lbl -bg {#EEEEEE}] -sticky wens -row 0 -column 0
+ set header [list {} \
+ {0x0_} {0x1_} {0x2_} {0x3_} \
+ {0x4_} {0x5_} {0x6_} {0x7_} \
+ ]
+ for {set y 1} {$y < 9} {incr y} {
+ grid [label $main_frame.vh_lbl$y -text [lindex $header $y] -bg {#FFFFFF}] \
+ -row $y -column 0 -pady [expr {$y % 2}] -sticky ns
+ set vh_cells([expr {$y - 1}]) $main_frame.vh_lbl$y
+ }
+ # Create horizontal header
+ set header [list {} \
+ {0x_0} {0x_1} {0x_2} {0x_3} \
+ {0x_4} {0x_5} {0x_6} {0x_7} \
+ {0x_8} {0x_9} {0x_A} {0x_B} \
+ {0x_C} {0x_D} {0x_E} {0x_F} \
+ ]
+ for {set x 1} {$x < 17} {incr x} {
+ grid [label $main_frame.hh_lbl$x -text [lindex $header $x] -bg {#FFFFFF}] \
+ -row 0 -column $x -padx [expr {$x % 2}] -sticky we
+ set hh_cells([expr {$x - 1}]) $main_frame.hh_lbl$x
+ }
+ # Create ASCII chart matrix
+ set hex_addr 0
+ set address 0
+ for {set y 1} {$y < 9} {incr y} {
+ for {set x 1} {$x < 17} {incr x} {
+ # Create cell frame
+ set frame [frame $main_frame.cell_$address \
+ -bg white -bd 0 \
+ ]
+
+ # Determinate hexadecimal address
+ set hex_addr [format %X $address]
+ if {$address < 16} {
+ set hex_addr "0$hex_addr"
+ }
+ set hex_addr "0x$hex_addr"
+
+ # Determinate character in the chart and color for it
+ set val [lindex $ASCII_TABLE($address) 0]
+ if {[string length $val] > 1} {
+ set foreground {#DD0000}
+ } {
+ set foreground {#0000DD}
+ }
+
+ # Create label containing character name
+ pack [label $frame.char_lbl -pady 0 \
+ -fg $foreground -bg white -text $val \
+ ]
+ # Create label containing character address
+ pack [label $frame.val_lbl \
+ -fg {#00DD00} -text $hex_addr \
+ -bg white -pady 0 \
+ ]
+
+ grid $frame -row $y -column $x -padx [expr {$x % 2}] -pady [expr {$y % 2}] -sticky we
+ set cells($address) $frame
+ foreach wdg [list $frame $frame.val_lbl $frame.char_lbl] {
+ bind $wdg <Enter> "$this cell_enter $address"
+ bind $wdg <Leave> "$this cell_leave $address"
+ bind $wdg <Button-1> "$this cell_click $address"
+ }
+ incr address
+ }
+ }
+ # Show ASCII chart
+ pack $main_frame -pady 5 -side top
+
+ ## Create details frame (character details)
+ # Create labelframe
+ set details_frame_header_frm [frame $win.details_frame_header_frm]
+ pack [label $details_frame_header_frm.lbl -text "Character: "] -side left
+ set char_ent [ttk::entry $details_frame_header_frm.ent \
+ -validatecommand "$this char_ent_validator %P" \
+ -width 4 \
+ -validate key \
+ ]
+ pack $char_ent -side left
+ set details_frame [ttk::labelframe $win.details_frame \
+ -labelwidget $details_frame_header_frm \
+ -padding 10 \
+ ]
+ # Entryboxes: HEX and DEC
+ grid [label $details_frame.hex_addr_lbl \
+ -text [mc "Hex address"] \
+ ] -row 0 -column 0 -sticky w
+ grid [label $details_frame.dec_addr_lbl \
+ -text [mc "Dec address"] \
+ ] -row 1 -column 0 -sticky w
+ set hex_addr_ent [ttk::entry $details_frame.hex_addr_ent \
+ -validatecommand "$this addr_ent_validator H %P" \
+ -validate key \
+ -width 3 \
+ ]
+ set dec_addr_ent [ttk::entry $details_frame.dec_addr_ent \
+ -validatecommand "$this addr_ent_validator D %P" \
+ -validate key \
+ -width 3 \
+ ]
+ grid $hex_addr_ent -row 0 -column 2 -sticky w
+ grid $dec_addr_ent -row 1 -column 2 -sticky w
+ # Entryboxes: OCT and BIN
+ grid [label $details_frame.oct_addr_lbl \
+ -text [mc "Oct address"] \
+ ] -row 0 -column 4 -sticky w
+ grid [label $details_frame.bin_addr_lbl \
+ -text [mc "Bin address"] \
+ ] -row 1 -column 4 -sticky w
+ set oct_addr_ent [ttk::entry $details_frame.oct_addr_ent \
+ -validate key \
+ -width 3 \
+ -validatecommand "$this addr_ent_validator O %P" \
+ ]
+ set bin_addr_ent [ttk::entry $details_frame.bin_addr_ent \
+ -validate key \
+ -width 8 \
+ -validatecommand "$this addr_ent_validator B %P" \
+ ]
+ grid $oct_addr_ent -row 0 -column 6 -sticky w
+ grid $bin_addr_ent -row 1 -column 6 -sticky w
+ # Entryboxes: "Caret notation" and "C Escape Code"
+ grid [label $details_frame.caret_not_lbl \
+ -text [mc "Caret notation"] \
+ ] -row 0 -column 8 -sticky w
+ grid [label $details_frame.escape_seq_lbl \
+ -text [mc "C Escape Code"] \
+ ] -row 1 -column 8 -sticky w
+ set caret_not_ent [ttk::entry $details_frame.caret_not_ent \
+ -validate key \
+ -width 3 \
+ -validatecommand "$this more_detail_ent_validator C %P" \
+ ]
+ set escape_seq_ent [ttk::entry $details_frame.escape_seq_ent \
+ -validate key \
+ -width 3 \
+ -validatecommand "$this more_detail_ent_validator E %P" \
+ ]
+ grid $caret_not_ent -row 0 -column 10 -sticky w
+ grid $escape_seq_ent -row 1 -column 10 -sticky w
+ # Create copy buttons (copy entrybox contents to clipboard)
+ foreach type {H D O B C E} \
+ row {0 1 0 1 0 1} \
+ col {1 1 5 5 9 9} \
+ {
+ grid [ttk::button $details_frame.copy_${type}_but \
+ -command "$this copy_contents ${type}" \
+ -image ::ICONS::16::editcopy \
+ -style Flat.TButton \
+ ] -row $row -column $col -sticky w -padx 3
+ DynamicHelp::add $details_frame.copy_${type}_but \
+ -text [mc "%s - Copy contents of entrybox to clipboard" $type]
+ bind $details_frame.copy_${type}_but <Enter> \
+ "$status_bar_lbl configure -text {[mc {Copy to clipboard}]}"
+ bind $details_frame.copy_${type}_but <Leave> \
+ "$status_bar_lbl configure -text {}"
+ }
+ # Configure event bindings for entryboxes
+ foreach widget [list \
+ $char_ent $hex_addr_ent $dec_addr_ent $oct_addr_ent \
+ $bin_addr_ent $caret_not_ent $escape_seq_ent \
+ ] {
+ bindtags $widget [list $widget TEntry $win all .]
+ }
+ # Configure details frame
+ grid columnconfigure $details_frame 3 -minsize 20
+ grid columnconfigure $details_frame 7 -minsize 20
+ grid columnconfigure $details_frame 11 -weight 1
+
+ # Finalize ...
+ pack $details_frame -padx 5 -anchor w -fill x
+ pack $bottom_frame -fill x
+ focus -force $char_ent
+ }
+
+ ## Set background color for certain cell in ASCII chart matrix
+ # @parm Int address - Cell address
+ # @parm Color color - New background color
+ # @return void
+ private method sel_bg_color {address color} {
+ $cells($address) configure -bg $color
+ $cells($address).char_lbl configure -bg $color
+ $cells($address).val_lbl configure -bg $color
+
+ $hh_cells([expr {$address & 0x0F}]) configure -bg $color
+ $vh_cells([expr {($address & 0xF0) >> 4}]) configure -bg $color
+ }
+
+ ## Handles event when mouse pointer enters certain cell in the ASCII chart
+ # @parm Int address - Cell address
+ # @return void
+ public method cell_enter {address} {
+ $status_bar_lbl configure -text [lindex $ASCII_TABLE($address) 3]
+ if {$selected_cell == $address} {
+ return
+ }
+ sel_bg_color $address {#DDFFDD}
+ }
+
+ ## Handles event when mouse pointer leaves certain cell in the ASCII chart
+ # @parm Int address - Cell address
+ # @return void
+ public method cell_leave {address} {
+ if {$selected_cell == $address} {
+ return
+ }
+ sel_bg_color $address {#FFFFFF}
+ $status_bar_lbl configure -text {}
+
+ if {$selected_cell != -1} {
+ $hh_cells([expr {$selected_cell & 0x0F}]) configure -bg {#BBBBFF}
+ $vh_cells([expr {($selected_cell & 0xF0) >> 4}]) configure -bg {#BBBBFF}
+ }
+ }
+
+ ## Handles event when clicks on certain cell in the ASCII chart
+ # @parm Int address - Cell address
+ # @return void
+ public method cell_click {address} {
+ if {$selected_cell == $address} {
+ unselect_current_cell 1 1
+ set selected_cell -1
+ return
+ }
+ select_cell $address
+ if {$selected_cell != -1} {
+ fill_entryboxes $address {}
+ }
+ }
+
+ ## Copy contents of certain entrybox to clipboard
+ # @parm Char type - Entrybox ID
+ # H - Hexadecimal address
+ # D - Decimal address
+ # O - Octal address
+ # B - Binary address
+ # C - Caret notation
+ # E - C escape sequence
+ # @return void
+ public method copy_contents {type} {
+ switch -- $type {
+ {H} {set widget $hex_addr_ent}
+ {D} {set widget $dec_addr_ent}
+ {O} {set widget $oct_addr_ent}
+ {B} {set widget $bin_addr_ent}
+ {C} {set widget $caret_not_ent}
+ {E} {set widget $escape_seq_ent}
+ }
+
+ clipboard clear
+ clipboard append [$widget get]
+ }
+
+ ## Select specified cell in ASCII chart (mark as selected and adjust details frame)
+ # @parm Int address - Cell address
+ # @return void
+ private method select_cell {address} {
+ if {$selected_cell != -1} {
+ unselect_current_cell 0 0
+ }
+ set selected_cell $address
+ sel_bg_color $address {#BBBBFF}
+ }
+
+ ## Unselect specified cell in ASCII chart (mark as normal and clear details frame)
+ # @parm Bool keep_current - Mark cell as a cell under mouse pointer (light green bg. color)
+ # @parm Bool affect_entryboxes - Clear entryboxes in details frame
+ # @return void
+ private method unselect_current_cell {keep_current affect_entryboxes} {
+ if {$selected_cell == -1} {
+ return
+ }
+
+ # Set new background color
+ if {$keep_current} {
+ sel_bg_color $selected_cell {#DDFFDD}
+ } {
+ sel_bg_color $selected_cell {#FFFFFF}
+ }
+
+ # Clear entryboxes in details frame
+ if {$affect_entryboxes} {
+ set validation_ena 0
+ foreach widget [list \
+ $char_ent $hex_addr_ent $dec_addr_ent $oct_addr_ent \
+ $bin_addr_ent $caret_not_ent $escape_seq_ent \
+ ] {
+ $widget delete 0 end
+ $widget configure -style TEntry
+ }
+ $char_ent configure -style TEntry
+ set validation_ena 1
+ }
+ }
+
+ ## Clear entryboxes in details frame
+ # @parm Char type - Entrybox to exclude
+ # M - Character
+ # H - Hexadecimal address
+ # D - Decimal address
+ # O - Octal address
+ # B - Binary address
+ # C - Caret notation
+ # E - C escape sequence
+ # @return void
+ private method clear_entryboxes {type} {
+ set validation_ena 0
+ foreach entry_type {M H D O B C E} \
+ entry_widget [list \
+ $char_ent $hex_addr_ent $dec_addr_ent $oct_addr_ent \
+ $bin_addr_ent $caret_not_ent $escape_seq_ent \
+ ] \
+ {
+ if {$type == $entry_type} {
+ continue
+ }
+ $entry_widget delete 0 end
+ $entry_widget configure -style TEntry
+ }
+ set validation_ena 1
+ }
+
+ ## Show details for character in specified address
+ # @parm Int address - Cell address
+ # @parm Char type - Entrybox to exclude
+ # M - Character
+ # H - Hexadecimal address
+ # D - Decimal address
+ # O - Octal address
+ # B - Binary address
+ # C - Caret notation
+ # E - C escape sequence
+ # @return void
+ private method fill_entryboxes {address type} {
+ clear_entryboxes $type
+ set validation_ena 0
+
+ # Character
+ if {$type != {M}} {
+ set value [lindex $ASCII_TABLE($address) 0]
+ $char_ent insert insert $value
+ if {[string length $value] > 1} {
+ $char_ent configure -style AsciiChart_RedFg.TEntry
+ } {
+ $char_ent configure -style AsciiChart_BlueFg.TEntry
+ }
+ }
+ # Hexadecimal address
+ if {$type != {H}} {
+ set value [format %X $address]
+ if {$address < 16} {
+ set value "0$value"
+ }
+ $hex_addr_ent insert insert $value
+ }
+ # Decimal address
+ if {$type != {D}} {
+ $dec_addr_ent insert insert $address
+ }
+ # Octal address
+ if {$type != {O}} {
+ $oct_addr_ent insert insert [::NumSystem::dec2oct $address]
+ }
+ # Binary address
+ if {$type != {B}} {
+ set value [::NumSystem::dec2bin $address]
+ set len [string length $value]
+ if {$len < 8} {
+ set value "[string repeat 0 [expr {8 - $len}]]$value"
+ }
+ $bin_addr_ent insert insert $value
+ }
+ # Caret notation
+ if {$type != {C}} {
+ $caret_not_ent insert insert [lindex $ASCII_TABLE($address) 1]
+ }
+ # C escape sequence
+ if {$type != {E}} {
+ $escape_seq_ent insert insert [lindex $ASCII_TABLE($address) 2]
+ }
+
+ set validation_ena 1
+ }
+
+ ## Validator for entrybox "Character"
+ # @parm String string - New entrybox contents
+ # @return Bool - Allways 1
+ public method char_ent_validator {string} {
+ if {!$validation_ena} {return 1}
+ set validation_ena 0
+
+ ## Validate input string
+ set length [string length $string]
+ if {!$length} {
+ $char_ent configure -style TEntry
+ clear_entryboxes M
+ unselect_current_cell 0 0
+ set validation_ena 1
+ return 1
+ }
+ if {$length > 3} {
+ set validation_ena 1
+ return 0
+ }
+
+ # Search for the given character in the ASCII chart
+ if {$length > 1} {
+ set string [string toupper $string]
+ }
+ for {set i 0} {$i < 128} {incr i} {
+ if {![string compare [lindex $ASCII_TABLE($i) 0] $string]} {
+ select_cell $i
+ fill_entryboxes $i M
+
+ if {$length > 1} {
+ $char_ent configure -style AsciiChart_RedFg.TEntry
+ } {
+ $char_ent configure -style AsciiChart_BlueFg.TEntry
+ }
+
+ set validation_ena 1
+ return 1
+ }
+ }
+
+ # Character not found
+ clear_entryboxes M
+ unselect_current_cell 0 0
+ $char_ent configure -style StringNotFound.TEntry
+ set validation_ena 1
+ return 1
+ }
+
+ ## Validator for entryboxes "Hex","Dec","Oct" and "Bin"
+ # @parm Char type - Source entry box
+ # H - Hexadecimal address
+ # D - Decimal address
+ # O - Octal address
+ # B - Binary address
+ # @parm String string - New entrybox contents
+ # @return Bool - Allways 1
+ public method addr_ent_validator {type string} {
+ if {!$validation_ena} {return 1}
+ set validation_ena 0
+
+ switch -- $type {
+ H {set widget $hex_addr_ent}
+ D {set widget $dec_addr_ent}
+ O {set widget $oct_addr_ent}
+ B {set widget $bin_addr_ent}
+ }
+
+ # Empty input string
+ set length [string length $string]
+ if {!$length} {
+ $widget configure -bg {#FFFFFF}
+ clear_entryboxes $type
+ unselect_current_cell 0 0
+ set validation_ena 1
+ return 1
+ }
+
+ # Validate input string and convert it into integer
+ switch -- $type {
+ H { ;# Hexadecimal
+ if {$length > 2 || ![string is xdigit -strict $string]} {
+ set validation_ena 1
+ return 0
+ }
+ set string [expr "0x$string"]
+ }
+ D { ;# Decimal
+ if {$length > 3 || ![string is digit -strict $string]} {
+ set validation_ena 1
+ return 0
+ }
+ }
+ O { ;# Octal
+ if {$length > 3 || ![regexp {^[0-7]+$} $string]} {
+ set validation_ena 1
+ return 0
+ }
+ set string [expr "0$string"]
+ }
+ B { ;# Binary
+ if {$length > 8 || ![regexp {^[01]+$} $string]} {
+ set validation_ena 1
+ return 0
+ }
+ set string [::NumSystem::bin2dec $string]
+ }
+ }
+ set string [string trimleft $string 0]
+ if {$string == {}} {
+ set string 0
+ }
+
+ # Check value range
+ if {$string > 127 || $string < 0} {
+ clear_entryboxes $type
+ unselect_current_cell 0 0
+ $widget configure -bg {#FFDDDD}
+ set validation_ena 1
+ return 1
+ }
+
+ # Adjust GUI (ACII chart and details frame)
+ select_cell $string
+ fill_entryboxes $string $type
+ $widget configure -bg {#DDFFDD}
+ return 1
+ }
+
+ ## Validator for entryboxes "Caret notation" and "C escape sequence"
+ # @parm Char type - Source entry box
+ # C - Caret notation
+ # E - C escape sequence
+ # @parm String string - New entrybox contents
+ # @return Bool - Allways 1
+ public method more_detail_ent_validator {type string} {
+ if {!$validation_ena} {return 1}
+ set validation_ena 0
+
+ # Dterminate widget object and index in ASCII chart array
+ if {$type == {C}} {
+ set widget $caret_not_ent
+ set index 1
+ } {
+ set widget $escape_seq_ent
+ set index 2
+ }
+
+ # Empty input string
+ if {![string length $string]} {
+ $widget configure -bg {#FFFFFF}
+ clear_entryboxes $type
+ unselect_current_cell 0 0
+ set validation_ena 1
+ return 1
+ }
+
+ # Inputs string must not be longer than 2 characters
+ if {[string length $string] > 2} {
+ set validation_ena 1
+ return 0
+ }
+
+ # Search for the given string in the ASCII chart array
+ for {set i 0} {$i < 128} {incr i} {
+ if {![string compare [lindex $ASCII_TABLE($i) $index] $string]} {
+ select_cell $i
+ fill_entryboxes $i $type
+
+ $widget configure -bg {#DDFFDD}
+ set validation_ena 1
+ return 1
+ }
+ }
+
+ # String not found
+ clear_entryboxes $type
+ unselect_current_cell 0 0
+ $widget configure -bg {#FFDDDD}
+ set validation_ena 1
+ return 1
+ }
+}
diff --git a/lib/utilities/baseconvertor.tcl b/lib/utilities/baseconvertor.tcl
new file mode 100755
index 0000000..ded53cb
--- /dev/null
+++ b/lib/utilities/baseconvertor.tcl
@@ -0,0 +1,912 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Utility "Base Convertor"
+# --------------------------------------------------------------------------
+
+class BaseConvertor {
+ ## COMMON
+ common count 0 ;# Int: Counter of class instances
+
+ ## PRIVATE
+ private variable win ;# Widget: Window
+ private variable win_obj ;# Object: Window object
+
+ private variable less_more_button ;# Widget: Button "Less/More"
+ private variable enlarge_shrink_button ;# Widget: Button "Enlarge/Shrink"
+
+ private variable right_top_frame ;# Widget: Right top frame
+ private variable left_top_frame ;# Widget: Left top frame
+
+ private variable less_more 0 ;# Bool: Mode flag "More"
+ private variable large 0 ;# Bool: Flag enlarged
+
+ private variable left_rows_created 0 ;# Int: Number of created rows in the left frame
+ private variable right_rows_created 0 ;# Int: Number of created rows in the right frame
+
+ private variable validation_in_progress 0 ;# Bool: Validation procedure in progress
+
+ private variable val_to_set [list {} {} {}] ;# List: Decimal values to set in the bottom 3 entryboxes after enlarge
+
+ private variable entry_h ;# Array of Widget: Entrybox "HEX", index is row (starting from 0)
+ private variable entry_d ;# Array of Widget: Entrybox "DEC", index is row (starting from 0)
+ private variable entry_b ;# Array of Widget: Entrybox "BIN", index is row (starting from 0)
+ private variable entry_o ;# Array of Widget: Entrybox "OCT", index is row (starting from 0)
+ private variable entry_t ;# Array of Widget: Canvas containing bits
+ private variable entry_c0 ;# Array of Widget: Entrybox "BCD L", index is row (starting from 0)
+ private variable entry_c1 ;# Array of Widget: Entrybox "BCD H", index is row (starting from 0)
+ private variable entry_a ;# Array of Widget: Entrybox "ASCII", index is row (starting from 0)
+ private variable bit ;# CanvasObject: bit rectangle, $bit(row_number,bit_number)
+
+ ## Object constructor
+ constructor {} {
+ # Configure ttk styles
+ if {!$count} {
+ ttk::style configure BaseConvertor_Focused_D.TEntry -fieldbackground {#AAAAFF}
+ ttk::style configure BaseConvertor_Focused_I.TEntry -fieldbackground {#DDDDFF}
+ }
+
+ incr count
+
+ create_window
+ create_gui
+ }
+
+ ## Object destructor
+ destructor {
+ }
+
+ ## Commence a new configuration
+ # @parm List conf_list - Configuration list previously returned by proc. "get_config"
+ # @return void
+ public method set_config {conf_list} {
+ # Set window position
+ $win_obj geometry \
+ {} {} \
+ [lindex $conf_list {0 2}] \
+ [lindex $conf_list {0 3}]
+
+ # Adjust modes
+ if {[lindex $conf_list 2]} {
+ less_more
+ }
+ if {[lindex $conf_list 3]} {
+ enlarge_shrink
+ }
+
+ # Fill in the entryboxes
+ for {set i 0} {$i < $left_rows_created} {incr i} {
+ validate {t} $i [lindex $conf_list [list 4 $i]]
+ }
+ if {$left_rows_created < 6} {
+ for {set i 0; set j 3} {$i < 3} {incr i; incr j} {
+ lset val_to_set $i [lindex $conf_list [list 4 $j]]
+ }
+ }
+
+ # Adjust flag "Shaded"
+ if {[lindex $conf_list 1]} {
+ update
+ $win_obj collapse_expand
+ }
+ }
+
+ ## Get configuration list
+ # @return List - Configuration list
+ public method get_config {} {
+ # Create list of current values in the entryboxes
+ set values {}
+ lappend values [$entry_d(0) get] [$entry_d(1) get] [$entry_d(2) get]
+ if {$left_rows_created > 3} {
+ lappend values \
+ [$entry_d(3) get] \
+ [$entry_d(4) get] \
+ [$entry_d(5) get]
+ } {
+ lappend values {} {} {}
+ }
+
+ # Finalize configuration list
+ return [list \
+ [$win_obj geometry] \
+ [$win_obj get_minim_flag] \
+ $less_more \
+ $large \
+ $values \
+ ]
+ }
+
+ ## Create window using class "InnerWindow"
+ # @return void
+ private method create_window {} {
+ set win_obj [InnerWindow #auto \
+ .baseconvertor_${count} \
+ [list 160 130 100 100] \
+ [mc "Convertor"] \
+ ::ICONS::16::kaboodleloop \
+ "$this close_window" \
+ ]
+ set win [$win_obj get_frame]
+ }
+
+ ## Create all window GUI
+ # @return void
+ private method create_gui {} {
+ # Create frames
+ set top_frame [frame $win.top_frame]
+ set left_top_frame [frame $top_frame.left_frame]
+ set right_top_frame [frame $top_frame.right_frame]
+ set bottom_frame [frame $win.bottom_frame]
+
+ # Start in mode "Shirked" + !"More"
+ create_left_frame
+
+ ## Create buttons in the bottom frame
+ # Button "Enlarge"/"Shrink"
+ set enlarge_shrink_button \
+ [ttk::button $bottom_frame.enlarge_shrink_button \
+ -text [mc "Enlarge"] \
+ -compound left \
+ -image ::ICONS::16::1downarrow \
+ -command "$this enlarge_shrink" \
+ -width 7 \
+ ]
+ pack $enlarge_shrink_button -side left
+ # Button "More"/"Less"
+ set less_more_button [ttk::button $bottom_frame.less_more_button\
+ -text [mc "More"] \
+ -compound right \
+ -image ::ICONS::16::1rightarrow \
+ -command "$this less_more" \
+ -width 5 \
+ ]
+ pack $less_more_button -side right
+
+ # Pack frames
+ pack $left_top_frame -side left -anchor nw
+ pack $top_frame -fill both -expand 1
+ pack $bottom_frame -fill x
+
+ # Focus the firts hexadecimal entrybox
+ focus -force $entry_h(0)
+ }
+
+ ## Close the window and forget configuration
+ # Calls proc. "::X::__base_convertor_close"
+ # @return void
+ public method close_window {} {
+ ::X::__base_convertor_close $this
+ $win_obj close_window
+ delete object $this
+ }
+
+ ## Validator for entryboxes
+ # Can be used to set a certain value for a certain row in this way:
+ # validate {t} $row_number $decimal_value
+ # @parm Char type - Value source
+ # h - Hexadecimal
+ # d - Decimal
+ # b - Binary
+ # o - Octal
+ # c0 - BCD - Low order nibble
+ # c1 - BCD - High order nibble
+ # a - ASCII
+ # t - Bits (Do not validate, just accept)
+ # @parm Int row - Row number, starting at zero
+ # @parm String content - String to validate and evaluate
+ # @return Bool - 1 == Legal; 0 == Illegal
+ public method validate {type row content} {
+ # This method cannot be recursive in any way
+ if {$validation_in_progress} {return 1}
+ set validation_in_progress 1
+
+ # Local variables
+ set result 1 ;# Bool: Result of validation
+ set zero_length 0 ;# Bool: Zero length input string
+ set value {} ;# Mixed: Decimal representation the validate value or {} (no value)
+
+ # Detect zero length input string
+ if {[string length $content]} {
+ set zero_length 0
+ } {
+ set zero_length 1
+ set content 0
+ }
+
+ # Validate input string
+ switch -- $type {
+ {h} { ;# Hexadecimal
+ if {![regexp {^[[:xdigit:]]{0,2}$} $content]} {
+ set result 0
+ } {
+ scan $content "%x" value
+ }
+ }
+ {d} { ;# Decimal
+ if {![regexp {^[[:digit:]]{0,3}$} $content]} {
+ set result 0
+ } elseif {$content > 255} {
+ set result 0
+ } {
+ set value $content
+ }
+ }
+ {b} { ;# Binary
+ if {![regexp {^[01]{0,8}$} $content]} {
+ set result 0
+ } {
+ set value [NumSystem::bin2dec $content]
+ }
+ }
+ {o} { ;# Octal
+ if {![regexp {^[0-7]{0,3}$} $content]} {
+ set result 0
+ } elseif {$content > 377} {
+ set result 0
+ } {
+ scan $content "%o" value
+ }
+ }
+ {c0} { ;# BCD - Low order nibble
+ if {![regexp {^[[:digit:]]{0,2}$} $content]} {
+ set result 0
+ } elseif {$content > 15} {
+ set result 0
+ } {
+ set value [$entry_c1($row) get]
+ if {![string length $value]} {
+ set value 0
+ }
+ set value [expr {$content + ($value << 4)}]
+ }
+ set zero_length 0
+ }
+ {c1} { ;# BCD - High order nibble
+ if {![regexp {^[[:digit:]]{0,2}$} $content]} {
+ set result 0
+ } elseif {$content > 15} {
+ set result 0
+ } {
+ set value [$entry_c0($row) get]
+ if {![string length $value]} {
+ set value 0
+ }
+ set value [expr {$value + ($content << 4)}]
+ }
+ set zero_length 0
+ }
+ {a} { ;# ASCII
+ if {$zero_length} {
+ set content {}
+ }
+ set zero_length 0
+
+ if {[string length $content] > 1} {
+ set result 0
+ } {
+ set value [NumSystem::ascii2dec $content]
+ }
+
+ if {![string length $value]} {
+ set value [$entry_d($row) get]
+ if {![string length $value]} {
+ set zero_length 1
+ }
+ }
+ }
+ {t} { ;# Bits (Do not validate, just accept)
+ set value $content
+ }
+ }
+
+ # Synchronize with the other entryboxes on the row
+ if {$result} {
+ fill_entryboxes $row $value $zero_length $type
+ }
+
+ # Finish ...
+ set validation_in_progress 0
+ return $result
+ }
+
+ ## Synchronize the specified value with the other entryboxes on the row
+ # @parm Int row - Row number
+ # @parm Int value - Value to fill in (in decimal)
+ # @parm Bool zero_length - Just clear all entryboxes
+ # @parm Char exclude - Entrybox to exclude during filling
+ # h - Hexadecimal
+ # d - Decimal
+ # b - Binary
+ # o - Octal
+ # c0 - BCD - Low order nibble
+ # c1 - BCD - High order nibble
+ # a - ASCII
+ # t - No meaning ...
+ # @return void
+ private method fill_entryboxes {row value zero_length exclude} {
+ # Clear entryboxes on the left
+ foreach w [list \
+ $entry_h($row) $entry_d($row) \
+ $entry_b($row) $entry_o($row) \
+ ] t {
+ h d
+ b o
+ } \
+ {
+ if {$exclude == $t} {
+ continue
+ }
+ $w delete 0 end
+ }
+
+ # Fill in entryboxes on the left
+ if {!$zero_length} {
+ if {$exclude != {h}} {
+ $entry_h($row) insert 0 [format {%X} $value]
+ }
+ if {$exclude != {d}} {
+ $entry_d($row) insert 0 $value
+ }
+ if {$exclude != {b}} {
+ $entry_b($row) insert 0 [NumSystem::dec2bin $value]
+ }
+ if {$exclude != {o}} {
+ $entry_o($row) insert 0 [format {%o} $value]
+ }
+ }
+
+ if {$row < $right_rows_created} {
+ # Clear entryboxes on the right
+ foreach w [list $entry_c0($row) $entry_c1($row) $entry_a($row)] \
+ t {c0 c1 a} \
+ {
+ if {$exclude == $t} {
+ continue
+ }
+
+ $w delete 0 end
+ }
+
+ # Adjust canvas widget with bit rectangles
+ set mask 1
+ for {set i 0} {$i < 8} {incr i} {
+ if {$zero_length} {
+ set fill {#FFFFFF}
+ set outline {#888888}
+ } elseif {[expr $value & $mask]} {
+ set fill ${::BitMap::one_fill}
+ set outline ${::BitMap::one_outline}
+ } {
+ set fill ${::BitMap::zero_fill}
+ set outline ${::BitMap::zero_outline}
+ }
+
+ $entry_t($row) itemconfigure $bit($row,$i) \
+ -fill $fill -outline $outline
+
+ set mask [expr {$mask << 1}]
+ }
+
+ # Fill in entryboxes on the right
+ if {!$zero_length} {
+ if {$exclude != {c0}} {
+ $entry_c0($row) insert 0 [expr {$value & 0x0F}]
+ }
+ if {$exclude != {c1}} {
+ $entry_c1($row) insert 0 [expr {$value >> 4}]
+ }
+ if {$exclude != {a}} {
+ if {$value > 31 && $value < 127} {
+ $entry_a($row) insert 0 [format {%c} $value]
+ }
+ }
+ }
+ }
+ }
+
+ ## Handles event <Enter> on canvas widget with bits,
+ # @parm Int r - Row number (0..5)
+ # @parm Int b - Bit number (0..7)
+ # @return void
+ public method bit_enter {r b} {
+ # Determinate current rectangle fill and outline
+ set fill [$entry_t($r) itemcget $bit($r,$b) -fill]
+ set outline [$entry_t($r) itemcget $bit($r,$b) -outline]
+
+ # Determinate new rectangle fill and outline
+ if {$fill == ${::BitMap::one_fill}} {
+ set fill ${::BitMap::one_a_fill}
+ set outline ${::BitMap::one_a_outline}
+ } elseif {$fill == ${::BitMap::zero_fill}} {
+ set fill ${::BitMap::zero_a_fill}
+ set outline ${::BitMap::zero_a_outline}
+ }
+
+ # Set new rectangle fill and outline and adjust cursor
+ $entry_t($r) itemconfigure $bit($r,$b) \
+ -fill $fill -outline $outline
+ $entry_t($r) configure -cursor hand1
+ }
+
+ ## Handles event <leave> on canvas widget with bits,
+ # @parm Int r - Row number (0..5)
+ # @parm Int b - Bit number (0..7)
+ # @return void
+ public method bit_leave {r b} {
+ # Determinate current rectangle fill and outline
+ set fill [$entry_t($r) itemcget $bit($r,$b) -fill]
+ set outline [$entry_t($r) itemcget $bit($r,$b) -outline]
+
+ # Determinate new rectangle fill and outline
+ if {$fill == ${::BitMap::one_a_fill}} {
+ set fill ${::BitMap::one_fill}
+ set outline ${::BitMap::one_outline}
+ } elseif {$fill == ${::BitMap::zero_a_fill}} {
+ set fill ${::BitMap::zero_fill}
+ set outline ${::BitMap::zero_outline}
+ }
+
+ # Set new rectangle fill and outline and adjust cursor
+ $entry_t($r) itemconfigure $bit($r,$b) \
+ -fill $fill -outline $outline
+ $entry_t($r) configure -cursor left_ptr
+ }
+
+ ## Handles event <Button-1> on canvas widget with bits,
+ # @parm Int r - Row number (0..5)
+ # @parm Int b - Bit number (0..7)
+ # @return void
+ public method bit_click {r b} {
+ # Determinate current rectangle fill
+ set fill [$entry_t($r) itemcget $bit($r,$b) -fill]
+
+ # Determinate new bit value
+ if {
+ $fill == ${::BitMap::one_a_fill}
+ ||
+ $fill == ${::BitMap::one_fill}
+ } then {
+ set value 0
+ } else {
+ set value [expr {1 << $b}]
+ }
+
+ # Determinate new value for the whole row
+ set dec [$entry_d($r) get]
+ if {![string length $dec]} {
+ set dec 0
+ }
+ set dec [expr {$dec & (0x0FF ^ (1 << $b))}]
+ incr dec $value
+
+ # Set new value for the whole row
+ validate {t} $r $dec
+ }
+
+ ## Set envent binds specific to this appliaction for the specified entrybox
+ # @parm Widget w - Entrybox widget
+ # @parm Char t - Entrybox type
+ # h - Hexadecimal
+ # d - Decimal
+ # b - Binary
+ # o - Octal
+ # c0 - BCD - Low order nibble
+ # c1 - BCD - High order nibble
+ # a - ASCII
+ # @parm Int r - Row number (0..5)
+ # @return void
+ private method set_bindings_for_an_entrybox {w t r} {
+ bind $w <Key-Up> "$this entry_key $t $r u; break"
+ bind $w <Key-Down> "$this entry_key $t $r d; break"
+ bind $w <Key-Left> "$this entry_key $t $r l; break"
+ bind $w <Key-Right> "$this entry_key $t $r r; break"
+ bind $w <Key-Tab> "$this entry_key $t $r t; break"
+ if {!$::MICROSOFT_WINDOWS} {
+ bind $w <Key-ISO_Left_Tab> "$this entry_key $t $r s; break"
+ }
+ bind $w <Key-Return> "$this entry_key $t $r e; break"
+ bind $w <Key-KP_Enter> "$this entry_key $t $r e; break"
+
+ bind $w <FocusIn> "$this entry_focus $t $r 1"
+ bind $w <FocusOut> "$this entry_focus $t $r 0"
+ }
+
+ ## Create the left frame of the window
+ # @return void
+ private method create_left_frame {} {
+ # Create labels
+ if {!$left_rows_created} {
+ set col 1
+ foreach text {
+ {HEX} {DEC} {BIN} {OCT}
+ } {
+ grid [label $left_top_frame.header_lbl_${col} \
+ -font $::smallfont -text [mc $text] -pady 0 \
+ ] -pady 0 -ipady 0 -row 1 -column $col
+ incr col
+ }
+ }
+
+ # Create entryboxes
+ set row 0
+ for {set row $left_rows_created} {$row < ($large ? 6 : 3)} {incr row} {
+ set col 1
+ foreach width {
+ 2 3 8 3
+ } type {
+ h d b o
+ } \
+ {
+ set entry_wgd [ttk::entry $left_top_frame.e_${type}_$row \
+ -width $width \
+ -validate key \
+ -validatecommand "$this validate $type $row %P" \
+ ]
+ set entry_${type}($row) $entry_wgd
+ grid $entry_wgd -row [expr {$row + 2}] -column $col
+
+ set_bindings_for_an_entrybox $entry_wgd $type $row
+
+ incr col
+ }
+ }
+ set left_rows_created $row
+
+ if {$large} {
+ for {set i 0; set j 3} {$i < 3} {incr i; incr j} {
+ validate {t} $j [lindex $val_to_set $i]
+ }
+ }
+ }
+
+ ## Create the left frame of the window
+ # @return void
+ private method create_right_frame {} {
+ # Create labels
+ if {!$right_rows_created} {
+ set col 1
+ grid [label $right_top_frame.header_lbl_${col} \
+ -font $::smallfont -text [mc "Bits"] -pady 0 \
+ ] -pady 0 -ipady 0 -row 1 -column $col
+ incr col
+ grid [label $right_top_frame.header_lbl_${col} \
+ -font $::smallfont -text [mc "BCD"] -pady 0 \
+ ] -pady 0 -ipady 0 -row 1 -column $col -columnspan 2
+ incr col 2
+ grid [label $right_top_frame.header_lbl_${col} \
+ -font $::smallfont -text [mc "ASCII"] -pady 0\
+ ] -pady 0 -ipady 0 -row 1 -column $col
+ incr col
+ }
+
+ # Create entryboxes and canvas widget
+ set row 0
+ for {set row $right_rows_created} {$row < ($large ? 6 : 3)} {incr row} {
+ set col 1
+ foreach type {
+ t c a
+ } \
+ {
+ switch -- $type {
+ {a} { ;# ASCII
+ set entry_wgd [ttk::entry $right_top_frame.e_${type}_$row \
+ -width 2 \
+ -validate all \
+ -validatecommand "$this validate ${type} $row %P" \
+ ]
+ set entry_${type}($row) $entry_wgd
+ grid $entry_wgd -row [expr {$row + 2}] -column $col
+ set_bindings_for_an_entrybox $entry_wgd $type $row
+ }
+ {c} { ;# BCD
+ set entry_wgd [ttk::entry $right_top_frame.e_${type}1_$row \
+ -width 2 \
+ -validate all \
+ -validatecommand "$this validate ${type}1 $row %P" \
+ ]
+ set entry_${type}1($row) $entry_wgd
+ grid $entry_wgd -row [expr {$row + 2}] -column $col
+ set_bindings_for_an_entrybox $entry_wgd "${type}1" $row
+
+ incr col
+
+ set entry_wgd [ttk::entry $right_top_frame.e_${type}0_$row \
+ -width 2 \
+ -validate all \
+ -validatecommand "$this validate ${type}0 $row %P" \
+ ]
+ set entry_${type}0($row) $entry_wgd
+ grid $entry_wgd -row [expr {$row + 2}] -column $col
+ set_bindings_for_an_entrybox $entry_wgd "${type}0" $row
+ }
+ {t} { ;# Bits
+ set x0 2
+
+ set y0 0
+ set y1 2
+
+
+ set canvas [canvas $right_top_frame.canvas_${row} \
+ -width 118 -height 18 -bd 0 -bg white \
+ -relief flat -highlightthickness 0 \
+ ]
+ grid $canvas -row [expr {$row + 2}] -column $col
+ set entry_${type}($row) $canvas
+
+ for {set b 7} {$b >= 0} {incr b -1} {
+
+ # Create bit rectagle
+ set bit($row,$b) [$canvas create \
+ rectangle $x0 $y1 \
+ [expr {$x0 + 12}] \
+ [expr {$y1 + 12}] \
+ -fill {#FFFFFF} \
+ -outline {#888888} \
+ ]
+
+ $canvas bind $bit($row,$b) <Enter> "$this bit_enter $row $b"
+ $canvas bind $bit($row,$b) <Leave> "$this bit_leave $row $b"
+ $canvas bind $bit($row,$b) <Button-1> "$this bit_click $row $b"
+
+ # Adjust X position for the next rectagle
+ incr x0 14
+ if {$b == 4} {
+ incr x0 3
+ }
+ }
+ }
+ }
+
+ incr col
+ }
+ }
+ set right_rows_created $row
+ }
+
+ ## Switch between modes "Enlarged" and "Shrinked"
+ # @return void
+ public method enlarge_shrink {} {
+ # Invert the mode flag
+ set large [expr {!$large}]
+
+ # Adjust buttons on the bottom bar and create the missing widgets if nessesary
+ if {$large} {
+ create_right_frame
+ create_left_frame
+ $win_obj geometry {} [expr {[winfo height $entry_h(0)] * 3 + 130}] {} {}
+ $enlarge_shrink_button configure \
+ -image ::ICONS::16::1uparrow \
+ -text [mc "Shrink"]
+ } {
+ $win_obj geometry {} 130 {} {}
+ $enlarge_shrink_button configure \
+ -image ::ICONS::16::1downarrow \
+ -text [mc "Enlarge"]
+ }
+
+ # Show or hide appropriate GUI elements
+ foreach w [list \
+ entry_h entry_d entry_b \
+ entry_o entry_t entry_c1\
+ entry_c0 entry_a \
+ ] c {
+ 1 2 3
+ 4 1 2
+ 3 4
+ } {
+ for {set i 3; set r 5} {$i < 6} {incr i; incr r} {
+ if {$large} {
+ grid [subst "\$${w}($i)"] -column $c -row $r
+ } {
+ grid forget [subst "\$${w}($i)"]
+ }
+ }
+ }
+
+ }
+
+ ## Switch between modes "More" and "Less"
+ # @return void
+ public method less_more {} {
+ # Invert the mode flag
+ set less_more [expr {!$less_more}]
+
+ # Adjust GUI
+ if {$less_more} {
+ create_right_frame
+ pack $right_top_frame -side left -anchor nw
+ $less_more_button configure \
+ -compound left -text [mc "Less"] \
+ -image ::ICONS::16::1leftarrow
+ $win_obj geometry 350 {} {} {}
+
+ for {set i 0} {$i < $right_rows_created} {incr i} {
+ validate {t} $i [$entry_d($i) get]
+ }
+ } {
+ pack forget $right_top_frame
+ $less_more_button configure \
+ -compound right -text [mc "More"] \
+ -image ::ICONS::16::1rightarrow
+ $win_obj geometry 160 {} {} {}
+ }
+ }
+
+ ## Entybox event handler for <FocusIn> and <FocusOut>
+ # Change entryboxes background colors
+ # @parm Char type - Entrybox type
+ # h - Hexadecimal
+ # d - Decimal
+ # b - Binary
+ # o - Octal
+ # c0 - BCD - Low order nibble
+ # c1 - BCD - High order nibble
+ # a - ASCII
+ # @parm Int row - Row number (0..5)
+ # @parm Bool focused - 1 == <FocusIn>; 0 == <FocusOut>
+ # @return void
+ public method entry_focus {type row focused} {
+ if {$focused} {
+ set style BaseConvertor_Focused_I.TEntry
+ set bg {#DDDDFF}
+ } {
+ set style TEntry
+ set bg {#FFFFFF}
+ }
+
+ foreach w [list \
+ $entry_h($row) $entry_d($row) \
+ $entry_b($row) $entry_o($row) \
+ ] \
+ {
+ $w configure -style $style
+ }
+
+ if {$right_rows_created > $row} {
+ foreach w [list \
+ $entry_c1($row) \
+ $entry_c0($row) \
+ $entry_a($row) \
+ ] \
+ {
+ $w configure -style $style
+ }
+
+ $entry_t($row) configure -bg $bg
+ }
+
+ if {$focused} {
+ [subst "\$entry_${type}($row)"] configure -style BaseConvertor_Focused_D.TEntry
+ } {
+ [subst "\$entry_${type}($row)"] selection clear
+ }
+
+ }
+
+
+ ## Entybox event handler for <Key-Up>, <Key-Down>, <Key-Left>, <Key-Right>, <Key-Tab>,
+ #+ <Key-ISO_Left_Tab>, <Key-Return> and <Key-KP_Enter>
+ # @parm Char type - Entrybox type
+ # h - Hexadecimal
+ # d - Decimal
+ # b - Binary
+ # o - Octal
+ # c0 - BCD - Low order nibble
+ # c1 - BCD - High order nibble
+ # a - ASCII
+ # @parm Int y - Row number (0..5)
+ # @parm Char key - Key pressed
+ # u - Up
+ # d - Down
+ # l - Left
+ # r - Right
+ # t - Tab
+ # s - Shift-Tab
+ # e - Enter
+ # @return void
+ public method entry_key {type y key} {
+ set entrybox [subst "\$entry_${type}($y)"]
+ set insert [$entrybox index insert]
+ set max_y $left_rows_created
+ incr max_y -1
+ switch -- $type {
+ {h} {set x 0}
+ {d} {set x 1}
+ {b} {set x 2}
+ {o} {set x 3}
+ {c1} {set x 4}
+ {c0} {set x 5}
+ {a} {set x 6}
+ }
+
+ $entrybox selection clear
+ switch -- $key {
+ {u} { ;# Up
+ if {!$y} {
+ return
+ }
+ incr y -1
+ }
+ {d} { ;# Down
+ if {$y == $max_y} {
+ return
+ }
+ incr y
+ }
+ {l} { ;# Left
+ if {!$x || $insert} {
+ $entrybox icursor [expr {$insert-1}]
+ return
+ }
+ incr x -1
+ }
+ {r} { ;# Right
+ if {($x == 6) || ($insert != [$entrybox index end])} {
+ $entrybox icursor [expr {$insert+1}]
+ return
+ }
+ incr x
+ }
+ {t} { ;# Tab
+ if {$x == 6} {
+ return
+ }
+ incr x
+ }
+ {s} { ;# Shift-Tab
+ if {!$x} {
+ return
+ }
+ incr x -1
+ }
+ {e} { ;# Enter
+ if {$y == $max_y} {
+ return
+ }
+ incr y
+ }
+ }
+
+ if {$x > 3 && $y >= $right_rows_created} {
+ return
+ }
+
+ set insert [expr {[$entrybox index end] - $insert}]
+ switch -- $x {
+ {0} {set type h}
+ {1} {set type d}
+ {2} {set type b}
+ {3} {set type o}
+ {4} {set type c1}
+ {5} {set type c0}
+ {6} {set type a}
+ }
+ set entrybox [subst "\$entry_${type}($y)"]
+ $entrybox selection range 0 end
+ $entrybox icursor [expr {[$entrybox index end] - $insert}]
+ focus $entrybox
+ }
+}
diff --git a/lib/utilities/eightsegment.tcl b/lib/utilities/eightsegment.tcl
new file mode 100755
index 0000000..de1903b
--- /dev/null
+++ b/lib/utilities/eightsegment.tcl
@@ -0,0 +1,509 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# 8 segment LED display configurator
+# --------------------------------------------------------------------------
+
+class EightSegment {
+ common count 0 ;# Int: Counter of object instances
+
+ private variable obj_idx ;# Int: Current object ID
+ private variable win ;# Widget: Dialog window
+ private variable canvas_widget ;# Widget: Canvas widget for LED display
+ private variable status_bar ;# Widget: Status bar label
+ private variable leds ;# Array of Bool: key == "Segment number" (0..7); value == ON/OFF (0|1)
+ private variable canvas_objects ;# Array: LED segments in canvas widget
+ private variable validation_ena 1 ;# Bool: Entryboxs validation enabled
+
+ private variable cc_hex_entry ;# Widget: Entrybox "Common catode - Hex"
+ private variable cc_dec_entry ;# Widget: Entrybox "Common catode - Dec"
+ private variable cc_bin_entry ;# Widget: Entrybox "Common catode - Bin"
+ private variable ca_hex_entry ;# Widget: Entrybox "Common anode - Hex"
+ private variable ca_dec_entry ;# Widget: Entrybox "Common anode - Dec"
+ private variable ca_bin_entry ;# Widget: Entrybox "Common anode - Bin"
+
+ private variable seg2pin ;# Array of Int: Segment no. -> Pin no.
+ private variable cbx ;# Array of widget: ComboBox widgets for connecting LED's to pins
+
+ constructor {} {
+ # Create dialog window
+ set win [toplevel .eightsegment$count -class {8 segment editor} -bg {#EEEEEE}]
+ set obj_idx $count
+ incr count
+
+ # Restore last session
+ for {set i 0} {$i < 8} {incr i} {
+ set seg2pin($i) $i
+ set leds($i) 0
+ }
+ array set seg2pin [lindex ${::EightSegment::config} 0]
+ array set leds [lindex ${::EightSegment::config} 1]
+ for {set i 0} {$i < 8} {incr i} {
+ set ::EightSegment::con_${obj_idx}_$i $seg2pin($i)
+ }
+
+ create_gui ;# Create GUI elements
+ refresh_canvas ;# Initialize canvas (LED diaplay)
+ reconnect 0 ;# Highight badly connected pins
+ refresh_entryboxes ;# Refresh EntryBoxes with values
+
+ # Set event bindings for the dialog window
+ bindtags $win [list $win Toplevel all .]
+ bind $win <Control-Key-q> "::itcl::delete object $this; break"
+
+ # Set window parameters
+ wm iconphoto $win ::ICONS::16::8seg
+ wm title $win "8 segment editor"
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "::itcl::delete object $this"
+ }
+
+ destructor {
+ for {set i 0} {$i < 8} {incr i} {
+ unset ::EightSegment::con_${obj_idx}_$i
+ }
+
+ set ::EightSegment::config [list [array get seg2pin] [array get leds]]
+ destroy $win
+ }
+
+ ## LED <-> PIN connection changed
+ # @parm Int segment - Number of segment LED
+ # @return void
+ public method reconnect {segment} {
+ # Unhighlight all ComboBoxes
+ for {set i 0} {$i < 8} {incr i} {
+ $cbx($i) configure -style TCombobox
+ }
+
+ # Highlight ComboBoxes related to pins which are in confict
+ for {set segment 0} {$segment < 8} {incr segment} {
+ set pin [subst "\$::EightSegment::con_${obj_idx}_$segment"]
+ set seg2pin($segment) $pin
+
+ for {set i 0} {$i < 8} {incr i} {
+ if {$i == $segment} {
+ continue
+ }
+
+ if {$seg2pin($i) == $pin} {
+ $cbx($i) configure -style EightSegment_RedFg.TCombobox
+ }
+ }
+ }
+
+ # Adjust display
+ refresh_canvas
+ }
+
+ ## Create window GUI
+ # @return void
+ private method create_gui {} {
+ # Create frames
+ set main_frame [frame $win.main_frame] ;# Entryboxes (left) and canvas (right)
+ set bottom_frame [frame $win.bottom_frame] ;# Status bar and button "Exit"
+
+ # Create status bar
+ set status_bar [label $bottom_frame.status_bar \
+ -justify left -anchor w \
+ ]
+
+ ttk::style configure EightSegment_RedFg.TCombobox -foreground {#FF0000}
+
+ ## Create entryboxes
+ # - Common catode
+ set left_frame [frame $main_frame.left_frame]
+ grid [label $left_frame.header_CC_lbl -text [mc "Common catode"]] \
+ -row 0 -column 0 -columnspan 4 -sticky w
+ grid [label $left_frame.sub_header_CC_hex_lbl -text [mc "Hex:"]] \
+ -row 1 -column 1 -sticky w
+ grid [label $left_frame.sub_header_CC_dec_lbl -text [mc "Dec:"]] \
+ -row 2 -column 1 -sticky w
+ grid [label $left_frame.sub_header_CC_bin_lbl -text [mc "Bin:"]] \
+ -row 3 -column 1 -sticky w
+ set cc_hex_entry [ttk::entry $left_frame.cc_hex_ent \
+ -width 3 \
+ -validate all \
+ -validatecommand "$this entry_validate C H %P" \
+ ]
+ set cc_dec_entry [ttk::entry $left_frame.cc_dec_ent \
+ -width 3 \
+ -validate all \
+ -validatecommand "$this entry_validate C D %P" \
+ ]
+ set cc_bin_entry [ttk::entry $left_frame.cc_bin_ent \
+ -width 8 \
+ -validate all \
+ -validatecommand "$this entry_validate C B %P" \
+ ]
+ grid $cc_hex_entry -row 1 -column 3 -sticky w
+ grid $cc_dec_entry -row 2 -column 3 -sticky w
+ grid $cc_bin_entry -row 3 -column 3 -sticky w
+ foreach type {H D B} row {1 2 3} {
+ grid [ttk::button $left_frame.copy_C${type}_but \
+ -command "$this copy_contents C ${type}" \
+ -image ::ICONS::16::editcopy \
+ -style Flat.TButton \
+ ] -row $row -column 2 -sticky w -padx 3
+ DynamicHelp::add $left_frame.copy_C${type}_but -text \
+ [mc "Copy contents of the entrybox to clipboard"]
+ set_local_status_tip $left_frame.copy_C${type}_but [mc "Copy to clipboard"]
+ }
+ # - Common anode
+ grid [label $left_frame.header_CA_lbl -text [mc "Common anode"]] \
+ -row 5 -column 0 -columnspan 4 -sticky w
+ grid [label $left_frame.sub_header_CA_hex_lbl -text [mc "Hex:"]] \
+ -row 6 -column 1 -sticky w
+ grid [label $left_frame.sub_header_CA_dec_lbl -text [mc "Dec:"]] \
+ -row 7 -column 1 -sticky w
+ grid [label $left_frame.sub_header_CA_bin_lbl -text [mc "Bin:"]] \
+ -row 8 -column 1 -sticky w
+ set ca_hex_entry [ttk::entry $left_frame.ca_hex_ent \
+ -width 3 \
+ -validate all \
+ -validatecommand "$this entry_validate A H %P" \
+ ]
+ set ca_dec_entry [ttk::entry $left_frame.ca_dec_ent \
+ -width 3 \
+ -validate all \
+ -validatecommand "$this entry_validate A D %P" \
+ ]
+ set ca_bin_entry [ttk::entry $left_frame.ca_bin_ent \
+ -width 8 \
+ -validate all \
+ -validatecommand "$this entry_validate A B %P" \
+ ]
+ grid $ca_hex_entry -row 6 -column 3 -sticky w
+ grid $ca_dec_entry -row 7 -column 3 -sticky w
+ grid $ca_bin_entry -row 8 -column 3 -sticky w
+ foreach type {H D B} row {6 7 8} {
+ grid [ttk::button $left_frame.copy_A${type}_but \
+ -command "$this copy_contents A ${type}" \
+ -image ::ICONS::16::editcopy \
+ -style Flat.TButton \
+ ] -row $row -column 2 -sticky w -padx 3
+ DynamicHelp::add $left_frame.copy_A${type}_but -text \
+ [mc "Copy contents of the entrybox to clipboard"]
+ set_local_status_tip $left_frame.copy_A${type}_but [mc "Copy to clipboard"]
+ }
+ # Set event bindings for entryboxes
+ foreach widget [list \
+ ${cc_hex_entry} ${cc_dec_entry} ${cc_bin_entry} \
+ ${ca_hex_entry} ${ca_dec_entry} ${ca_bin_entry} \
+ ] {
+ bindtags $widget [list $widget TEntry $win all .]
+ }
+ # Configure and pack left top frame
+ grid rowconfigure $left_frame 4 -minsize 10
+ grid columnconfigure $left_frame 0 -minsize 20
+ pack $left_frame -side left -padx 5
+
+ # Create canvas widget - LED display
+ set canvas_widget [canvas $main_frame.canvas \
+ -width 125 -height 180 -bg white \
+ -bd 1 -relief solid \
+ ]
+ set canvas_objects(0) [$canvas_widget create polygon \
+ 36 15 46 5 97 5 107 15 97 25 46 25 \
+ ]
+ set canvas_objects(1) [$canvas_widget create polygon \
+ 110 18 120 28 112 72 100 84 91 75 99 29 \
+ ]
+ set canvas_objects(2) [$canvas_widget create polygon \
+ 100 90 110 100 102 144 90 156 81 147 89 101 \
+ ]
+ set canvas_objects(3) [$canvas_widget create polygon \
+ 87 159 77 169 26 169 16 159 26 149 77 149 \
+ ]
+ set canvas_objects(4) [$canvas_widget create polygon \
+ 13 156 25 144 33 100 23 90 12 101 4 147 \
+ ]
+ set canvas_objects(5) [$canvas_widget create polygon \
+ 23 84 35 72 43 28 33 18 22 29 14 75 \
+ ]
+ set canvas_objects(6) [$canvas_widget create polygon \
+ 26 87 36 97 87 97 97 87 87 77 36 77 \
+ ]
+ set canvas_objects(7) [$canvas_widget create oval 98 155 116 173]
+ for {set i 0} {$i < 8} {incr i} {
+ $canvas_widget itemconfigure $canvas_objects($i) \
+ -outline {#FF0000} -activeoutline {#00FF00}
+ $canvas_widget bind $canvas_objects($i) <Button-1> "$this select_segment $i"
+ }
+ foreach coords {{70 15} {105 50} {95 125} {50 160} {20 125} {30 50} {60 88} {107 164}} \
+ text {A B C D E F G P} \
+ i {0 1 2 3 4 5 6 7} \
+ {
+ set obj [$canvas_widget create text \
+ [lindex $coords 0] [lindex $coords 1] \
+ -text $text -fill {#000000} \
+ ]
+ $canvas_widget bind $obj <Button-1> "$this select_segment $i"
+ }
+ pack $canvas_widget -side left -padx 5
+
+ ## Create right frame (Connections)
+ set right_frame [frame $main_frame.right_frame]
+ # Header - "LED"
+ grid [label $right_frame.header_0_lbl \
+ -text [mc "LED"] \
+ ] -row 0 -column 0
+ # Header - "PIN"
+ grid [label $right_frame.header_1_lbl \
+ -text [mc "PIN"] \
+ ] -row 0 -column 1
+ # Create ComboBoxes and their labels
+ for {set i 0} {$i < 8} {incr i} {
+ grid [label $right_frame.pin_${i}_lbl \
+ -text [lindex {A B C D E F G P} $i] \
+ ] -row [expr {$i + 1}] -column 0
+ set cbx($i) [ttk::combobox $right_frame.cb_p$i \
+ -width 1 \
+ -state readonly \
+ -values {0 1 2 3 4 5 6 7} \
+ -textvariable ::EightSegment::con_${obj_idx}_$i \
+ ]
+ bind $cbx($i) <<ComboboxSelected>> "$this reconnect $i"
+ grid $cbx($i) -row [expr {$i + 1}] -column 1
+ }
+ # Pack the right frame
+ pack $right_frame -side left -padx 5 -anchor nw
+
+ # Create button "Exit"
+ pack [ttk::button $bottom_frame.close_but \
+ -compound left \
+ -text [mc "Close"] \
+ -command "::itcl::delete object $this" \
+ -image ::ICONS::16::exit \
+ ] -side right -pady 5
+ pack $status_bar -side left -fill x
+
+ # Pack window frames
+ pack $main_frame -fill both -expand 1 -pady 5 -side top
+ pack $bottom_frame -fill x -side top
+ }
+
+ ## Set status bar tip in this window only
+ # @parm Widget widget - Widget related to the status tip
+ # @parm String text - Status bar tip text
+ # @return void
+ private method set_local_status_tip {widget text} {
+ bind $widget <Enter> [list $status_bar configure -text $text]
+ bind $widget <Leave> [list $status_bar configure -text {}]
+ }
+
+ ## Copy contents of the specified exntrybox to clipboard
+ # @parm Char common_electrode - C == Catode; A == Anode
+ # @parm Char radix - H == Hexadecimal; D == Decimal; B == Binary
+ # @return void
+ public method copy_contents {common_electrode radix} {
+ # Common catode
+ if {$common_electrode == {C}} {
+ switch -- $radix {
+ {H} {set widget ${cc_hex_entry}}
+ {D} {set widget ${cc_dec_entry}}
+ {B} {set widget ${cc_bin_entry}}
+ }
+ # Common anode
+ } {
+ switch -- $radix {
+ {H} {set widget ${ca_hex_entry}}
+ {D} {set widget ${ca_dec_entry}}
+ {B} {set widget ${ca_bin_entry}}
+ }
+ }
+
+ clipboard clear
+ clipboard append [$widget get]
+ }
+
+ ## Invert LED in specified segment
+ # @parm Int i - Segment number
+ # @return void
+ public method select_segment {i} {
+ set leds($seg2pin($i)) [expr {!$leds($seg2pin($i))}]
+ refresh_canvas
+ refresh_entryboxes
+ }
+
+ ## Value entrybox validator
+ # @parm Char common_electrode - C == Catode; A == Anode
+ # @parm Char radix - H == Hexadecimal; D == Decimal; B == Binary
+ # @parm String value - String to validate
+ # @return Bool - always 1
+ public method entry_validate {common_electrode radix value} {
+ if {![string length $value]} {return 1}
+ if {!$validation_ena} {return 1}
+ set validation_ena 0
+
+ ## Validate extrybox contents
+ switch -- $radix {
+ H {
+ set max_length 2
+ set char_class xdigit
+ }
+ D {
+ set max_length 3
+ set char_class digit
+ }
+ B {
+ set max_length 8
+ set char_class digit
+ if {![regexp {^[01]*$} $value]} {
+ set validation_ena 1
+ return 0
+ }
+ }
+ }
+ if {[string length $value] > $max_length} {
+ set validation_ena 1
+ return 0
+ }
+ if {![string is $char_class -strict $value]} {
+ set validation_ena 1
+ return 0
+ }
+
+ # Convert value to decimal
+ if {$radix == {H}} {
+ set value [expr "0x$value"]
+ } elseif {$radix == {B}} {
+ set value [::NumSystem::bin2dec $value]
+ }
+
+ # Adjust array $led() (LED states)
+ if {$common_electrode == {C}} {
+ set mask 1
+ for {set i 0} {$i < 8} {incr i} {
+ set leds($i) [expr {$value & $mask}]
+ set mask [expr {$mask * 2}]
+ }
+ } {
+ set mask 1
+ for {set i 0} {$i < 8} {incr i} {
+ set leds($i) [expr {!($value & $mask)}]
+ set mask [expr {$mask * 2}]
+ }
+ }
+
+ # Adjust canvas and other entryboxes
+ refresh_entryboxes ${common_electrode}${radix}
+ refresh_canvas
+
+ set validation_ena 1
+ return 1
+ }
+
+ ## Adjust canvas (LED display) to array $led (LED states)
+ # @return void
+ private method refresh_canvas {} {
+ for {set i 0} {$i < 8} {incr i} {
+ if {$leds($seg2pin($i))} {
+ $canvas_widget itemconfigure $canvas_objects($i) -fill #FF0000
+ } {
+ $canvas_widget itemconfigure $canvas_objects($i) -fill #FFFFFF
+ }
+ }
+ }
+
+ ## Adjust entryboxes to array $led (LED states)
+ # @parm String - Entrybox to exclude; value == ${common_electrode}${Number system}
+ # @return void
+ private method refresh_entryboxes args {
+ set validation_ena 0
+
+ # Determinate value displayed on LED display
+ set value 0
+ set inv_value 255
+ set mask 1
+ for {set i 0} {$i < 8} {incr i} {
+ if {$leds($i)} {
+ incr value $mask
+ incr inv_value -$mask
+ }
+ set mask [expr {$mask * 2}]
+ }
+
+ ## Clear entryboxes
+ if {$args != {CH}} {
+ $cc_hex_entry delete 0 end
+ }
+ if {$args != {CD}} {
+ $cc_dec_entry delete 0 end
+ }
+ if {$args != {CB}} {
+ $cc_bin_entry delete 0 end
+ }
+ if {$args != {AH}} {
+ $ca_hex_entry delete 0 end
+ }
+ if {$args != {AD}} {
+ $ca_dec_entry delete 0 end
+ }
+ if {$args != {AB}} {
+ $ca_bin_entry delete 0 end
+ }
+
+ ## Fill in entryboxes
+ if {$args != {CD}} {
+ $cc_dec_entry insert insert $value
+ }
+ if {$args != {CH}} {
+ set foo_value [format %X $value]
+ if {[string length $foo_value] < 2} {
+ set foo_value "0$foo_value"
+ }
+ $cc_hex_entry insert insert $foo_value
+ }
+ if {$args != {CB}} {
+ set foo_value [::NumSystem::dec2bin $value]
+ if {[string length $foo_value] < 8} {
+ set foo_value "[string repeat 0 [expr {8 - [string length $foo_value]}]]$foo_value"
+ }
+ $cc_bin_entry insert insert $foo_value
+ }
+
+ if {$args != {AD}} {
+ $ca_dec_entry insert insert $inv_value
+ }
+ if {$args != {AH}} {
+ set foo_value [format %X $inv_value]
+ if {[string length $foo_value] < 2} {
+ set foo_value "0$foo_value"
+ }
+ $ca_hex_entry insert insert $foo_value
+ }
+ if {$args != {AB}} {
+ set foo_value [::NumSystem::dec2bin $inv_value]
+ if {[string length $foo_value] < 8} {
+ set foo_value "[string repeat 0 [expr {8 - [string length $foo_value]}]]$foo_value"
+ }
+ $ca_bin_entry insert insert $foo_value
+ }
+
+ set validation_ena 1
+ }
+}
+set ::EightSegment::config $::CONFIG(EIGHT_SEG_EDITOR)
diff --git a/lib/utilities/hexeditdlg.tcl b/lib/utilities/hexeditdlg.tcl
new file mode 100755
index 0000000..42175f1
--- /dev/null
+++ b/lib/utilities/hexeditdlg.tcl
@@ -0,0 +1,1793 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Prodides hexadecimal editor for external data and program memory.
+# This editor uses dynamic data loading.
+# --------------------------------------------------------------------------
+
+class HexEditDlg {
+ common count 0 ;# Instance counter
+ common win_pos {+0+0} ;# Window position (+X+Y)
+ common mode {hex} ;# View mode {hex dec oct}
+ common cell {0} ;# Current cell (0 - 0xFFFF)
+ common current_view {left} ;# Focused view {left right}
+ # Font for mode combobox
+ common mode_cb_font [font create \
+ -family {Helvetica} \
+ -size -17 \
+ -weight bold \
+ ]
+ # General normal size bold font
+ common bold_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -12 \
+ -weight bold \
+ ]
+ # Status bar tips for main menu for XDATA mode
+ common HELPFILE_XDATA {
+ {
+ {Load IHEX8 file into editor and simulator XDATA memory}
+ {}
+ {Save current content of XDATA memory to IHEX8 file}
+ {Save current document under a different name}
+ {}
+ {Reload data from simulator XDATA memory}
+ {}
+ {Exit editor}
+ } {
+ {Copy selected text to clipboard}
+ {Paste clipboard contents}
+ {}
+ {}
+ {Invoke dialog for searching strings in the text}
+ {Find next occurence of the search string}
+ {Find previous occurence of the search string}
+ } {
+ {Switch view mode to hexadecimal}
+ {Switch view mode to decimal}
+ {Switch view mode to octal}
+ }
+ }
+ # Status bar tips for main menu for CODE mode
+ common HELPFILE_CODE {
+ {
+ {Load IHEX8 file into editor and simulator XDATA memory}
+ {Save current content of program (CODE) memory to IHEX8 file}
+ {}
+ {Save}
+ {Save current document under a different name}
+ {}
+ {Exit editor}
+ } {
+ {Copy selected text to clipboard}
+ {Paste clipboard contents}
+ {}
+ {}
+ {Invoke dialog for searching strings in the text}
+ {Find next occurence of the search string}
+ {Find previous occurence of the search string}
+ } {
+ {Switch view mode to hexadecimal}
+ {Switch view mode to decimal}
+ {Switch view mode to octal}
+ }
+ }
+
+ ## PRIVATE
+ private variable project ;# Object: Project realted to this editor
+ private variable type ;# String: HexEditor type (one of {xdata code})
+ private variable hexeditor ;# Object: Hexadecimal editor pseudowidget
+ private variable win ;# Widget: Dialog toplevel window
+ private variable mainmenu ;# ID of dialog main menu
+ private variable edit_menu ;# ID of dialog edit menu
+ private variable mode_combo_box ;# ID of mode combobox
+ private variable right_sbar_label ;# ID of right label on dialog status bar
+ private variable middle_sbar_label ;# ID of middle label on dialog status bar
+ private variable left_sbar_label ;# ID of left label on dialog status bar
+ private variable current_cell ;# Current cell (0 - 0xFFFF)
+ private variable validation_ena 0 ;# Bool: EntryBox validation enable
+ private variable dec_val_entry ;# EntryBox: Value - Decimal
+ private variable oct_val_entry ;# EntryBox: Value - Octal
+ private variable hex_val_entry ;# EntryBox: Value - Hexadecimal
+ private variable bin_val_entry ;# EntryBox: Value - Binary
+ private variable dec_addr_entry ;# EntryBox: Address - Decimal
+ private variable oct_addr_entry ;# EntryBox: Address - Octal
+ private variable hex_addr_entry ;# EntryBox: Address - Hexadecimal
+ private variable bin_addr_entry ;# EntryBox: Address - Binary
+ private variable sub_call_but ;# Button: Call subprogram
+ private variable prg_jump_but ;# Button: Perform program jump
+ private variable obj_idx ;# Index of the current instance
+ private variable loaded_lines {} ;# Map of loaded lines (for dynamic data loading)
+ private variable opened_file {} ;# Name of opened file
+ private variable modified 0 ;# Bool: fag modified
+ private variable capacity 0 ;# Int: Memory capacity
+ private variable last_PC -1 ;# Int: Last position of PC pointer
+ private variable last_PC_length 0 ;# Int: Length of the last PC pointer
+ private variable last_PC_d -1 ;# Int: Last position of PC pointer (func move_program_pointer_directly)
+ private variable last_PC_length_d 0 ;# Int: Length of the last PC pointer (func move_program_pointer_directly)
+ private variable pre_last_PC -1 ;# Int: Last value of $last_PC
+ private variable pre_last_PC_length 0 ;# Int: Last value of $last_PC_length
+
+ ## Object constructor
+ # @parm Object _project - Parent project
+ # @parm String _type - Type of contents (one of {xdata code eram eeprom uni})
+ constructor {_project _type} {
+ # Initalize object variables
+ set project $_project
+ set type $_type
+ set obj_idx $count
+ set win [toplevel .hexeditdlg${obj_idx} -class {Hex Editor} -bg {#EEEEEE}]
+ set loaded_lines [string repeat [string repeat 0 0xFF] 0xFF]
+
+ incr count ;# Increment instance counter
+
+ # Determinate memory capacity
+ switch -- $type {
+ {code} {
+ set capacity [$project cget -P_option_mcu_xcode]
+ incr capacity [expr {[lindex [$project cget -procData] 2] * 1024}]
+ }
+ {xdata} {
+ set capacity [$project cget -P_option_mcu_xdata]
+ }
+ {eram} {
+ set capacity [lindex [$project cget -procData] 8]
+ }
+ {eeprom} {
+ set capacity [lindex [$project cget -procData] 32]
+ }
+ {uni} {
+ set capacity 0x10000
+ }
+ }
+
+ # Create dialog frames
+ set tool_bar_frame [frame $win.tool_bar] ;# Toolbar
+ set middle_frame $win.middle_frame ;# Left view and right view
+ set bottom_frame [frame $win.bottom_frame] ;# EntryBoxes: Value & Address
+ set statusbar_frame [frame $win.statusbar_frame] ;# Dialog statusbar
+
+ # Create dialog componets
+ create_status_bar $statusbar_frame
+ create_main_menu
+ create_tool_bar $tool_bar_frame
+ create_middle_bottom_frame $middle_frame $bottom_frame
+ create_main_win_bindings
+
+ # Add items "LJMP" and "LCALL" to popup menu
+ if {$type == {code}} {
+ if {[$project is_frozen]} {
+ set state normal
+ } {
+ set state disabled
+ }
+
+ [$hexeditor get_popup_menu] add separator
+ [$hexeditor get_popup_menu] add command -label [mc "LJMP this_address"] \
+ -underline 1 -command "$this prog_jump" -state $state \
+ -compound left -image ::ICONS::16::exec
+ [$hexeditor get_popup_menu] add command -label [mc "LCALL this_address"]\
+ -underline 1 -command "$this sub_call" -state $state \
+ -compound left -image ::ICONS::16::exec
+ }
+
+ # Load data from simulator engine to current visible area
+ load_data_to_current_view
+
+ # Fill EntryBoxes
+ if {$cell >= $capacity} {
+ set current_cell [expr {$capacity - 1}]
+ } {
+ set current_cell $cell
+ }
+ set value [$hexeditor get_values $current_cell $current_cell]
+ fill_entries {} val $value
+ fill_entries {} addr $current_cell
+ set validation_ena 1
+
+ # Pack dialog frames
+ pack $tool_bar_frame -fill x -anchor w
+ pack $middle_frame -anchor nw -after $tool_bar_frame -pady 10
+ pack $bottom_frame -anchor w -after $middle_frame
+ pack $statusbar_frame -side bottom -fill x -after $bottom_frame
+
+ # Set window title
+ if {$type == {code}} {
+ set window_icon {kcmmemory_C}
+ wm title $win "[mc {Code memory}] - $project - MCU 8051 IDE"
+ } elseif {$type == {eram}} {
+ set window_icon {kcmmemory_E}
+ wm title $win "[mc {Expanded RAM}] - $project - MCU 8051 IDE"
+ } elseif {$type == {eeprom}} {
+ set window_icon {kcmmemory_P}
+ wm title $win "[mc {Data EEPROM}] - $project - MCU 8051 IDE"
+ } elseif {$type == {xdata}} {
+ set window_icon {kcmmemory_X}
+ wm title $win "[mc {XDATA memory}] - $project - MCU 8051 IDE"
+ } else {
+ set window_icon {ascii}
+ wm title $win "[mc {untitled}] - [mc {Hexadecimal editor}] - MCU 8051 IDE"
+ }
+
+ # Set window geometry
+ wm resizable $win 0 0
+ if {$mode == {hex}} {
+ wm geometry $win ${win_pos}
+ } {
+ wm geometry $win ${win_pos}
+ }
+
+ # Finalize window configuration
+ wm iconphoto $win ::ICONS::16::$window_icon
+ if {$type == {uni}} {
+ wm protocol $win WM_DELETE_WINDOW "$this quit"
+ } {
+ wm protocol $win WM_DELETE_WINDOW \
+ [list ::X::close_hexedit $type $project]
+ }
+ }
+
+ ## Object destructor
+ destructor {
+ # Save current window parameters
+ set win_pos [wm geometry $win]
+ set win_pos [split $win_pos {+}]
+ set win_pos "+[lindex $win_pos 1]+[lindex $win_pos 2]"
+ set cell [$hexeditor getCurrentCell]
+ set current_view [$hexeditor getCurrentView]
+
+ # Remove dialog window and uset its variables
+ destroy $win
+ unset ::HexEditDlg::dec_val_${obj_idx}
+ unset ::HexEditDlg::hex_val_${obj_idx}
+ unset ::HexEditDlg::oct_val_${obj_idx}
+ unset ::HexEditDlg::bin_val_${obj_idx}
+ unset ::HexEditDlg::dec_addr_${obj_idx}
+ unset ::HexEditDlg::hex_addr_${obj_idx}
+ unset ::HexEditDlg::oct_addr_${obj_idx}
+ unset ::HexEditDlg::bin_addr_${obj_idx}
+ unset ::HexEditDlg::mode_${obj_idx}
+ }
+
+ ## Create key event bindings for dialog window
+ # @return void
+ private method create_main_win_bindings {} {
+ foreach widget [list $win [$hexeditor getLeftView] [$hexeditor getRightView]] {
+ bind $widget <Control-Key-o> "$this openhex; break"
+ bind $widget <Control-Key-s> "$this save; break"
+ bind $widget <Control-Key-S> "$this saveas; break"
+ bind $widget <Key-F5> "$this reload; break"
+ bind $widget <Control-Key-q> "$this quit; break"
+ }
+ }
+
+ ## Create main dialog menu
+ # @return voi
+ private method create_main_menu {} {
+ ## Create menu widgets
+ # Main
+ set mainmenu [menu $win.mainmenu \
+ -bd 0 -tearoff 0 -bg {#EEEEEE} \
+ -activeforeground {#6666FF} \
+ -activebackground {#EEEEEE} \
+ ]
+ set file_menu [menu $mainmenu.file_menu -tearoff 0] ;# Main -> File
+ set edit_menu [menu $mainmenu.edit_menu -tearoff 0] ;# Main -> Edit
+ set mode_menu [menu $mainmenu.mode_menu -tearoff 0] ;# Main -> Mode
+
+ # Create menu event bindings for purpose of status bar tips
+ bind $file_menu <<MenuSelect>> "$this menu_sbar_show 0 \[%W index active\]"
+ bind $edit_menu <<MenuSelect>> "$this menu_sbar_show 1 \[%W index active\]"
+ bind $mode_menu <<MenuSelect>> "$this menu_sbar_show 2 \[%W index active\]"
+ bind $file_menu <Leave> "$this sbar_show {}"
+ bind $edit_menu <Leave> "$this sbar_show {}"
+ bind $mode_menu <Leave> "$this sbar_show {}"
+
+ # Create File menu
+ if {$type == {code}} {
+ $file_menu add command -label "Open ADF" -compound left \
+ -command "$this opensim" -underline 0 \
+ -image ::ICONS::16::fileopen
+ }
+ $file_menu add command -label "Open IHEX8" -compound left \
+ -accelerator "Ctrl+O" -command "$this openhex" \
+ -image ::ICONS::16::fileopen -underline 1
+ $file_menu add separator
+ $file_menu add command -label "Save" -compound left \
+ -accelerator "Ctrl+S" -command "$this save" \
+ -image ::ICONS::16::filesave -underline 0
+ $file_menu add command -label "Save as" -compound left \
+ -accelerator "Ctrl+Shift+S" -command "$this saveas" \
+ -image ::ICONS::16::filesaveas -underline 1
+ $file_menu add separator
+ if {$type != {code}} {
+ $file_menu add command -label "Reload" -compound left \
+ -accelerator "F5" -command "$this reload" \
+ -image ::ICONS::16::reload -underline 1
+ $file_menu add separator
+ }
+ $file_menu add command -label "Exit" -compound left \
+ -accelerator "Ctrl+Q" -command "$this quit" \
+ -image ::ICONS::16::exit -underline 1
+
+ # Create Edit menu
+ $edit_menu add command -label "Copy" -compound left \
+ -accelerator "Ctrl+C" -command "$this text_copy" \
+ -image ::ICONS::16::editcopy -underline 0
+ $edit_menu add command -label "Paste" -compound left \
+ -accelerator "Ctrl+V" -command "$this text_paste" \
+ -image ::ICONS::16::editpaste -underline 0
+ $edit_menu add separator
+ $edit_menu add command -label "Find" -compound left \
+ -accelerator "Ctrl+F" -command "$this find_string 0" \
+ -image ::ICONS::16::find -underline 0
+ $edit_menu add command -label "Find next" -compound left \
+ -accelerator "F3" -command "$this find_string 1" \
+ -image ::ICONS::16::1downarrow -underline 5
+ $edit_menu add command -label "Find previous" -compound left \
+ -accelerator "Shift+F3" -command "$this find_string 2" \
+ -image ::ICONS::16::1uparrow -underline 8
+
+ # Create Mode menu
+ set ::HexEditDlg::mode_${obj_idx} $mode
+ $mode_menu add radiobutton -label "HEX" \
+ -variable ::HexEditDlg::mode_${obj_idx} \
+ -indicatoron 0 -compound left -image ::ICONS::raoff \
+ -selectimage ::ICONS::raon -value {hex} -underline 0 \
+ -command [list $this adjust_mode]
+ $mode_menu add radiobutton -label "DEC" \
+ -variable ::HexEditDlg::mode_${obj_idx} \
+ -indicatoron 0 -compound left -image ::ICONS::raoff \
+ -selectimage ::ICONS::raon -value {dec} -underline 0 \
+ -command [list $this adjust_mode]
+ $mode_menu add radiobutton -label "OCT" \
+ -variable ::HexEditDlg::mode_${obj_idx} \
+ -indicatoron 0 -compound left -image ::ICONS::raoff \
+ -selectimage ::ICONS::raon -value {oct} -underline 0 \
+ -command [list $this adjust_mode]
+
+ # Create Main menu
+ $mainmenu add cascade -label "File" -underline 0 -menu $file_menu
+ $mainmenu add cascade -label "Edit" -underline 0 -menu $edit_menu
+ $mainmenu add cascade -label "Mode" -underline 0 -menu $mode_menu
+ $win configure -menu $mainmenu
+ }
+
+ ## Create dialog toolbar
+ # @parm Widget frame -target frame
+ # @return void
+ private method create_tool_bar {frame} {
+ # Create toolbar frame
+ set toolbar_frame [frame $frame.toolbar]
+ # - Button "Open Hex"
+ pack [ttk::button $toolbar_frame.openhex \
+ -command "$this openhex" \
+ -image ::ICONS::22::fileopen \
+ -style Flat.TButton \
+ ] -side left -padx 2
+ DynamicHelp::add $toolbar_frame.openhex -text [mc "Load IHEX8 file"]
+ set_sbar_tip $toolbar_frame.openhex [mc "Open file"]
+ # - Separator
+ pack [ttk::separator $toolbar_frame.sep0 \
+ -orient vertical \
+ ] -side left -padx 4 -fill y -expand 1
+ # - Button "Save"
+ pack [ttk::button $toolbar_frame.save \
+ -command "$this save" \
+ -image ::ICONS::22::filesave \
+ -style Flat.TButton \
+ ] -side left -padx 2
+ DynamicHelp::add $toolbar_frame.save -text [mc "Save current data to IHEX8 file"]
+ set_sbar_tip $toolbar_frame.save [mc "Save file"]
+ # - Button "Save as"
+ pack [ttk::button $toolbar_frame.saveas \
+ -command "$this saveas" \
+ -image ::ICONS::22::filesaveas \
+ -style Flat.TButton \
+ ] -side left -padx 2
+ DynamicHelp::add $toolbar_frame.saveas -text [mc "Save current data to IHEX8 file under a different name"]
+ set_sbar_tip $toolbar_frame.saveas [mc "Save as"]
+ # - Separator
+ pack [ttk::separator $toolbar_frame.sep1 \
+ -orient vertical \
+ ] -side left -padx 4 -fill y -expand 1
+ if {$type != {code}} {
+ # - Button "Reload"
+ pack [ttk::button $toolbar_frame.reload \
+ -command "$this reload" \
+ -image ::ICONS::22::reload \
+ -style Flat.TButton \
+ ] -side left -padx 2
+ DynamicHelp::add $toolbar_frame.reload -text [mc "Reload data from simulator"]
+ set_sbar_tip $toolbar_frame.reload [mc "Reload"]
+ # - Separator
+ pack [ttk::separator $toolbar_frame.sep2 \
+ -orient vertical \
+ ] -side left -padx 4 -fill y -expand 1
+ }
+ # - Button "Exit"
+ pack [ttk::button $toolbar_frame.exit \
+ -style Flat.TButton \
+ -command "$this quit" \
+ -image ::ICONS::22::exit \
+ ] -side left -padx 2
+ DynamicHelp::add $toolbar_frame.exit -text [mc "Exit editor"]
+ set_sbar_tip $toolbar_frame.exit [mc "Exit"]
+
+ pack $toolbar_frame -side left -anchor w
+
+ # - Mode ComboBox
+ set mode_combo_box [ttk::combobox $frame.mode_cb \
+ -values {HEX DEC OCT} \
+ -state readonly \
+ -font $mode_cb_font \
+ -width 4 \
+ ]
+ bind $mode_combo_box <<ComboboxSelected>> [list $this switch_mode]
+ DynamicHelp::add $mode_combo_box -text [mc "Current view mode"]
+ set_sbar_tip $frame.mode_cb \
+ [mc "View mode"]
+ $mode_combo_box current [lsearch {hex dec oct} $mode]
+ pack $mode_combo_box -side right -anchor e -fill y -expand 0
+ }
+
+ ## Set status tip for the given widget
+ # @parm Widget wdg - Target widget
+ # @parm String txt - Status tip
+ # @return void
+ private method set_sbar_tip {wdg txt} {
+ bind $wdg <Enter> [list $this sbar_show $txt]
+ bind $wdg <Leave> [list $this sbar_show {}]
+ }
+
+ ## Create hexeditor and entryboxes for address and value
+ # @parm Widget middle_frame - Frame for hexeditor
+ # @parm Widget bottom_frame - Frame for entryboxes
+ # @return void
+ private method create_middle_bottom_frame {middle_frame bottom_frame} {
+ ## Create and configure HexEditor
+ set hg [expr {$capacity / 16}]
+ if {[expr {$capacity % 16}]} {
+ incr hg
+ }
+ set hexeditor [HexEditor editor${obj_idx} $middle_frame 16 $hg 4 $mode 1 0 16 $capacity]
+ if {$current_view == {left}} {
+ $hexeditor focus_left_view
+ } {
+ $hexeditor focus_right_view
+ }
+ $hexeditor setCurrentCell $cell
+ $hexeditor bindCellEnter "$this change_right_stat_bar_addr"
+ $hexeditor bindCellLeave "$this change_right_stat_bar_addr {}"
+ $hexeditor bindCurrentCellChanged "$this current_cell_changed"
+ $hexeditor bindCellValueChanged "$this cell_value_changed"
+ $hexeditor bindScrollAction "$this load_data_to_current_view"
+
+ # Create labelframes for Value & Address
+ set value_lframe [ttk::labelframe $bottom_frame.value_label_frame \
+ -text [mc "VALUE"] -padding 5 \
+ ]
+ set address_lframe [ttk::labelframe $bottom_frame.address_label_frame \
+ -text [mc "ADDRESS"] -padding 5 \
+ ]
+
+ # Create entryboxes
+ set i 0
+ set width [list 4 4 9 9 8 8 17 17]
+ foreach valtype {val addr} frm [list $value_lframe $address_lframe] {
+ foreach radix {dec oct hex bin} {
+ set ${radix}_${valtype}_entry [ttk::entry $frm.${radix}_${valtype}_entry \
+ -width [lindex $width $i] \
+ -validate all \
+ -textvariable ::HexEditDlg::${radix}_${valtype}_${obj_idx} \
+ -validatecommand [list $this validate_entry ${valtype} ${radix} %P] \
+ ]
+ bindtags $frm.${radix}_${valtype}_entry \
+ [list $frm.${radix}_${valtype}_entry TEntry $win all .]
+ incr i
+ }
+ }
+
+ # Pack entry boxes and create labels for them
+ grid [label $value_lframe.dec_label -text [mc "DEC: "]] -row 0 -column 0
+ grid [label $value_lframe.oct_label -text [mc "OCT: "]] -row 1 -column 0
+ grid [label $value_lframe.hex_label -text [mc "HEX: "]] -row 0 -column 3
+ grid [label $value_lframe.bin_label -text [mc "BIN: "]] -row 1 -column 3
+ grid $dec_val_entry -row 0 -column 1 -sticky e
+ grid $oct_val_entry -row 1 -column 1 -sticky e
+ grid $hex_val_entry -row 0 -column 4 -sticky e
+ grid $bin_val_entry -row 1 -column 4 -sticky e
+ grid columnconfigure $value_lframe 2 -minsize 10
+
+ grid [label $address_lframe.dec_label -text [mc "DEC: "]] -row 0 -column 0
+ grid [label $address_lframe.oct_label -text [mc "OCT: "]] -row 1 -column 0
+ grid [label $address_lframe.hex_label -text [mc "HEX: "]] -row 0 -column 3
+ grid [label $address_lframe.bin_label -text [mc "BIN: "]] -row 1 -column 3
+ grid $dec_addr_entry -row 0 -column 1 -sticky e
+ grid $oct_addr_entry -row 1 -column 1 -sticky e
+ grid $hex_addr_entry -row 0 -column 4 -sticky e
+ grid $bin_addr_entry -row 1 -column 4 -sticky e
+ grid columnconfigure $address_lframe 2 -minsize 10
+
+ # Create buttons "Call" and "Jump"
+ if {$type == {code}} {
+ if {[$project is_frozen]} {
+ set state normal
+ } {
+ set state disabled
+ }
+
+ set prg_jump_but [ttk::button $address_lframe.prg_jump_but \
+ -text [mc "LJMP"] \
+ -state $state \
+ -command "$this prog_jump" \
+ -width 6 \
+ ]
+ DynamicHelp::add $prg_jump_but -text [mc "Perform program jump"]
+ set_sbar_tip $prg_jump_but [mc "Program jump"]
+ set sub_call_but [ttk::button $address_lframe.sub_call_but \
+ -text [mc "LCALL"] \
+ -state $state \
+ -command "$this sub_call" \
+ -width 6 \
+ ]
+ DynamicHelp::add $sub_call_but -text [mc "Perform subprogram call"]
+ set_sbar_tip $sub_call_but [mc "Subprogram call"]
+
+ grid [ttk::separator $address_lframe.sep -orient vertical] \
+ -row 0 -column 5 -sticky ns -padx 5 -rowspan 2
+ grid $prg_jump_but -row 0 -column 6 -sticky we
+ grid $sub_call_but -row 1 -column 6 -sticky we
+ }
+
+ pack $value_lframe -side left -padx 10
+ pack $address_lframe -side left -padx 10
+ }
+
+ ## Create dialog status bar
+ # @parm Widget frame - Frame for the status bar
+ # @return void
+ private method create_status_bar {frame} {
+ # Create status bar labels
+ set left_sbar_label [label $frame.left -anchor w]
+ set middle_sbar_label [Label $frame.middle]
+ set right_sbar_label [label $frame.right \
+ -fg {#0000FF} -font $bold_font -width 6 \
+ ]
+
+ # Set filename to "untitled" if editor is universal
+ $middle_sbar_label configure -text {untitled}
+
+ # Pack status bar labels
+ pack $left_sbar_label -side left -fill x -expand 1 -anchor w
+ pack $middle_sbar_label -side left -fill none -anchor w -after $left_sbar_label -padx 10
+ pack [label $frame.left_left \
+ -text [mc "Cursor:"] \
+ -font $bold_font \
+ -fg {#555555} \
+ ] -side left -after $middle_sbar_label
+ pack $right_sbar_label -side left -after $frame.left_left
+
+ # Set status tips for right part of the status bar
+ set_sbar_tip $frame.left_left [mc "Address of entry under mouse cursor"]
+ set_sbar_tip $right_sbar_label [mc "Address of entry under mouse cursor"]
+
+ # Initialize pointer address display
+ change_right_stat_bar_addr {}
+ }
+
+ ## Write value to simulator engine and synchronize with all watchers
+ # @parm Int addr - Target address
+ # @parm int val - Register value
+ # @return void
+ private method write_to_simulator {addr val} {
+ if {$type == {uni}} {
+ return
+ }
+
+ # XRAM or ERAM
+ if {$type != {code}} {
+ set hex_addr [format "%X" $addr]
+ set len [string length $hex_addr]
+ if {$len < 4} {
+ set hex_addr "[string repeat 0 [expr {4 - $len}]]$hex_addr"
+ }
+ if {$type == {xdata}} {
+ $project setXdataDEC $addr $val
+ } elseif {$type == {eeprom}} {
+ $project setEepromDEC $addr $val
+ } else {
+ $project setEramDEC $addr $val
+ }
+ $project rightPanel_watch_sync $hex_addr
+
+ # Code memory
+ } {
+ $project setCodeDEC $addr $val
+ }
+ }
+
+ ## Set flag modified and adjust dialog window title
+ # @parm Bool bool - New flag value
+ # @return void
+ private method setModified {bool} {
+ if {$opened_file == {} || $modified == $bool} {
+ return
+ }
+ set modified $bool
+ if {$modified} {
+ wm title $win "\[modified\] [wm title $win]"
+ } {
+ wm title $win [string range [wm title $win] 11 end]
+ }
+ }
+
+
+ ## Parse given data (IHEX-8 and load it into the editor + sync with external components)
+ # @parm String hex_data - input data
+ # @return void
+ private method readHex {hex_data} {
+ # Any EOL -> LF
+ regsub -all {\r\n?} $hex_data "\n" hex_data
+ # Split by lines
+ set hex_data [split $hex_data "\n"]
+
+ # Local variables
+ set pointer 0 ;# Current address
+ set line_number 0 ;# Number of the current line
+ set errors_count 0 ;# Number of errors occured while parsing ihex file
+ set eof 0 ;# Bool: EOF detected
+ set error_string {} ;# Text of error message
+
+ # Clear current data
+ if {$type != {code} && $type != {uni}} {
+ if {$type == {xdata}} {
+ for {set i 0} {$i < $capacity} {incr i} {
+ $project setXdataDEC $i 0
+ }
+ } elseif {$type == {eram}} {
+ for {set i 0} {$i < $capacity} {incr i} {
+ $project setEramDEC $i 0
+ }
+ }
+ $project rightPanel_watch_sync_all
+ }
+
+ # Iterate over data lines
+ foreach line $hex_data {
+ incr line_number
+
+ # Skip comments
+ if {[string index $line 0] != {:}} {continue}
+
+ # Check for allowed characters
+ if {![regexp {^:[0-9A-Fa-f]+$} $line]} {
+ incr errors_count
+ append error_string [mc "Line\t%s:\tInvalid characters\n"] $line_number
+ continue
+ }
+
+ # Local variables
+ set check [string range $line {end-1} end] ;# Control count
+ set line [string range $line 1 {end-2}] ;# Whole line (just without Control count)
+ set data [string range $line 8 end] ;# Data
+ set len [string range $line 0 1] ;# Length of data
+ set addr [string range $line 2 5] ;# Address
+ set rectype [string range $line 6 7] ;# Record type
+
+ # Convert address and length to decimal
+ set addr [expr "0x$addr"]
+ set len [expr "0x$len"]
+
+ # Check for valid control count
+ if {$check != [::IHexTools::getCheckSum $line]} {
+ incr errors_count
+ append error_string [mc "Line\t%s:\tInvalid chceksum\n" $line_number]
+ continue
+ }
+ # Check for valid lenght
+ if {($len * 2) != [string bytelength $data]} {
+ incr errors_count
+ append error_string [mc "Line\t%s:\tInvalid length\n" $line_number]
+ continue
+ }
+ # Check for supported record types
+ if {$rectype == {01}} {
+ set eof 1
+ break
+ }
+ if {$rectype != {00}} {
+ incr errors_count
+ append error_string [mc "Line\t%s:\tUnknown record type: '%s'\n" $line_number $rectype]
+ continue
+ }
+
+ # Set current address
+ set pointer $addr
+ if {$pointer >= $capacity} {
+ break
+ }
+
+ # Parse data field
+ set len [expr {$len * 2}]
+ for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
+ set number [string range $data $i $j]
+ if {$type == {uni}} {
+ $hexeditor setValue $pointer [expr "0x$number"]
+ } {
+ write_to_simulator $pointer [expr "0x$number"]
+ }
+ incr pointer
+ }
+ }
+
+ # Append error if there is no EOF
+ if {!$eof} {
+ incr errors_count
+ append error_string [mc "Line\t%s:\tMissing EOF" [expr {$line_number + 1}]]
+ }
+
+ # Invoke error dialog
+ if {$errors_count} {
+ # Create dialog window
+ set dialog [toplevel .error_message_dialog -bg {#EEEEEE}]
+
+ # Create main frame (text widget and scrolbar)
+ set main_frame [frame $dialog.main_frame]
+
+ # Create text widget
+ set text [text $main_frame.text \
+ -yscrollcommand "$main_frame.scrollbar set" \
+ -bg {#FFFFFF} -width 0 -height 0 \
+ ]
+ pack $text -side left -fill both -expand 1
+ # Create scrollbar
+ pack [ttk::scrollbar $main_frame.scrollbar \
+ -orient vertical \
+ -command "$text yview" \
+ ] -side right -fill y
+
+ # Pack main frame and create button "Close"
+ pack $main_frame -fill both -expand 1
+ pack [ttk::button $dialog.ok_button \
+ -text [mc "Close"] \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ]
+
+ # Show error string and disable the text widget
+ $text insert end $error_string
+ $text configure -state disabled
+
+ # Set window attributes
+ wm iconphoto $dialog ::ICONS::16::no
+ wm title $dialog [mc "Error(s) occured while parsing IHEX file"]
+ wm minsize $dialog 500 250
+ wm protocol $dialog WM_DELETE_WINDOW "grab release $dialog; destroy $dialog"
+ wm transient $dialog $win
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+ }
+ }
+
+ ## Synchronize all EntryBoxes with the given value
+ # @parm String exclude - Name entry to exclude from synchronization {dec hex oct bin}
+ # @parm String valtype - Value type (one of {val addr}) (Value | Address)
+ # @parm Int value - Value (must be in decimal)
+ # @return void
+ private method fill_entries {exclude valtype value} {
+ # Determinate maximum value length (number of digits)
+ if {$valtype == {val}} {
+ set hexlen 2
+ set octlen 3
+ set binlen 8
+ } {
+ set hexlen 4
+ set octlen 7
+ set binlen 16
+ }
+
+ # Empty value -> clear entry boxes
+ if {$value == {}} {
+ set hex {}
+ set oct {}
+ set bin {}
+ # Non empty value -> convert
+ } {
+ # To hexadecimal
+ set hex [format %X $value]
+ set len [string length $hex]
+ if {$len != $hexlen} {
+ set hex "[string repeat {0} [expr {$hexlen - $len}]]$hex"
+ }
+
+ # To octal
+ set oct [format %o $value]
+ set len [string length $oct]
+ if {$len != $octlen} {
+ set oct "[string repeat {0} [expr {$octlen - $len}]]$oct"
+ }
+
+ # To binary
+ set bin [NumSystem::dec2bin $value]
+ set len [string length $bin]
+ if {$len < $binlen} {
+ set bin "[string repeat {0} [expr {$binlen - $len}]]$bin"
+ }
+ }
+
+ # Synchronize EntryBoxes
+ if {$valtype == {val}} {
+ if {$exclude != {dec}} {
+ set ::HexEditDlg::dec_val_${obj_idx} $value
+ }
+ if {$exclude != {hex}} {
+ set ::HexEditDlg::hex_val_${obj_idx} $hex
+ }
+ if {$exclude != {oct}} {
+ set ::HexEditDlg::oct_val_${obj_idx} $oct
+ }
+ if {$exclude != {bin}} {
+ set ::HexEditDlg::bin_val_${obj_idx} $bin
+ }
+ } else {
+ if {$exclude != {dec}} {
+ set ::HexEditDlg::dec_addr_${obj_idx} $value
+ }
+ if {$exclude != {hex}} {
+ set ::HexEditDlg::hex_addr_${obj_idx} $hex
+ }
+ if {$exclude != {oct}} {
+ set ::HexEditDlg::oct_addr_${obj_idx} $oct
+ }
+ if {$exclude != {bin}} {
+ set ::HexEditDlg::bin_addr_${obj_idx} $bin
+ }
+ }
+ }
+
+ ## Change content of cursor address display on status bar
+ # @parm Mixed args - [lindex $args 0] == Decimal address
+ # @return void
+ public method change_right_stat_bar_addr args {
+ set address [lindex $args 0]
+
+ # Empty address
+ if {$address == {}} {
+ $right_sbar_label configure -text " --- "
+ return
+ }
+
+ # Non empty address -> convert to HEX and display
+ set address [format %X $address]
+ set len [string length $address]
+ if {$len < 4} {
+ set address "[string repeat {0} [expr {4 - $len}]]$address"
+ }
+ $right_sbar_label configure -text "0x$address"
+ }
+
+ ## Adjust view mode to content of mode combobox
+ # @return void
+ public method switch_mode {} {
+ set mode [lindex {hex dec oct} [$mode_combo_box current]]
+ set ::HexEditDlg::mode_${obj_idx} $mode
+ sbar_show {Working ...}
+ update
+ $hexeditor switch_mode $mode
+ sbar_show {}
+ }
+
+ ## This method should be called after value change in hexeditor
+ # This method writes new value to simulator engine, watchers and EntryBoxes
+ # @parm Int addr - Address of changed cell
+ # @parm int val - New value of the entry
+ # @return void
+ public method cell_value_changed {addr val} {
+ set current_cell $addr
+ set validation_ena 0
+ fill_entries {} val $val
+ write_to_simulator $addr $val
+ setModified 1
+ set validation_ena 1
+ }
+
+ ## This method should be called after current cell change in hexeditor
+ # Synchronizes EntryBoxes
+ # @parm Int addr - New cell address
+ # @return void
+ public method current_cell_changed {addr} {
+ set validation_ena 0
+ set current_cell $addr
+ set value [$hexeditor get_values $addr $addr]
+ fill_entries {} val $value
+ fill_entries {} addr $addr
+ set validation_ena 1
+ }
+
+ ## Validate content of EntryBox in bottom frame
+ # + Synchronize value with all others (if valid)
+ # @parm String valtype - Value type (Address {addr} | Value {val})
+ # @parm String radix - Number base (one of {oct hex dec bin})
+ # @parm String value - Value to validate (and synchronize)
+ # @return void
+ public method validate_entry {valtype radix value} {
+ # If validation is disabled or value is empty -> abort
+ if {!$validation_ena || $value == {}} {
+ return 1
+ }
+
+ # Check for valid characters
+ if {$valtype == {val}} {
+ set m 1
+ } {
+ set m 2
+ }
+ set len [string length $value]
+ switch -- $radix {
+ {dec} {
+ if {$len > (3 * $m) || ![string is digit $value]} {
+ return 0
+ }
+ }
+ {hex} {
+ if {$len > (2 * $m) || ![string is xdigit $value]} {
+ return 0
+ }
+ }
+ {oct} {
+ if {!$len > (3 * $m) || [regexp {^[0-7]+$} $value]} {
+ return 0
+ }
+ }
+ {bin} {
+ if {$len > (8 * $m) || ![regexp {^[01]+$} $value]} {
+ return 0
+ }
+ }
+ }
+
+ # Tempotary disable validations (to prevent infinite event loops)
+ set validation_ena 0
+
+ # Convert value to decimal
+ set value [string trimleft $value 0]
+ if {$value == {}} {
+ set value 0
+ }
+ switch -- $radix {
+ {hex} {
+ set value [expr "0x$value"]
+ }
+ {oct} {
+ set value [expr "0$value"]
+ }
+ {bin} {
+ set value [NumSystem::bin2dec $value]
+ }
+ }
+
+ # Check for allowed value range
+ if {$valtype == {val}} {
+ if {$value > 255} {
+ set validation_ena 1
+ return 0
+ }
+ } {
+ if {$value >= $capacity} {
+ set validation_ena 1
+ return 0
+ }
+ }
+
+ # Synchronize with all other
+ fill_entries $radix $valtype $value
+ if {$valtype == {val}} {
+ $hexeditor setValue $current_cell $value
+ write_to_simulator $current_cell $value
+ } {
+ set current_cell $value
+ $hexeditor setCurrentCell $value
+ }
+
+ # Set flag modified + Reenable validations
+ setModified 1
+ set validation_ena 1
+
+ return 1
+ }
+
+ ## Perform program jump
+ # @return void
+ public method prog_jump {} {
+ if {$type != {code}} {return}
+ $project setPC [subst "\$::HexEditDlg::dec_addr_${obj_idx}"]
+ set lineNum [$project simulator_getCurrentLine]
+ if {$lineNum != {}} {
+ $project move_simulator_line $lineNum
+ } {
+ $project editor_procedure {} unset_simulator_line {}
+ }
+ $project Simulator_sync_PC_etc
+ }
+
+ ## Perform subprogram call
+ # @return void
+ public method sub_call {} {
+ if {$type != {code}} {return}
+ $project simulator_subprog_call [subst "\$::HexEditDlg::dec_addr_${obj_idx}"]
+ set lineNum [$project simulator_getCurrentLine]
+ if {$lineNum != {}} {
+ $project move_simulator_line $lineNum
+ } {
+ $project editor_procedure {} unset_simulator_line {}
+ }
+ $project Simulator_sync_PC_etc
+ }
+
+ ## Adjust view mode to state of mode menu
+ # @return void
+ public method adjust_mode {} {
+ $mode_combo_box current [lsearch {hex dec oct} [subst "\$::HexEditDlg::mode_${obj_idx}"]]
+ sbar_show {Working ...}
+ update
+ $hexeditor switch_mode [subst "\$::HexEditDlg::mode_${obj_idx}"]
+ sbar_show {Working}
+ }
+
+ ## Quit dialog
+ # @return void
+ public method quit {} {
+ if {$modified} {
+ set response [tk_messageBox \
+ -parent $win \
+ -type yesnocancel \
+ -icon question \
+ -title [mc "File modified"] \
+ -message [mc "File %s has been modifed.\nDo you want to save it ?" [file tail $opened_file]]]
+ if {$response == {yes}} {
+ save
+ } elseif {$response != {no}} {
+ return
+ }
+ }
+ if {$type == {uni}} {
+ delete object $this
+ } {
+ ::X::close_hexedit $type $project
+ }
+ }
+
+ ## Show status tip for menu entry
+ # @parm Int help_file_index - Menu index
+ # @parm Int entry_index - Entry index
+ # @return void
+ public method menu_sbar_show {help_file_index entry_index} {
+ # Validate input data
+ if {![string is digit $entry_index]} {
+ $left_sbar_label configure -text {}
+ return
+ }
+ if {![string is digit $help_file_index]} {
+ $left_sbar_label configure -text {}
+ return
+ }
+
+ # Show status tip
+ if {$type == {code}} {
+ $left_sbar_label configure -text \
+ [mc [lindex $HELPFILE_CODE [list $help_file_index $entry_index]]]
+ } {
+ $left_sbar_label configure -text \
+ [mc [lindex $HELPFILE_XDATA [list $help_file_index $entry_index]]]
+ }
+ }
+
+ ## Load data from simulator engine to current visible area
+ # @return void
+ public method load_data_to_current_view {} {
+ if {$type == {uni}} {return}
+
+ # Local variables
+ set startrow [$hexeditor getTopRow] ;# Start row
+ set endrow [expr {$startrow + 15}] ;# End row
+ set startaddr [expr {$startrow * 16}] ;# Start address for 1st row
+ set endaddr [expr {($startrow + 1) * 16 - 1}] ;# End address for 1st row
+
+ # Determinate command to gain data
+ if {$type == {code}} {
+ set cmd {getCodeDEC}
+ } elseif {$type == {xdata}} {
+ set cmd {getXdataDEC}
+ } elseif {$type == {eeprom}} {
+ set cmd {getEepromDEC}
+ } else {
+ set cmd {getEramDEC}
+ }
+
+ # Iterate over visible rows and load data to them
+ for {set row $startrow} {$row <= $endrow} {incr row} {
+ if {[string index $loaded_lines $row] == 1} {
+ incr startaddr 16
+ incr endaddr 16
+ continue
+ }
+
+ for {set addr $startaddr} {$addr <= $endaddr} {incr addr} {
+ if {$addr >= $capacity} {
+ break
+ }
+ $hexeditor setValue $addr [$project $cmd $addr]
+ }
+
+ incr startaddr 16
+ incr endaddr 16
+ }
+
+ # Adjust map of loaded lines
+ set loaded_lines [string replace $loaded_lines $startrow $endrow [string repeat 1 16]]
+ }
+
+ ## Show text in status bar
+ # @parm String text - Text to show
+ # @return void
+ public method sbar_show {text} {
+ $left_sbar_label configure -text $text
+ }
+
+ ## Action for Menu/Toolbar - Copy
+ # Invoke dialog "Find string"
+ # @return void
+ public method text_copy {} {
+ $hexeditor text_copy
+ }
+
+ ## Action for Menu/Toolbar - Paste
+ # Invoke dialog "Find string"
+ # @return void
+ public method text_paste {} {
+ $hexeditor text_paste
+ }
+
+ ## Action for Menu/Toolbar - "Find" or "Find next" or "Find previous"
+ # Invoke dialog "Find string"
+ # @return void
+ public method find_string {action} {
+ switch -- $action {
+ 0 {$hexeditor find_dialog}
+ 1 {$hexeditor find_next}
+ 2 {$hexeditor find_prev}
+ }
+ }
+
+ ## Action for Menu/Toolbar - Reload
+ # Reload content of HexEditor
+ # @return void
+ public method reload {} {
+ # Store original cursor position
+ set current_cursor_pos [$hexeditor getCurrentCell]
+
+ if {$type != {xdata} && $type != {uni}} {return}
+ if {$type == {uni}} {
+ set ext [string replace [file extension $opened_file] 0 0]
+ if {$ext != {} && $opened_file != {}} {
+ open_file $opened_file $ext
+ }
+ } {
+ refresh
+ }
+
+ # Restore original cursor position
+ update
+ $hexeditor setCurrentCell $current_cursor_pos
+ $hexeditor seeCell $current_cursor_pos
+ }
+
+ ## Action for Menu/Toolbar - Save as
+ # Save current content of hexeditor as IHEX8 file and ask for file name
+ # @return void
+ public method saveas {} {
+ set directory [file dirname $opened_file]
+ if {$type == {uni}} {
+ if {${::X::project_menu_locked}} {
+ set project {}
+ } {
+ set project ${::X::actualProject}
+ }
+ }
+ if {$directory == {.}} {
+ if {$project == {}} {
+ set directory ${::X::defaultDirectory}
+ } {
+ set directory [$project cget -projectPath]
+ }
+ }
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Save file - MCU 8051 IDE"] \
+ -master $win \
+ -directory $directory \
+ -initialfile [$middle_sbar_label cget -text] \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{IHEX8} {*.{hex,ihx}} }
+ {{All files} {*} }
+ }
+ fsd setokcmd "$this save_file_proc \[::HexEditDlg::fsd get\]"
+ fsd activate
+ }
+
+ ## Action for Menu/Toolbar - Save
+ # Save current content of the editor to $opened_file
+ # @return void
+ public method save {} {
+ if {$opened_file == {}} {
+ saveas
+ return
+ }
+ save_file_proc $opened_file
+ }
+
+ ## Action for Menu/Toolbar - Open Hex
+ # @return void
+ public method openhex {} {
+ set directory [file dirname $opened_file]
+ if {$type == {uni}} {
+ if {${::X::project_menu_locked}} {
+ set project {}
+ } {
+ set project ${::X::actualProject}
+ }
+ }
+ if {$directory == {.}} {
+ if {$project == {}} {
+ set directory ${::X::defaultDirectory}
+ } {
+ set directory [$project cget -projectPath]
+ }
+ }
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Open file - MCU 8051 IDE"] \
+ -master $win -directory $directory \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{IHEX8} {*.{hex,ihx}} }
+ {{All files} {*} }
+ }
+ fsd setokcmd "$this open_file \[::HexEditDlg::fsd get\] hex"
+ fsd activate
+ }
+
+ ## Action for Menu/Toolbar - Open Adb
+ # @return void
+ public method opensim {} {
+ if {$type != {code}} {return}
+ set directory [file dirname $opened_file]
+ if {$directory == {.}} {
+ set directory [$project cget -projectPath]
+ }
+ catch {delete object fsd}
+ KIFSD::FSD fsd \
+ -title [mc "Open file - MCU 8051 IDE"] \
+ -master $win -directory $directory \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{Simulator file} {*.adb} }
+ {{All files} {*} }
+ }
+ fsd setokcmd "$this open_file \[::HexEditDlg::fsd get\] adf"
+ fsd activate
+ }
+
+ ## Open the give file and load its contents into editor
+ # @parm String filename - Relative or absolute filename
+ # @parm String extension - Fily type {adf hex}
+ # @return void
+ public method open_file {filename extension} {
+ # Store original cursor position
+ set current_cursor_pos [$hexeditor getCurrentCell]
+
+ # Normalize filename
+ set filename [file normalize $filename]
+ set directory [file dirname $filename]
+ if {$type == {uni}} {
+ if {${::X::project_menu_locked}} {
+ set project {}
+ } {
+ set project ${::X::actualProject}
+ }
+ }
+ if {$directory == {.}} {
+ if {$project == {}} {
+ set directory ${::X::defaultDirectory}
+ } {
+ set directory [$project cget -projectPath]
+ }
+ }
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "$directory/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join $directory $filename]
+ }
+ }
+
+ # Open file
+ if {[catch {
+ set file [open $filename r]
+ }]} then {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to open file:\n%s" $filename]
+ return
+ }
+
+ # Clear editor
+ if {$type == {uni}} {
+ $hexeditor fill_views
+ } {
+ $project simulator_clear_memory $type
+ }
+
+ # Load contents
+ if {$extension == {adf}} {
+ $project load_program_from_adf $filename
+ } {
+ readHex [read $file]
+ }
+
+ # Finalize
+ close $file
+ set_filename $filename
+ refresh
+
+ # Restore original cursor position
+ update
+ $hexeditor setCurrentCell $current_cursor_pos
+ $hexeditor seeCell $current_cursor_pos
+ }
+
+ ## Save content of the editor into the given file in format IHEX8
+ # @parm String filename - target filename
+ # @return void
+ public method save_file_proc {filename} {
+ # Adjust filename
+ set filename [file normalize $filename]
+ set directory [file dirname $filename]
+ set rootname $filename
+ if {$type == {uni}} {
+ if {${::X::project_menu_locked}} {
+ set project {}
+ } {
+ set project ${::X::actualProject}
+ }
+ }
+ if {$directory == {.}} {
+ if {$project == {}} {
+ set directory ${::X::defaultDirectory}
+ } {
+ set directory [$project cget -projectPath]
+ }
+ }
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ if {![regexp "^(~|/)" $filename]} {
+ set filename "$directory/$filename"
+ }
+ } { ;# Microsoft windows way
+ if {![regexp "^\w:" $filename]} {
+ set filename [file join $directory $filename]
+ }
+ }
+
+ # Adjust file extension
+ if {![regexp {\.(hex|ihx)$} $filename]} {
+ if {$type != {code} && $type != {uni} } {
+ append filename {.xdata.hex}
+ } {
+ append filename {.hex}
+ }
+ }
+
+ if {[file exists $filename]} {
+ # Check if the file is writable
+ if {![file writable $filename]} {
+ tk_messageBox -type ok -icon error -title [mc "Permission denied"] \
+ -message [mc "Unable to access file: %s" $filename] -parent $win
+ return
+ }
+ # Ask user for overwrite existing file
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent $win \
+ -title [mc "Overwrite file"] \
+ -message [mc "A file name '%s' already exists. Are you sure you want to overwrite it ?" [file tail $filename]]
+ ] != {yes}
+ } {
+ return
+ }
+ # Create a backup file
+ catch {
+ file rename -force $filename "$filename~"
+ }
+ }
+
+ # Write filename on statusbar
+ set_filename $filename
+
+ if {$type == {xdata}} {
+ set getDataCommand {getXdata}
+
+ } elseif {$type == {eram}} {
+ set getDataCommand {getEram}
+
+ } elseif {$type == {eeprom}} {
+ set getDataCommand {getEeprom}
+
+ } else {
+ set getDataCommand {getCode}
+ }
+
+ # Open file
+ if {[catch {
+ set file [open $filename w 420]
+ }]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [mc "Permission denied"] \
+ -message [mc "Unable to open file:\n%s" $filename]
+ return
+ }
+
+ # Determinate number of 2048 B blocks
+ set maximum [expr {$capacity / 2048 + 1}]
+
+ # Create progress dialog
+ set ::X::saving_progress 0
+ set ::X::abort_saving 0
+
+ create_progress_bar .prgDl \
+ $win \
+ {} \
+ "Saving: $rootname" \
+ ::X::saving_progress \
+ $maximum \
+ [mc "Saving file"] \
+ ::ICONS::16::filesave \
+ [mc "Abort"] \
+ {set ::X::abort_saving 1}
+
+ # Local variables
+ set addr 0 ;# Address
+ set len 0 ;# Length
+ set data {} ;# Data field
+ set pointer -1 ;# Current address
+
+ # $maximum* update Progress Dialog
+ for {set i 0} {$i < $maximum} {incr i} {
+
+ # Create 8*32 IHEX records
+ for {set j 0} {$j < 2048} {incr j} {
+
+ # Increment address pointer
+ incr pointer
+ if {$pointer >= $capacity} {
+ break
+ }
+
+ # Get register value
+ set code [$hexeditor get_values $pointer $pointer]
+ if {$code != {}} {
+ set code [format {%X} $code]
+ if {[string length $code] == 1} {
+ set code "0$code"
+ }
+ }
+
+ # If buffer is full -> create record
+ if {$code == {} || $len == 255} {
+ # Save record
+ if {$len != 0} {
+ puts -nonewline $file {:}
+ puts $file [createHexRecord \
+ [format "%X" $len] \
+ [format "%X" $addr] \
+ 00 $data \
+ ]
+ }
+ # Reset some variables related to the last record
+ set addr $pointer
+ incr addr
+ set len 0
+ set data {}
+ if {$len != 255} {continue}
+ }
+
+ # Increment length field and append register value to data field
+ incr len
+ append data $code
+ }
+
+ # Update Progress Dialog
+ incr ::X::saving_progress
+ update
+ # Optionaly abort
+ if {${::X::abort_saving}} {
+ set abort_saving 0
+ destroy .prgDl
+ return
+ }
+ }
+
+ # Destroy Progress Dialog
+ catch {destroy .prgDl}
+
+ # Save the last (incomplete) record
+ if {$len != 0} {
+ puts -nonewline $file {:}
+ puts $file [::HexEditDlg::createHexRecord \
+ [format "%X" $len] [format "%X" $addr] 00 $data]
+ }
+
+ # Save EOF
+ puts -nonewline $file {:00000001FF}
+
+ # Done ...
+ close $file
+ setModified 0
+ sbar_show [mc "File %s saved" $filename]
+ }
+
+ ## Create Intel HEX 8 field
+ # @parm String len - field length (max. 2 hex digits)
+ # @parm String addr - field address (max. 4 hex digits)
+ # @parm String type - field type (exaclty 2 hex digits (eg. '00' or '01'))
+ # @parm String data - data (even number of hex digits, max. 512)
+ # @return String - Intel HEX 8 field
+ proc createHexRecord {len addr rectype data} {
+ # Adjust length
+ if {[string length $len] == 1} {set len "0$len"}
+ # Adjust address
+ set addr_len [string length $addr]
+ if {$addr_len < 4} {
+ set addr "[string repeat 0 [expr {4 - $addr_len}]]$addr"
+ }
+ # Create field
+ set result "${len}${addr}${rectype}"
+ append result $data
+ # Compute control count (see Compiler)
+ append result [::IHexTools::getCheckSum $result]
+ # Return result
+ return $result
+ }
+
+ # -------------------------------------------------------------------
+ # GENERAL PUBLIC INTERFACE
+ # -------------------------------------------------------------------
+
+ ## Inform hexeditor about simulator start or shutdown
+ # @parm Bool started - 1 == Simulator started; 0 == Simulator stopped
+ # @return void
+ public method simulator_stared_stopped {started} {
+ if {$type != {code}} {
+ return
+ }
+
+ if {$started} {
+ set state {normal}
+ } {
+ set state {disabled}
+ }
+ $sub_call_but configure -state $state
+ $prg_jump_but configure -state $state
+ [$hexeditor get_popup_menu] entryconfigure [::mc "LJMP this_address"] -state $state
+ [$hexeditor get_popup_menu] entryconfigure [::mc "LCALL this_address"] -state $state
+ }
+
+ ## Move program pointer (highlight cells) -- Avaliable only for code memory hexeditor
+ # @parm Int new_PC - New program counter
+ # @parm Int int_length - Instruction length
+ # @return void
+ public method move_program_pointer {new_PC int_length} {
+ if {$type != {code}} {
+ return
+ }
+
+ if {$pre_last_PC > -1} {
+ for {set i 0} {$i < $pre_last_PC_length} {incr i} {
+ $hexeditor set_bg_hg $pre_last_PC 0 1
+ incr pre_last_PC
+ }
+ }
+ set pre_last_PC $last_PC
+ set pre_last_PC_length $last_PC_length
+
+ if {$last_PC > -1} {
+ for {set i 0} {$i < $last_PC_length} {incr i} {
+ $hexeditor set_bg_hg $last_PC 1 1
+ $hexeditor set_bg_hg $last_PC 0 2
+ incr last_PC
+ }
+ }
+
+ set last_PC_length_d 0
+ set last_PC_d -1
+ set last_PC_length $int_length
+ set last_PC $new_PC
+
+ for {set i 0} {$i < $int_length} {incr i} {
+ $hexeditor set_bg_hg $new_PC 1 2
+ incr new_PC
+ }
+ $hexeditor seeCell $new_PC
+ }
+
+ ## Directly move program pointer (do not affect previous PC pointer) -- Avaliable only for code memory hexeditor
+ # @parm Int new_PC - New program counter (-1 == unresolved)
+ # @parm Int int_length - Instruction length
+ # @return void
+ public method move_program_pointer_directly {new_PC int_length} {
+ if {$type != {code}} {
+ return
+ }
+
+ if {$last_PC_d > -1} {
+ for {set i 0} {$i < $last_PC_length_d} {incr i} {
+ $hexeditor set_bg_hg $last_PC_d 0 0
+ incr last_PC_d
+ }
+ }
+ if {$new_PC == -1} {
+ set last_PC_length_d 0
+ set last_PC_d -1
+ return
+ }
+ set last_PC_length_d $int_length
+ set last_PC_d $new_PC
+
+ for {set i 0} {$i < $int_length} {incr i} {
+ $hexeditor set_bg_hg $new_PC 1 0
+ incr new_PC
+ }
+ $hexeditor seeCell $new_PC
+ }
+
+ ## Clear highlight for all cells in the editor
+ # @return void
+ public method clear_highlight {} {
+ $hexeditor clearHighlighting
+ }
+
+ ## Set background highlight
+ # @parm Int addr - Cell address
+ # @parm Bool bool - 1 == Set; 0 == Clear
+ # @return void
+ public method set_bg_hg_clr {addr bool} {
+ $hexeditor set_bg_hg $addr $bool 0
+ }
+
+ ## Write value to the editor
+ # - avaliable only in modes: XDATA and ERAM
+ # @parm String address - hexadecimal address
+ # @return void
+ public method reg_sync {address} {
+ if {$type == {code}} {
+ return
+ }
+
+ set address [expr "0x$address"]
+ if {$type == {xdata}} {
+ set val [$project getXdataDEC $address]
+ } elseif {$type == {eeprom}} {
+ set val [$project getEepromDEC $address]
+ } else {
+ set val [$project getEramDEC $address]
+ }
+ set org_val [$hexeditor get_values $address $address]
+ $hexeditor setValue $address $val
+ if {$org_val != $val} {
+ $hexeditor setHighlighted $address 1
+ }
+ if {$address == $current_cell} {
+ set validation_ena 0
+ fill_entries {} val $val
+ set validation_ena 1
+ }
+ setModified 1
+ }
+
+ ## Reload content of the editor
+ # @return void
+ public method refresh {} {
+ if {$type == {uni}} {return}
+
+ set loaded_lines [string repeat [string repeat 0 0xFF] 0xFF]
+ load_data_to_current_view
+ setModified 1
+ }
+
+ ## Get configuration list
+ # @return List - config list for procedure loadConfig
+ proc getConfig {} {
+ return [list $win_pos $mode $cell $current_view [::HexEditor::get_config]]
+ }
+
+ ## Load config list (result of procedure getConfig)
+ # @parm List - config list
+ # @return void
+ proc loadConfig {config} {
+ # Parse config list
+ set win_pos [lindex $config 0]
+ set mode [lindex $config 1]
+ set cell [lindex $config 2]
+ set current_view [lindex $config 3]
+
+ # load configuration for hexeditor widget
+ ::HexEditor::load_config_list [lindex $config 4]
+
+ # Validate loaded values
+ if {![regexp {^\+\d+\+\d+$} $win_pos]} {
+ puts stderr "Invalid value of key win_pos (`$win_pos')"
+ set win_pos {+0+0}
+ }
+ if {$mode != {hex} && $mode != {dec} && $mode != {oct}} {
+ puts stderr "Invalid value of key mode (`$mode')"
+ set mode {hex}
+ }
+ if {![string is digit -strict $cell]} {
+ puts stderr "Invalid value of key cell (`$cell')"
+ set cell 0
+ }
+ if {$current_view != {left} && $current_view != {right}} {
+ puts stderr "Invalid value of key current_view (`$current_view')"
+ set current_view {left}
+ }
+ }
+
+ ## Set name of current file (for purpose of saving and for status bar)
+ # @parm String filename - Full filename
+ # @return void
+ public method set_filename {filename} {
+ set opened_file $filename
+
+ set filename [file tail $filename]
+ $middle_sbar_label configure -text $filename -helptext $opened_file
+ if {$type == {uni}} {
+ if {$modified} {
+ wm title $win "\[modified\] $filename - [mc {Hexadecimal editor}] - MCU 8051 IDE"
+ } {
+ wm title $win "$filename - [mc {Hexadecimal editor}] - MCU 8051 IDE"
+ }
+ }
+ }
+}
diff --git a/lib/utilities/notes.tcl b/lib/utilities/notes.tcl
new file mode 100755
index 0000000..f39312f
--- /dev/null
+++ b/lib/utilities/notes.tcl
@@ -0,0 +1,896 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION:
+# Scribble notes independent on project
+# --------------------------------------------------------------------------
+
+class Notes {
+ ## COMMON
+ common count 0 ;# Int: Counter of object instances
+ common bgcolor {#EEEE55} ;# Color: Background color for title bar and window border
+ common bgcolor2 {#FFFF88} ;# Color: Background color for the canvas widget
+ # Font: For inserted text
+ common canvas_text_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ -weight bold \
+ ]
+ # List: Popup menu for the canvas widget
+ common MENU {
+ {radiobutton "Pencil" {} ::Notes::__mode {P}
+ "change_mode P" 0}
+ {radiobutton "Line" {} ::Notes::__mode {L}
+ "change_mode L" 0}
+ {radiobutton "Arrow" {} ::Notes::__mode {A}
+ "change_mode A" 0}
+ {radiobutton "Rectangle" {} ::Notes::__mode {R}
+ "change_mode R" 0}
+ {radiobutton "Oval" {} ::Notes::__mode {O}
+ "change_mode O" 0}
+ {radiobutton "Insert text" {} ::Notes::__mode {T}
+ "change_mode T" 0}
+ {radiobutton "Move canvas" {} ::Notes::__mode {M}
+ "change_mode M" 0}
+ {radiobutton "Eraser" {} ::Notes::__mode {C}
+ "change_mode C" 0}
+ {separator}
+ {command "Zoom in" "" 0 {canvas_zoom_in_from_pmenu}
+ {viewmag_in}}
+ {command "Zoom out" "" 0 {canvas_zoom_out_from_pmenu}
+ {viewmag_out}}
+ {separator}
+ {command "Insert image" "" 0 {load_image}
+ {fileimport}}
+ {command "Select color" "" 0 {select_color}
+ {colorize}}
+ {separator}
+ {command "Clear all" "" 0 {canvas_clear_all}
+ {emptytrash}}
+ }
+
+ ## PRIVATE
+ private variable filename ;# String: Nothing yet ...
+ private variable geometry ;# Geometry: Window geometry
+ private variable win ;# Widget: Dialog window (widget class Frame)
+
+ private variable main_frame ;# Widget: Main window frame
+ private variable canvas_widget ;# Widget: Canvas widget for writing notes
+ private variable title_bar ;# Widget: Window title bar
+ private variable title_label ;# Widget: Label containg text "Scribble notepad"
+ private variable close_button ;# Widget: Close button
+ private variable coll_exp_but ;# Widget: Shade button
+ private variable minim_flag 0 ;# Bool: Shaded or not
+ private variable allow_raise_win 1 ;# Bool: Allows to use command "raise" to force window visibility
+ private variable popup_menu_created 0 ;# Bool: Canvas widget popup menu has been created
+ private variable menu ;# Widget: Popup menu for he canvas widget
+
+ private variable drawing_mode P ;# Char: Current drawing mode
+ private variable selected_color black ;# Color: Selected drawing color
+ private variable loaded_image {} ;# Image: Image to insert (image object not filename)
+ private variable text_to_write {} ;# String: Text to insert
+
+ private variable click_X ;# Int: Auxiliary variable for storing last position
+ private variable click_Y ;# Int: Auxiliary variable for storing last position
+
+ private variable max_X ;# Int: Auxiliary variable for storing max. allowed position
+ private variable max_Y ;# Int: Auxiliary variable for storing max. allowed position
+
+ private variable mode_pen_but ;# Widget: Button "Pencil" mode
+ private variable mode_line_but ;# Widget: Button "Line" mode
+ private variable mode_arrow_but ;# Widget: Button "Arrow" mode
+ private variable mode_rectangle_but ;# Widget: Button "Rectangle" mode
+ private variable mode_oval_but ;# Widget: Button "Oval" mode
+ private variable mode_text_but ;# Widget: Button "Insert text" mode
+ private variable mode_clear_but ;# Widget: Button "Eraser" mode
+ private variable load_image_but ;# Widget: Button "Import image"
+ private variable select_color_but ;# Widget: Button "Select color"
+ private variable move_but ;# Widget: Button "Move canvas" mode
+ private variable flag_modified 0 ;# Bool: Flag modified
+
+ ## contructor
+ # @parm String _file_name - (Nothing yet)
+ # @parm List _geometry - {X Y W H}
+ constructor {_file_name _geometry} {
+ incr count
+
+ set filename $_file_name
+ if {$_geometry == {}} {
+ set geometry {50 50 300 300}
+ } {
+ set geometry $_geometry
+ }
+
+ # Configure specific ttk styles
+ ttk::style configure Notes.TButton \
+ -padding 0 \
+ -background $bgcolor
+ ttk::style configure Notes_Flat.TButton \
+ -background $bgcolor \
+ -padding 0 \
+ -borderwidth 1 \
+ -relief flat
+ ttk::style map Notes_Flat.TButton \
+ -relief [list active raised] \
+ -background [list disabled {#EEEEEE}]
+
+ create_win
+ }
+
+ destructor {
+ destroy $win
+ }
+
+ ## Close the window
+ # @return void
+ public method close {} {
+ if {$flag_modified} {
+ if {[tk_messageBox \
+ -type yesno \
+ -icon question \
+ -parent $win \
+ -title [mc "Really close ?"] \
+ -message [mc "Do you really want to close your notes ? (There is no save function ...)"] \
+ ] != {yes}} then {
+ return
+ }
+ }
+ delete object $this
+ }
+
+ ## Event handler: title bar <Button-1>
+ # @parm Int x - Absolute X coordinate
+ # @parm Int y - Absolute Y coordinate
+ # @return void
+ public method title_B1 {x y} {
+ set click_X [expr {[winfo x $win] - $x}]
+ set click_Y [expr {[winfo y $win] - $y}]
+
+ set max_X [winfo width .]
+ set max_Y [winfo height .]
+ incr max_X -70
+ incr max_Y -70
+
+ focus $title_label
+ $title_label configure -cursor fleur
+ }
+
+ ## Event handler: title bar <ButtonRelease-1>
+ # @return void
+ public method title_B1_release {} {
+ $title_label configure -cursor left_ptr
+ }
+
+ ## Event handler: title bar <B1-Motion>
+ # @parm Int x - Absolute X coordinate
+ # @parm Int y - Absolute Y coordinate
+ # @return void
+ public method title_B1_motion {x y} {
+ incr x $click_X
+ incr y $click_Y
+
+ if {$x > 0 && $x < $max_X} {
+ place $win -x $x
+ }
+ if {$y > 0 && $y < $max_Y} {
+ place $win -y $y
+ }
+ }
+
+ ## Event handler: right bottom corner <Button-1>
+ # @return void
+ public method resize_B1 {} {
+ set click_X [expr {-[winfo x $win] - [winfo x .]}]
+ set click_Y [expr {-[winfo y $win] - [winfo y .]}]
+
+ set max_X [expr {[winfo width .] + [winfo x .]}]
+ set max_Y [expr {[winfo height .] + [winfo y .]}]
+ }
+
+ ## Event handler: right bottom corner <B1-Motion>
+ # @parm Int x - Absolute X coordinate
+ # @parm Int y - Absolute Y coordinate
+ # @return void
+ public method resize_B1_motion {x y} {
+ set _x $x
+ set _y $y
+ incr x $click_X
+ incr y $click_Y
+
+ if {$x < 200 || $_x > $max_X} {
+ set x [winfo width $win]
+ }
+ if {$y < 200 || $_y > $max_Y} {
+ set y [winfo height $win]
+ }
+ place $win -width $x -height $y
+ }
+
+ ## Change drawing mode
+ # @parm Char mode - New mode
+ # A - Arrow
+ # C - Eraser
+ # T - Insert text
+ # O - Oval
+ # R - Rectangle
+ # L - Line
+ # P - Pencil
+ # I - Insert image
+ # M - Move canvas
+ # @return void
+ public method change_mode {mode} {
+ # Local variables
+ set drawing_mode_org $drawing_mode
+
+ # Object variables
+ set drawing_mode $mode
+
+ # Bring toolbar buttons to default states
+ foreach w [list \
+ $mode_pen_but $mode_line_but $mode_arrow_but \
+ $mode_rectangle_but $mode_oval_but $mode_text_but \
+ $mode_clear_but $load_image_but $move_but \
+ ] {
+ $w configure -style Notes_Flat.TButton
+ }
+
+ # Switch drawing mode
+ set w {}
+ switch -- $drawing_mode {
+ A { ;# Arrow
+ $canvas_widget configure -cursor cross
+ set w $mode_arrow_but
+ }
+ C { ;# Eraser
+ $canvas_widget configure -cursor left_ptr
+ set w $mode_clear_but
+ }
+ T { ;# Insert text
+ if {[prompt_for_text]} {
+ $canvas_widget configure -cursor cross
+ set w $mode_text_but
+ } {
+ if {$drawing_mode_org == {T}} {
+ set drawing_mode_org {M}
+ }
+ change_mode $drawing_mode_org
+ }
+ }
+ O { ;# Draw oval
+ $canvas_widget configure -cursor cross
+ set w $mode_oval_but
+ }
+ R { ;# Draw rectangle
+ $canvas_widget configure -cursor cross
+ set w $mode_rectangle_but
+ }
+ L { ;# Draw line
+ $canvas_widget configure -cursor cross
+ set w $mode_line_but
+ }
+ P { ;# Pencil
+ $canvas_widget configure -cursor pencil
+ set w $mode_pen_but
+ }
+ I { ;# Insert image
+ $canvas_widget configure -cursor cross
+ set w $load_image_but
+ }
+ M { ;# Move canvas
+ $canvas_widget configure -cursor fleur
+ set w $move_but
+ }
+ }
+
+ # Highlight toolbar button belonging to the selected mode
+ if {$w != {}} {
+ $w configure -style Notes.TButton
+ }
+ }
+
+ ## (Un)Shade window
+ # @return void
+ public method collapse_expand {} {
+ # Object variables
+ set minim_flag [expr {!$minim_flag}]
+
+ # Shade
+ if {$minim_flag} {
+ set image _1downarrow
+ pack forget $main_frame
+ place $win -height [expr {[winfo height $win.title_bar] + 4}]
+ # Unshade
+ } {
+ set image _1uparrow
+ pack $main_frame -fill both -expand 1 -padx 2 -pady 2
+ place $win -height [expr {[lindex $geometry 3] + 2}]
+ }
+ $coll_exp_but configure -image ::ICONS::16::$image
+ }
+
+ ## Create popup menu
+ # @return void
+ private method create_popup_menu {} {
+ if {$popup_menu_created} {return}
+ set popup_menu_created 1
+
+ set menu $canvas_widget.menu
+ menuFactory $MENU $menu 0 "$this " 0 {}
+ }
+
+ ## Popup menu
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @parm Int X - Absolute X coordinate
+ # @parm Int Y - Absolute Y coordinate
+ # @return void
+ public method popup_menu {x y X Y} {
+ create_popup_menu
+ set ::Notes::__mode $drawing_mode
+ set ::Notes::_menu_x $x
+ set ::Notes::_menu_y $y
+
+ tk_popup $menu $X $Y
+ focus $title_label
+ }
+
+ ## Zoom in canvas contents from the specified coordinates
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method canvas_zoom_in {x y} {
+ $canvas_widget scale all $x $y 1.5 1.5
+ }
+
+ ## Zoom out canvas contents from the specified coordinates
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method canvas_zoom_out {x y} {
+ $canvas_widget scale all $x $y 0.75 0.75
+ }
+
+ ## Zoom in canvas contents (from popup menu)
+ # @return void
+ public method canvas_zoom_in_from_pmenu {} {
+ canvas_zoom_in $::Notes::_menu_x $::Notes::_menu_y
+ }
+
+ ## Zoom out canvas contents (from popup menu)
+ # @return void
+ public method canvas_zoom_out_from_pmenu {} {
+ canvas_zoom_out $::Notes::_menu_x $::Notes::_menu_y
+ }
+
+ ## Create notepad window
+ # @return void
+ private method create_win {} {
+ # Create window frame
+ set win [frame .notes$count -bd 1 -relief raised -bg $bgcolor]
+
+ ## Create title bar
+ # - Title bar frame
+ set title_bar [frame $win.title_bar -bg $bgcolor]
+ set title_label [label $title_bar.text \
+ -bg $bgcolor -compound left \
+ -text [mc "Scribble notepad"] \
+ -image ::ICONS::16::pencil \
+ -pady 0 \
+ ]
+ # - Button "Close"
+ set close_button [ttk::button $title_bar.close_but \
+ -style Notes_Flat.TButton \
+ -command "$this close" \
+ -image ::ICONS::16::button_cancel \
+ -takefocus 0 \
+ ]
+ DynamicHelp::add $title_bar.close_but -text [mc "Close"]
+ setStatusTip -widget $close_button -text [mc "Close"]
+ # - Button "Shade"
+ set coll_exp_but [ttk::button $title_bar.col_exp_but \
+ -style Notes_Flat.TButton \
+ -command "$this collapse_expand" \
+ -image ::ICONS::16::_1uparrow \
+ -takefocus 0 \
+ ]
+ DynamicHelp::add $title_bar.col_exp_but -text [mc "Shade"]
+ setStatusTip -widget $coll_exp_but -text [mc "Shade"]
+ # Pack buttons
+ pack $coll_exp_but -padx 5 -side left -pady 0 -ipady 0
+ pack $title_label -side left -fill x -pady 0 -ipady 0 -expand 1
+ pack $close_button -side right -pady 0 -ipady 0 -padx 3
+ # Set title bar event bindings
+ bind $title_label <Double-1> "$this collapse_expand"
+ bind $title_label <Button-1> "$this title_B1 %X %Y"
+ bind $title_label <B1-Motion> "$this title_B1_motion %X %Y"
+ bind $title_label <ButtonRelease-1> "$this title_B1_release"
+
+ ## Create main frame
+ set main_frame [frame $win.main_frame -bg $bgcolor2]
+ set canvas_widget [canvas $main_frame.canvas \
+ -bg $bgcolor2 -highlightthickness 0 \
+ -width 0 -height 0 -bd 0 \
+ ]
+ bind $canvas_widget <Button-1> "$this canvas_B1 %x %y"
+ bind $canvas_widget <B1-Motion> "$this canvas_B1_motion %x %y"
+ bind $canvas_widget <Motion> "$this canvas_motion %x %y"
+ bind $canvas_widget <ButtonRelease-1> "$this canvas_B1_release %x %y"
+ bind $canvas_widget <ButtonRelease-3> "$this popup_menu %x %y %X %Y"
+ bind $canvas_widget <Leave> "$this canvas_leave"
+ bind $canvas_widget <Enter> "$this canvas_enter %x %y"
+
+ bind $canvas_widget <Button-4> "$this canvas_zoom_in %x %y"
+ bind $canvas_widget <Button-5> "$this canvas_zoom_out %x %y"
+
+ ## Create bottom frame
+ # Create the frame
+ set bottom_frame [frame $main_frame.bottom_frame -bg $bgcolor]
+ # - Resizing corner
+ pack [label $bottom_frame.resize \
+ -bg $bgcolor -cursor lr_angle \
+ -image ::ICONS::16::corner \
+ ] -side right
+ # - Set event bindings for the resizing corner
+ bind $bottom_frame.resize <Button-1> "$this resize_B1"
+ bind $bottom_frame.resize <B1-Motion> "$this resize_B1_motion %X %Y"
+ # - Button "Pencil"
+ set mode_pen_but [ttk::button $bottom_frame.mode_pen_but \
+ -command "$this change_mode P" \
+ -image ::ICONS::16::pencil \
+ ]
+ DynamicHelp::add $bottom_frame.mode_pen_but -text [mc "Pencil"]
+ setStatusTip -widget $mode_pen_but -text [mc "Pencil"]
+ pack $mode_pen_but -side left -ipady 0
+ # - Button "Line"
+ set mode_line_but [ttk::button $bottom_frame.mode_line_but \
+ -command "$this change_mode L" \
+ -image ::ICONS::16::line \
+ ]
+ DynamicHelp::add $bottom_frame.mode_line_but -text [mc "Line"]
+ setStatusTip -widget $mode_line_but -text [mc "Draw lines"]
+ pack $mode_line_but -side left -ipady 0
+ # - Button "Arrow"
+ set mode_arrow_but [ttk::button $bottom_frame.mode_arrow_but \
+ -command "$this change_mode A" \
+ -image ::ICONS::16::arr \
+ ]
+ DynamicHelp::add $bottom_frame.mode_arrow_but -text [mc "Arrow"]
+ setStatusTip -widget $mode_arrow_but -text [mc "Draw arrows"]
+ pack $mode_arrow_but -side left -ipady 0
+ # - Button "Retangle"
+ set mode_rectangle_but [ttk::button $bottom_frame.mode_rectangle_but \
+ -command "$this change_mode R" \
+ -image ::ICONS::16::grid1 \
+ ]
+ DynamicHelp::add $bottom_frame.mode_rectangle_but -text [mc "Retangle"]
+ setStatusTip -widget $mode_rectangle_but -text [mc "Draw retangles"]
+ pack $mode_rectangle_but -side left -ipady 0
+ # - Button "Oval"
+ set mode_oval_but [ttk::button $bottom_frame.mode_oval_but \
+ -command "$this change_mode O" \
+ -image ::ICONS::16::oval \
+ ]
+ DynamicHelp::add $bottom_frame.mode_oval_but -text [mc "Oval"]
+ setStatusTip -widget $mode_oval_but -text [mc "Draw ovals"]
+ pack $mode_oval_but -side left -ipady 0
+ # - Button "Insert text"
+ set mode_text_but [ttk::button $bottom_frame.mode_text_but \
+ -command "$this change_mode T" \
+ -image ::ICONS::16::editclear \
+ ]
+ DynamicHelp::add $bottom_frame.mode_text_but -text [mc "Insert text"]
+ setStatusTip -widget $mode_text_but -text [mc "Insert text"]
+ pack $mode_text_but -side left -ipady 0
+ # - Button "Move"
+ set move_but [ttk::button $bottom_frame.move_but \
+ -command "$this change_mode M" \
+ -image ::ICONS::16::mouse \
+ ]
+ DynamicHelp::add $bottom_frame.move_but -text [mc "Move"]
+ setStatusTip -widget $move_but -text [mc "Move"]
+ pack $move_but -side left -ipady 0
+ # - Button "Eraser"
+ set mode_clear_but [ttk::button $bottom_frame.mode_clear_but \
+ -command "$this change_mode C" \
+ -image ::ICONS::16::eraser \
+ ]
+ DynamicHelp::add $bottom_frame.mode_clear_but -text [mc "Eraser"]
+ setStatusTip -widget $mode_clear_but -text [mc "Eraser"]
+ pack $mode_clear_but -side left -ipady 0
+ # - Button "Select color"
+ set select_color_but [button $bottom_frame.select_color_but \
+ -command "$this select_color" \
+ -bd 1 -relief raised -overrelief raised \
+ -activebackground $selected_color \
+ -bg $selected_color -pady 0 \
+ ]
+ DynamicHelp::add $bottom_frame.select_color_but -text [mc "Select color"]
+ setStatusTip -widget $select_color_but -text [mc "Select color"]
+ pack $select_color_but -side right -ipady 0 -pady 0 -padx 8
+ # - Button "Insert image"
+ set load_image_but [ttk::button $bottom_frame.load_image_but \
+ -command "$this load_image" \
+ -image ::ICONS::16::fileimport \
+ ]
+ DynamicHelp::add $bottom_frame.load_image_but -text [mc "Insert image"]
+ setStatusTip -widget $load_image_but -text [mc "Insert image"]
+ pack $load_image_but -side right -ipady 0
+ # - Button "Clear all"
+ set clear_all_but [ttk::button $bottom_frame.clear_all_but \
+ -command "$this canvas_clear_all" \
+ -image ::ICONS::16::emptytrash \
+ ]
+ DynamicHelp::add $bottom_frame.clear_all_but -text [mc "Clear all"]
+ setStatusTip -widget $clear_all_but -text [mc "Clear all"]
+ pack $clear_all_but -side right -ipady 0
+ # - Separator
+ pack [ttk::separator $bottom_frame.sep0 \
+ -orient vertical \
+ ] -fill y -padx 5 -side right
+ # Restore default states of buttons on the bottom bar
+ foreach w [list \
+ $mode_pen_but $mode_line_but $mode_arrow_but \
+ $mode_rectangle_but $mode_oval_but $mode_text_but \
+ $mode_clear_but $load_image_but $clear_all_but \
+ $move_but \
+ ] {
+ $w configure -style Notes_Flat.TButton
+ }
+
+ # Pack all components of the window
+ pack $title_bar -fill x
+ pack $canvas_widget -fill both -expand 1
+ pack $bottom_frame -fill x -side bottom
+ pack $main_frame -fill both -expand 1 -padx 2 -pady 2
+
+ # Set default drawing mode
+ change_mode P
+
+ # Show the window
+ bind $win <Visibility> "$this raise_win"
+ place $win \
+ -x [lindex $geometry 0] \
+ -y [lindex $geometry 1] \
+ -width [lindex $geometry 2] \
+ -height [lindex $geometry 3] \
+ -anchor nw
+ raise $win
+ }
+
+ ## Insure window visibility
+ # @return void
+ public method raise_win {} {
+ if {!$allow_raise_win} {return}
+ set allow_raise_win 0
+ after 1000 "catch {$this set_allow_raise_win}"
+ raise $win
+ }
+
+ ## @see raise_win
+ # @return void
+ public method set_allow_raise_win {} {
+ set allow_raise_win 1
+ }
+
+ ## Prompt user for text to insert to the canvas
+ # @return void
+ private method prompt_for_text {} {
+ set ::Notes::text_prompt_text {}
+ set dialog [toplevel .notes_pd -bg {#EEEEEE}]
+
+ ## Create top frame
+ set frame [frame $dialog.frm]
+ # - Label "Text"
+ pack [label $frame.lbl \
+ -text [mc "Text:"] \
+ ] -side left
+ # - EntryBox
+ set entry [ttk::entry $frame.text_entry \
+ -textvariable ::Notes::text_prompt_text \
+ -width 30 \
+ ]
+ # Pack them
+ pack $entry -side left -fill x -expand 1
+ pack $frame -padx 5 -pady 5 -fill x -expand 1
+ # Set events bindings
+ bind $entry <Return> "
+ grab release $dialog
+ destroy $dialog
+ "
+ bind $entry <Escape> "
+ set ::Notes::text_prompt_text {}
+ grab release $dialog
+ destroy $dialog
+ "
+
+ ## Create bottom frame
+ set frame [frame $dialog.frm_b]
+ # - Button "Cancel"
+ pack [ttk::button $dialog.cancel_button \
+ -compound left \
+ -image ::ICONS::16::button_cancel \
+ -text [mc "Cancel"] \
+ -command "
+ set ::Notes::text_prompt_text {}
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side right
+ # - Button "Ok"
+ pack [ttk::button $dialog.ok_button \
+ -compound left \
+ -image ::ICONS::16::ok \
+ -text [mc "Ok"] \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side right
+ pack $frame -pady 5 -padx 5 -fill x
+
+ wm title $dialog [mc "Enter text"]
+ wm transient $dialog .
+ wm geometry $dialog =250x70+[expr {[winfo screenwidth $win] / 2 - 250}]+[expr {[winfo screenheight $win] / 2 - 70}]
+ update
+ focus -force $entry
+ grab $dialog
+ raise $dialog
+ tkwait window $dialog
+
+ set text_to_write ${::Notes::text_prompt_text}
+ return [string length $text_to_write]
+ }
+
+ ## Event handler: canvas <Enter>
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method canvas_enter {x y} {
+ switch -- $drawing_mode {
+ T { ;# Insert text
+ $canvas_widget create text $x $y -text $text_to_write -anchor w -tags incomplete -font $canvas_text_font -fill $selected_color
+ }
+ I { ;# Import image
+ $canvas_widget create image $x $y -image $loaded_image -tags incomplete
+ }
+ }
+ }
+
+ ## Event handler: canvas <Button-1>
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method canvas_B1 {x y} {
+ set click_X $x
+ set click_Y $y
+
+ switch -- $drawing_mode {
+ C { ;# Eraser
+ set flag_modified 1
+ $canvas_widget create rectangle \
+ [expr {$x - 10}] [expr {$y - 10}] \
+ [expr {$x + 10}] [expr {$y + 10}] \
+ -outline $bgcolor2 -fill $bgcolor2
+ }
+ T { ;# Insert text
+ set flag_modified 1
+ $canvas_widget dtag incomplete incomplete
+ $canvas_widget create text $x $y -text $text_to_write -anchor w -tags incomplete -font $canvas_text_font -fill $selected_color
+ }
+ I { ;# Import image
+ set flag_modified 1
+ $canvas_widget dtag incomplete incomplete
+ $canvas_widget create image $x $y -image $loaded_image -tags incomplete
+ }
+ }
+
+ focus $canvas_widget
+ }
+
+ ## Event handler: canvas <Motion>
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method canvas_motion {x y} {
+ switch -- $drawing_mode {
+ C { ;# Eraser
+ $canvas_widget delete incomplete
+ $canvas_widget create rectangle \
+ [expr {$x - 10}] [expr {$y - 10}] \
+ [expr {$x + 10}] [expr {$y + 10}] \
+ -tag incomplete -outline #FF0000
+ }
+ T { ;# Insert text
+ $canvas_widget coords incomplete $x $y
+ }
+ I { ;# Import image
+ $canvas_widget coords incomplete $x $y
+ }
+ }
+ }
+
+ ## Event handler: canvas <B1-Motion>
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method canvas_B1_motion {x y} {
+ $canvas_widget delete incomplete
+ switch -- $drawing_mode {
+ C { ;# Eraser
+ set flag_modified 1
+ $canvas_widget create rectangle \
+ [expr {$x - 10}] [expr {$y - 10}] \
+ [expr {$x + 10}] [expr {$y + 10}] \
+ -outline $bgcolor2 -fill $bgcolor2
+ $canvas_widget create rectangle \
+ [expr {$x - 10}] [expr {$y - 10}] \
+ [expr {$x + 10}] [expr {$y + 10}] \
+ -tag incomplete -outline #FF0000
+ }
+ T { ;# Insert text
+ if {![llength [$canvas_widget find withtag incomplete]]} {
+ $canvas_widget create text $x $y -text $text_to_write -anchor w -tags incomplete -font $canvas_text_font -fill $selected_color
+ }
+ $canvas_widget coords incomplete $x $y
+ }
+ O { ;# Draw oval
+ $canvas_widget create oval $click_X $click_Y $x $y -tag incomplete -dash {_} -outline $selected_color
+ }
+ R { ;# Draw rectangle
+ $canvas_widget create rectangle $click_X $click_Y $x $y -tag incomplete -dash {_} -outline $selected_color
+ }
+ L { ;# Draw line
+ $canvas_widget create line $click_X $click_Y $x $y -tag incomplete -dash {_} -fill $selected_color
+ }
+ P { ;# Pencil
+ set flag_modified 1
+ $canvas_widget create line $click_X $click_Y $x $y -fill $selected_color
+ set click_X $x
+ set click_Y $y
+ }
+ A { ;# Draw arrow
+ $canvas_widget create line $click_X $click_Y $x $y -tag incomplete -dash {_} -arrow last -fill $selected_color
+ }
+ I { ;# Import image
+ if {![llength [$canvas_widget find withtag incomplete]]} {
+ $canvas_widget create image $x $y -image $loaded_image -tags incomplete
+ }
+ $canvas_widget coords incomplete $x $y
+ }
+ M { ;# Move canvas
+ $canvas_widget move all [expr {$x - $click_X}] [expr {$y - $click_Y}]
+
+ set click_X $x
+ set click_Y $y
+ }
+ }
+ }
+
+ ## Event handler: canvas <ButtonRelease-1>
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method canvas_B1_release {x y} {
+ switch -- $drawing_mode {
+ O { ;# Draw oval
+ set flag_modified 1
+ $canvas_widget itemconfigure incomplete -dash {} -outline $selected_color
+ $canvas_widget dtag incomplete incomplete
+ }
+ R { ;# Draw rectangle
+ set flag_modified 1
+ $canvas_widget itemconfigure incomplete -dash {} -outline $selected_color
+ $canvas_widget dtag incomplete incomplete
+ }
+ L { ;# Draw line
+ set flag_modified 1
+ $canvas_widget itemconfigure incomplete -dash {} -fill $selected_color
+ $canvas_widget dtag incomplete incomplete
+ }
+ A { ;# Draw arrow
+ set flag_modified 1
+ $canvas_widget itemconfigure incomplete -dash {} -fill $selected_color
+ $canvas_widget dtag incomplete incomplete
+ }
+ }
+ }
+
+ ## Event handler: canvas <Leave>
+ # @return void
+ public method canvas_leave {} {
+ $canvas_widget delete incomplete
+ }
+
+ ## Completely clear the canvas
+ # @return void
+ public method canvas_clear_all {} {
+ if {[tk_messageBox \
+ -parent . \
+ -type yesno \
+ -icon question \
+ -title [mc "Are you sure ?"] \
+ -message [mc "Do you really want to clear this notepad\n(there is no undo action)"] \
+ ] != {yes}} {
+ return
+ }
+ $canvas_widget delete all
+ }
+
+ ## Select drawing color
+ # @return void
+ public method select_color {} {
+ set color [SelectColor .select_color \
+ -parent . \
+ -color $selected_color \
+ -title [mc "Select color"] \
+ ]
+
+ if {$color != {}} {
+ set selected_color $color
+ $select_color_but configure -bg $color -activebackground $color
+ }
+ }
+
+ ## Select image file to import
+ # @return void
+ public method load_image {} {
+ catch {delete object ::fsd}
+
+ set directory {}
+ catch {
+ set directory [$::X::actualProject cget -projectPath]
+ }
+
+ KIFSD::FSD ::fsd \
+ -directory $directory \
+ -title [mc "Insert image from file"] \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{PNG files} {*.png}}
+ {{All files} {*}}
+ }
+
+ ::fsd setokcmd "$this load_image_file \[::fsd get\]"
+ ::fsd activate
+ }
+
+ ## Import image from file
+ # @parm String file - Full file name
+ # @return void
+ public method load_image_file {file} {
+ set loaded_image {}
+ if {[catch {
+ set loaded_image [image create photo -file $file]
+ }]} {
+ tk_messageBox \
+ -title [mc "Unable to read file"] \
+ -type ok -icon warning \
+ -message [mc "Unable to read file:\n%s" $file]
+ return
+ }
+
+ if {$loaded_image != {}} {
+ change_mode I
+ }
+ }
+}
diff --git a/lib/utilities/rs232debugger.tcl b/lib/utilities/rs232debugger.tcl
new file mode 100755
index 0000000..dacb8d5
--- /dev/null
+++ b/lib/utilities/rs232debugger.tcl
@@ -0,0 +1,1460 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements RS232/UART debugger
+# --------------------------------------------------------------------------
+
+class RS232Debugger {
+ ## COMMON
+ common count 0 ;# Int: Counter of class instances
+ # Font: Big bold font
+ common bold_font [font create \
+ -family {helvetica} \
+ -size -12 -weight {bold} \
+ ]
+ # Font: Tiny normal font
+ common tiny_font [font create \
+ -family {helvetica} \
+ -size -9 -weight {normal} \
+ ]
+ # Font: Tiny bold font
+ common tiny_font_bold [font create \
+ -family {helvetica} \
+ -size -9 -weight {bold} \
+ ]
+ # Font: Normal font
+ common normal_font [font create \
+ -family {helvetica} \
+ -size -11 -weight {normal} \
+ ]
+ # Font: Also normal font, but a bit larger
+ common big_font [font create \
+ -family {helvetica} \
+ -size -12 -weight {normal} \
+ ]
+ # Int: Pool interval for selected RS232 interface
+ common POOL_INTERVAL 50 ;# mili-seconds
+ # List of Int: Available baud rates for RS232
+ common available_baud_rates {
+ 50 75 110 134 150 200
+ 300 600 1200 1800 2400 4800
+ 9600 19200 38400 57600 115200 230400
+ 460800
+ }
+
+ # List: Configuration list
+ common config_list $::CONFIG(RS232_DEBUGGER)
+
+
+ ## PRIVATE
+ private variable obj_idx ;# Int: Object index
+ private variable win ;# Widget: Dialog window
+ private variable connector_canvas ;# Widget: Canvas widget displaying the DE-9 connector
+ private variable port_combobox ;# Widget: Combobox for device file selection
+ private variable status_bar_label ;# Widget: Status bar
+
+ private variable baud_cb ;# Widget: ComboBox for selecting baud rate
+ private variable parity_cb ;# Widget: ComboBox for selecting type of parity
+ private variable data_cb ;# Widget: ComboBox for selecting number of data bits
+ private variable stop_cb ;# Widget: ComboBox for selecting number of stop bits
+ private variable enable_reception_chb ;# Widget: Check button "Enable reception"
+ private variable close_connection_button ;# Widget: Button "Close connection"
+
+ private variable leds ;# Array of CanvasObjects: LEDs indicating logical states on wires
+ private variable dtr_button ;# Widget: Button "DTR"
+ private variable rts_button ;# Widget: Button "RTS"
+ private variable break_button ;# Widget: Button "Break"
+
+ private variable send_selected_button ;# Widget: Button "Send selected"
+ private variable clear_selected_rec_button ;# Widget: Button "Clear selected" in section "Receive"
+ private variable receive_here_button ;# Widget: Button "Receive here"
+ private variable clear_selected_snd_button ;# Widget: Button "Clear selected" in section "Send"
+ private variable receive_hexeditor ;# Object: Hexeditor intented for reception
+ private variable send_hexeditor ;# Object: Hexeditor intented for sending
+
+ private variable pool_timer {} ;# Object: Pool timer object
+ private variable channel {} ;# Channel: Opened device file
+ private variable port_filename {} ;# String: Device file name
+ private variable reception_address 0 ;# Int: Address in reception hexeditor where received data are stored
+ private variable reception_enabled 1 ;# Bool: Reception enabled
+ private variable prev_tty_status ;# List: Previous TTY status (before any action performed by this code)
+
+ private variable baud_conf {9600} ;# Int: Selected baud rate for communication
+ private variable parity_conf {n} ;# Char: Selected type of parity
+ private variable data_conf {8} ;# Int: Number of data bits
+ private variable stop_conf {1} ;# Int: Number of stop bits
+
+
+ ## Object constructor
+ constructor {} {
+ # Configure local ttk styles
+ ttk::style configure RS232Debugger_FileInUse.TCombobox \
+ -fieldbackground {#DDFFDD}
+ ttk::style map RS232Debugger_FileInUse.TCombobox \
+ -fieldbackground [list {readonly !readonly} {#DDFFDD}]
+
+ ttk::style configure RS232Debugger_FileFound.TCombobox \
+ -fieldbackground {#FFFFAA}
+ ttk::style map RS232Debugger_FileFound.TCombobox \
+ -fieldbackground [list {readonly !readonly} {#FFFFAA}]
+
+ ttk::style configure RS232Debugger_FileNotFound.TCombobox \
+ -fieldbackground {#FFDDDD}
+ ttk::style map RS232Debugger_FileNotFound.TCombobox \
+ -fieldbackground [list {readonly !readonly} {#FFDDDD}]
+
+ ttk::style configure RS232Debugger_SignalAllDefault.TButton \
+ -foreground {#000000} \
+ -background {#DDDDDD}
+ ttk::style map RS232Debugger_SignalAllDefault.TButton \
+ -background [list active {#EEEEEE}]
+
+ ttk::style configure RS232Debugger_SignalTxDTrue.TButton \
+ -background {#AAFFAA} \
+ -foreground {#000000}
+ ttk::style map RS232Debugger_SignalTxDTrue.TButton \
+ -background [list active {#DDFFDD}] \
+ -foreground [list active {#00FF00}]
+
+ ttk::style configure RS232Debugger_SignalNormalTrue.TButton \
+ -background {#AAFFAA} \
+ -foreground {#000000}
+ ttk::style map RS232Debugger_SignalNormalTrue.TButton \
+ -background [list active {#DDFFDD}] \
+ -foreground [list active {#00FF00}]
+
+ ttk::style configure RS232Debugger_SignalTxDFalse.TButton \
+ -background {#DDDDDD} \
+ -foreground {#000000}
+ ttk::style map RS232Debugger_SignalTxDFalse.TButton \
+ -background [list active {#EEEEEE}] \
+ -foreground [list active {#000000}]
+
+ ttk::style configure RS232Debugger_SignalNormalFalse.TButton \
+ -background {#FFAAAA} \
+ -foreground {#000000}
+ ttk::style map RS232Debugger_SignalNormalFalse.TButton \
+ -background [list active {#FFDDDD}] \
+ -foreground [list active {#FF0000}]
+
+
+ incr count
+ set obj_idx $count
+
+ array set prev_tty_status {0 {} cts {} dsr {} ri {} dcd {} dtr {} rts {} break {}}
+
+ # Validate and possibly correct configuration list
+ if {[lsearch -ascii -exact $available_baud_rates [lindex $config_list 0]] == -1} {
+ puts stderr [mc "RS232 DBG: Invalid baud rate, setting to default: %s" $baud_conf]
+ lset config_list 0 $baud_conf
+ }
+ if {[lsearch -ascii -exact {n o e m s} [lindex $config_list 1]] == -1} {
+ puts stderr [mc "RS232 DBG: Invalid parity, setting to default: %s" $parity_conf]
+ lset config_list 1 $parity_conf
+ }
+ if {[lsearch -ascii -exact {5 6 7 8} [lindex $config_list 2]] == -1} {
+ puts stderr [mc "RS232 DBG: Invalid data length, setting to default: %s" $data_conf]
+ lset config_list 2 $data_conf
+ }
+ if {[lsearch -ascii -exact {1 2} [lindex $config_list 3]] == -1} {
+ puts stderr [mc "RS232 DBG: Invalid stop bit length, setting to default: %s" $stop_conf]
+ lset config_list 3 $stop_conf
+ }
+ if {[lsearch -ascii -exact {0 1} [lindex $config_list 4]] == -1} {
+ puts stderr [mc "RS232 DBG: Invalid flag reception_enabled, setting to default: %s" $reception_enabled]
+ lset config_list 4 $reception_enabled
+ }
+ if {![string is digit -strict [lindex $config_list 9]] || [lindex $config_list 9] < 0 || [lindex $config_list 9] > 256} {
+ puts ">> {[lindex $config_list 9]}"
+ puts stderr [mc "RS232 DBG: Invalid reception address, setting to default: %s" $reception_address]
+ lset config_list 9 $reception_address
+ }
+ if {![string is digit -strict [lindex $config_list 7]] || [lindex $config_list 7] < 0 || [lindex $config_list 7] > 255} {
+ puts stderr [mc "RS232 DBG: Invalid current cell address, setting to default: %s" "0"]
+ lset config_list 7 0
+ }
+ if {![string is digit -strict [lindex $config_list 8]] || [lindex $config_list 8] < 0 || [lindex $config_list 8] > 255} {
+ puts stderr [mc "RS232 DBG: Invalid current cell address, setting to default: %s" "0"]
+ lset config_list 8 0
+ }
+
+ # Load configuration list
+ set baud_conf [lindex $config_list 0]
+ set parity_conf [lindex $config_list 1]
+ set data_conf [lindex $config_list 2]
+ set stop_conf [lindex $config_list 3]
+ set reception_enabled [lindex $config_list 4]
+ set reception_address [expr {int([lindex $config_list 9])}]
+ if {$reception_address == 256} {
+ set reception_address 0
+ }
+
+ # Initialize GUI
+ create_gui
+ set_tty_controls_state 0
+
+ # Restore data displayed in hexeditors
+ foreach idx {5 6} hexedit [list $receive_hexeditor $send_hexeditor] {
+ set data [lindex $config_list $idx]
+ if {![llength $data]} {
+ continue
+ }
+
+ for {set i 0} {$i < 0x100} {incr i} {
+ $hexedit setValue $i [lindex $data $i]
+ }
+ }
+
+ # restore addresses of current cells in hexeditors
+ $receive_hexeditor setCurrentCell [lindex $config_list 7]
+ $send_hexeditor setCurrentCell [lindex $config_list 8]
+ }
+
+ ## Object destructor
+ destructor {
+ # Create a new configuration list
+ set config_list [list \
+ $baud_conf $parity_conf $data_conf \
+ $stop_conf $reception_enabled \
+ [$receive_hexeditor get_values 0 255] \
+ [$send_hexeditor get_values 0 255] \
+ [$receive_hexeditor getCurrentCell] \
+ [$send_hexeditor getCurrentCell] \
+ $reception_address \
+ ]
+
+ # Cancel pool timer
+ catch {after cancel $pool_timer}
+
+ # Close opended channel
+ if {$channel !={}} {
+ catch {fileevent $channel readable {}}
+ catch {close $channel}
+ }
+
+ # Destroy GUI
+ destroy $win
+ }
+
+ ## Create dialog GUI
+ # @return void
+ private method create_gui {} {
+ # Create window
+ set win [toplevel .rs232debugger$count -class [mc "RS232 Debugger"] -bg {#EEEEEE}]
+
+ # Create status bar
+ set status_bar_label [label $win.status_bar_label -justify left -pady 0 -anchor w]
+ pack $status_bar_label -side bottom -fill x
+
+ # Create top frame
+ set top_frame [frame $win.top_frame]
+ create_top_frame $top_frame
+ pack $top_frame -fill x -anchor nw
+
+ # Create bottom frame
+ set bottom_frame [frame $win.bottom_frame]
+ create_bottom_frame $bottom_frame
+ pack $bottom_frame -fill x -anchor nw
+
+ $receive_hexeditor clearBgHighlighting 0
+ $receive_hexeditor set_bg_hg $reception_address 1 0
+
+ # Configure window
+ wm title $win [mc "UART/RS232 Debugger - MCU 8051 IDE"]
+ wm iconphoto $win ::ICONS::16::chardevice
+ wm resizable $win 0 0
+ wm protocol $win WM_DELETE_WINDOW "catch {delete object $this}"
+ }
+
+ ## Set status bar tip for specified widget
+ # @parm Widget widget - Target widget
+ # @parm String text - Text of the stutus tip
+ # @return void
+ private method set_status_tip {widget text} {
+ bind $widget <Enter> "$status_bar_label configure -text {$text}"
+ bind $widget <Leave> "$status_bar_label configure -text {}"
+ }
+
+ ## Draw DE-9 connector in the $connector_canvas
+ # @parm Int x - X offset
+ # @parm Int y - Y offset
+ # @return void
+ private method draw_connector {x y} {
+ ## Draw package
+ set coords {
+ 1 19 3 16 27 1 33 1 37 6 37 88
+ 33 91 27 91 3 80 1 74 1 19
+ }
+
+ # Transform coordinates -- adjust them to the given origin
+ set coordinates [list]
+ set len [llength $coords]
+ for {set m 0; set n 1} {$n < $len} {incr m 2; incr n 2} {
+ lappend coordinates \
+ [expr {[lindex $coords $m] + $x}]
+ lappend coordinates \
+ [expr {[lindex $coords $n] + $y}]
+ }
+
+ $connector_canvas create line $coordinates \
+ -tags connector -width 1 -fill #000000
+
+ ## Draw pins
+ set coords {
+ 28 16 28 32 28 48 28 64 28 80
+ 12 24 12 40 12 56 12 72
+ }
+ set tags {dcd_pin rxd_pin txd_pin dtr_pin gnd_pin dsr_pin rts_pin cts_pin ri_pin}
+
+ # Transform coordinates -- adjust them to the given origin
+ set len [llength $coords]
+ for {set m 0; set n 1; set i 0} {$n < $len} {incr m 2; incr n 2; incr i} {
+ $connector_canvas create oval \
+ [expr {[lindex $coords $m] - 2 + $x}] \
+ [expr {[lindex $coords $n] - 2 + $y}] \
+ [expr {[lindex $coords $m] + 2 + $x}] \
+ [expr {[lindex $coords $n] + 2 + $y}] \
+ -tags connector -width 1 \
+ -outline #000000 -tags [lindex $tags $i]
+ }
+
+ ## Draw pin numbers
+ set coords {
+ 21 16 21 32 21 48 21 64 21 80
+ 5 24 5 40 5 56 5 72
+ }
+ set tags {{} dcd_num rxd_num txd_num dtr_num gnd_num dsr_num rts_num cts_num ri_num}
+
+ # Transform coordinates -- adjust them to the given origin
+ set len [llength $coords]
+ for {set m 0; set n 1; set i 1} {$n < $len} {incr m 2; incr n 2; incr i} {
+ $connector_canvas create text \
+ [expr {[lindex $coords $m] + $x}] \
+ [expr {[lindex $coords $n] + $y}] \
+ -tags connector -fill #000000 \
+ -anchor center -justify center -text $i \
+ -font $tiny_font -tags [lindex $tags $i]
+ }
+
+ ## Draw common ground
+ set coords {
+ 31 80 60 80 60 105 53 105 67 105
+ }
+
+ # Transform coordinates -- adjust them to the given origin
+ set coordinates [list]
+ set len [llength $coords]
+ for {set m 0; set n 1} {$n < $len} {incr m 2; incr n 2} {
+ lappend coordinates \
+ [expr {[lindex $coords $m] + $x}]
+ lappend coordinates \
+ [expr {[lindex $coords $n] + $y}]
+ }
+
+ $connector_canvas create line $coordinates \
+ -tags gnd_wire -width 1 -fill #000000
+
+ $connector_canvas bind gnd_wire <Enter> "$this wire_enter gnd"
+ $connector_canvas bind gnd_wire <Leave> "$this wire_leave gnd"
+
+ ## Write texts
+ $connector_canvas create text \
+ [expr {$x + 10}] [expr {$y - 25}] \
+ -anchor n -justify left \
+ -font $big_font -text [mc "RS-232\nDTE"]
+ $connector_canvas create text \
+ [expr {$x + 10}] [expr {$y + 100}] \
+ -anchor n -justify left \
+ -font $big_font -text [mc "DE-9"]
+ }
+
+ ## Draw wires, LEDs and buttons in the $connector_canvas
+ # @parm Int x - X offset
+ # @parm Int y - Y offset
+ # @return void
+ private method draw_wires_and_controls {x y} {
+ ## DCD
+ set leds(dcd) [label $connector_canvas.dcd_led \
+ -image ::ICONS::16::ledgray \
+ ]
+ bind $leds(dcd) <Enter> "$this wire_enter dcd"
+ bind $leds(dcd) <Leave> "$this wire_leave dcd"
+ $connector_canvas create window \
+ [expr {$x + 100}] [expr {$y + 1}] \
+ -anchor center -window $leds(dcd)
+ $connector_canvas create line \
+ [expr {$x + 31}] [expr {$y + 16}] \
+ [expr {$x + 100}] [expr {$y + 16}] \
+ [expr {$x + 100}] [expr {$y + 1}] \
+ -width 1 -fill {#888888} -tags dcd_wire
+ $connector_canvas create line \
+ [expr {$x + 74}] [expr {$y + 16}] \
+ [expr {$x + 75}] [expr {$y + 16}] \
+ -width 1 -fill {#888888} -tags dcd_wire \
+ -arrow last
+ $connector_canvas create text \
+ [expr {$x + 100}] [expr {$y - 7}] \
+ -tags connector -fill #000000 \
+ -anchor s -justify left -text [mc "DCD"]\
+ -font $normal_font
+
+ ## DSR
+ set leds(dsr) [label $connector_canvas.dsr_led \
+ -image ::ICONS::16::ledgray \
+ ]
+ bind $leds(dsr) <Enter> "$this wire_enter dsr"
+ bind $leds(dsr) <Leave> "$this wire_leave dsr"
+ $connector_canvas create window \
+ [expr {$x + 135}] [expr {$y + 1}] \
+ -anchor center -window $leds(dsr)
+
+ $connector_canvas create line \
+ [expr {$x + 15}] [expr {$y + 24}] \
+ [expr {$x + 135}] [expr {$y + 24}] \
+ [expr {$x + 135}] [expr {$y + 1}] \
+ -width 1 -fill {#888888} -tags dsr_wire
+ $connector_canvas create line \
+ [expr {$x + 74}] [expr {$y + 24}] \
+ [expr {$x + 75}] [expr {$y + 24}] \
+ -width 1 -fill {#888888} -tags dsr_wire \
+ -arrow last
+ $connector_canvas create text \
+ [expr {$x + 135}] [expr {$y - 7}] \
+ -tags connector -fill #000000 \
+ -anchor s -justify left -text [mc "DSR"]\
+ -font $normal_font
+
+ ## CTS
+ set leds(cts) [label $connector_canvas.cts_led \
+ -image ::ICONS::16::ledgray \
+ ]
+ bind $leds(cts) <Enter> "$this wire_enter cts"
+ bind $leds(cts) <Leave> "$this wire_leave cts"
+ $connector_canvas create window \
+ [expr {$x + 170}] [expr {$y + 1}] \
+ -anchor center -window $leds(cts)
+
+ $connector_canvas create line \
+ [expr {$x + 15}] [expr {$y + 56}] \
+ [expr {$x + 170}] [expr {$y + 56}] \
+ [expr {$x + 170}] [expr {$y + 1}] \
+ -width 1 -fill {#888888} -tags cts_wire
+ $connector_canvas create line \
+ [expr {$x + 74}] [expr {$y + 56}] \
+ [expr {$x + 75}] [expr {$y + 56}] \
+ -width 1 -fill {#888888} -tags cts_wire \
+ -arrow last
+ $connector_canvas create text \
+ [expr {$x + 170}] [expr {$y - 7}] \
+ -tags connector -fill #000000 \
+ -anchor s -justify left -text [mc "CTS"]\
+ -font $normal_font
+
+ ## RI
+ set leds(ri) [label $connector_canvas.ri_led \
+ -image ::ICONS::16::ledgray \
+ ]
+ bind $leds(ri) <Enter> "$this wire_enter ri"
+ bind $leds(ri) <Leave> "$this wire_leave ri"
+ $connector_canvas create window \
+ [expr {$x + 205}] [expr {$y + 1}] \
+ -anchor center -window $leds(ri)
+
+ $connector_canvas create line \
+ [expr {$x + 15}] [expr {$y + 72}] \
+ [expr {$x + 205}] [expr {$y + 72}] \
+ [expr {$x + 205}] [expr {$y + 1}] \
+ -width 1 -fill {#888888} -tags ri_wire
+ $connector_canvas create line \
+ [expr {$x + 74}] [expr {$y + 72}] \
+ [expr {$x + 75}] [expr {$y + 72}] \
+ -width 1 -fill {#888888} -tags ri_wire \
+ -arrow last
+ $connector_canvas create text \
+ [expr {$x + 205}] [expr {$y - 7}] \
+ -tags connector -fill #000000 \
+ -anchor s -justify left -text [mc "RI"] \
+ -font $normal_font
+
+
+ ## DTR
+ set dtr_button [ttk::button $connector_canvas.dtr_button \
+ -style RS232Debugger_SignalAllDefault.TButton \
+ -command "$this invert_tty_status_bit dtr" \
+ -text "-" \
+ -width 2 \
+ ]
+ bind $dtr_button <Enter> "$this wire_enter dtr"
+ bind $dtr_button <Leave> "$this wire_leave dtr"
+ $connector_canvas create window \
+ [expr {$x + 100}] [expr {$y + 95}] \
+ -anchor center -window $dtr_button
+
+ $connector_canvas create line \
+ [expr {$x + 31}] [expr {$y + 64}] \
+ [expr {$x + 100}] [expr {$y + 64}] \
+ [expr {$x + 100}] [expr {$y + 95}] \
+ -width 1 -fill {#888888} -tags dtr_wire
+ $connector_canvas create line \
+ [expr {$x + 46}] [expr {$y + 64}] \
+ [expr {$x + 45}] [expr {$y + 64}] \
+ -width 1 -fill {#888888} -tags dtr_wire \
+ -arrow last
+ $connector_canvas create text \
+ [expr {$x + 100}] [expr {$y + 105}] \
+ -tags connector -fill #000000 \
+ -anchor n -justify left -text [mc "DTR"]\
+ -font $normal_font
+
+ ## RTS
+ set rts_button [ttk::button $connector_canvas.rts_button \
+ -style RS232Debugger_SignalAllDefault.TButton \
+ -command "$this invert_tty_status_bit rts" \
+ -text "-" \
+ -width 2 \
+ ]
+ bind $rts_button <Enter> "$this wire_enter rts"
+ bind $rts_button <Leave> "$this wire_leave rts"
+ $connector_canvas create window \
+ [expr {$x + 135}] [expr {$y + 95}] \
+ -anchor center -window $rts_button
+
+ $connector_canvas create line \
+ [expr {$x + 15}] [expr {$y + 40}] \
+ [expr {$x + 135}] [expr {$y + 40}] \
+ [expr {$x + 135}] [expr {$y + 95}] \
+ -width 1 -fill {#888888} -tags rts_wire
+ $connector_canvas create line \
+ [expr {$x + 46}] [expr {$y + 40}] \
+ [expr {$x + 45}] [expr {$y + 40}] \
+ -width 1 -fill {#888888} -tags rts_wire \
+ -arrow last
+ $connector_canvas create text \
+ [expr {$x + 135}] [expr {$y + 105}] \
+ -tags connector -fill #000000 \
+ -anchor n -justify left -text [mc "RTS"]\
+ -font $normal_font
+
+ ## TxD
+ set break_button [ttk::button $connector_canvas.break_button \
+ -style RS232Debugger_SignalAllDefault.TButton \
+ -command "$this invert_tty_status_bit break" \
+ -text [mc "Break"] \
+ -width 5 \
+ ]
+ bind $break_button <Enter> "$this wire_enter txd"
+ bind $break_button <Leave> "$this wire_leave txd"
+ $connector_canvas create window \
+ [expr {$x + 180}] [expr {$y + 95}] \
+ -anchor center -window $break_button
+
+ $connector_canvas create line \
+ [expr {$x + 31}] [expr {$y + 48}] \
+ [expr {$x + 180}] [expr {$y + 48}] \
+ [expr {$x + 180}] [expr {$y + 95}] \
+ -width 1 -fill {#0000FF} -tags txd_wire
+ $connector_canvas create line \
+ [expr {$x + 46}] [expr {$y + 48}] \
+ [expr {$x + 45}] [expr {$y + 48}] \
+ -width 1 -fill {#0000FF} -tags txd_wire \
+ -arrow last
+ $connector_canvas create line \
+ [expr {$x + 180}] [expr {$y + 120}] \
+ [expr {$x + 180}] [expr {$y + 105}] \
+ -width 1 -fill {#0000FF} -arrow last
+
+ ## RxD
+ $connector_canvas create line \
+ [expr {$x + 31}] [expr {$y + 32}] \
+ [expr {$x + 220}] [expr {$y + 32}] \
+ [expr {$x + 220}] [expr {$y + 90}] \
+ [expr {$x + 250}] [expr {$y + 120}] \
+ -width 1 -fill {#0000FF} -tags rxd_wire \
+ -arrow last
+ $connector_canvas create line \
+ [expr {$x + 74}] [expr {$y + 32}] \
+ [expr {$x + 75}] [expr {$y + 32}] \
+ -width 1 -fill {#0000FF} -tags rxd_wire \
+ -arrow last
+
+ foreach wire {dcd dsr cts ri dtr rts txd rxd} {
+ $connector_canvas bind ${wire}_wire <Enter> "$this wire_enter $wire"
+ $connector_canvas bind ${wire}_wire <Leave> "$this wire_leave $wire"
+ }
+ }
+
+ ## Create top frame in the dialog window (connector_canvas (left) and configuration (right))
+ # @parm Widget target_frame - Parent frame
+ # @return void
+ private method create_top_frame {target_frame} {
+
+ #
+ ## Connector canvas
+ #
+
+ # Create canvas widget
+ set connector_canvas [canvas $target_frame.canvas \
+ -width 280 -height 150 -bg {#EEEEEE} \
+ -bd 0 -relief flat -highlightthickness 0 \
+ ]
+ pack $connector_canvas -side left -anchor sw
+
+ # Fill in the connector canvas
+ draw_connector 20 30
+ draw_wires_and_controls 20 30
+
+
+
+ #
+ ## Configuration frame
+ #
+
+ # Create labelframe
+ set conf_frame [ttk::labelframe $target_frame.conf_frame\
+ -padding 5 \
+ -labelwidget [label $target_frame.conf_label \
+ -font $bold_font \
+ -compound left \
+ -text [mc "Port configuration"] \
+ -image ::ICONS::16::configure \
+ ] \
+ ]
+ pack $conf_frame -side left -anchor nw
+ # - Physical port
+ grid [label $conf_frame.port_lbl \
+ -text [mc "Physical port"] \
+ ] -row 1 -column 1 -sticky w
+ set port_combobox [ttk::combobox $conf_frame.port_cb \
+ -width 12 \
+ -validate all \
+ -validatecommand "$this port_combobox_validate %P" \
+ -exportselection 0 \
+ ]
+ bind $port_combobox <<ComboboxSelected>> \
+ "$this port_combobox_accept"
+ bind $port_combobox <Return> "$this port_combobox_accept"
+ bind $port_combobox <KP_Enter> "$this port_combobox_accept"
+
+ port_combobox_refresh
+ grid $port_combobox -row 1 -column 2 -sticky w
+ set_status_tip $port_combobox [mc "Special character file representing the target physical device"]
+ grid [ttk::button $conf_frame.port_combobox_refresh_button \
+ -image ::ICONS::16::reload \
+ -command "$this port_combobox_refresh" \
+ -style Flat.TButton \
+ ] -row 1 -column 3 -sticky w
+ set_status_tip $conf_frame.port_combobox_refresh_button [mc "Refresh list of relevant devices"]
+ # - Baud rate
+ grid [label $conf_frame.baud_lbl \
+ -text [mc "Baud rate"] \
+ ] -row 3 -column 1 -sticky w
+ set baud_cb [ttk::combobox $conf_frame.baud_cb \
+ -state readonly \
+ -width 6 \
+ -exportselection 0 \
+ -values $available_baud_rates \
+ ]
+ bind $baud_cb <<ComboboxSelected>> \
+ "$this change_port_config b \[$conf_frame.baud_cb get\]"
+ set_status_tip $baud_cb [mc "Connection speed in bps"]
+ grid $baud_cb -row 3 -column 2 -sticky w
+ $conf_frame.baud_cb current [lsearch [$conf_frame.baud_cb cget -values] $baud_conf]
+ # - Parity
+ grid [label $conf_frame.parity_lbl \
+ -text [mc "Parity"] \
+ ] -row 4 -column 1 -sticky w
+ set parity_cb [ttk::combobox $conf_frame.parity_cb \
+ -values {none odd even mark space} \
+ -state readonly \
+ -width 6 \
+ -exportselection 0 \
+ ]
+ bind $parity_cb <<ComboboxSelected>> \
+ "$this change_port_config p \[$conf_frame.parity_cb get\]"
+ set_status_tip $parity_cb [mc "Parity"]
+ grid $parity_cb -row 4 -column 2 -sticky w
+ $conf_frame.parity_cb current [lsearch {n o e m s} $parity_conf]
+ # - Data bits
+ grid [label $conf_frame.data_lbl \
+ -text [mc "Data bits"] \
+ ] -row 5 -column 1 -sticky w
+ set data_cb [ttk::combobox $conf_frame.data_cb \
+ -state readonly \
+ -width 1 \
+ -values {5 6 7 8} \
+ -exportselection 0 \
+ ]
+ bind $data_cb <<ComboboxSelected>> \
+ "$this change_port_config d \[$conf_frame.data_cb get\]"
+ set_status_tip $data_cb [mc "Number of data bits"]
+ grid $data_cb -row 5 -column 2 -sticky w
+ $conf_frame.data_cb current [lsearch [$conf_frame.data_cb cget -values] $data_conf]
+ # - Stop bits
+ grid [label $conf_frame.stop_lbl \
+ -text [mc "Stop bits"] \
+ ] -row 6 -column 1 -sticky w
+ set stop_cb [ttk::combobox $conf_frame.stop_cb \
+ -state readonly \
+ -width 1 \
+ -values {1 2} \
+ -exportselection 0 \
+ ]
+ bind $stop_cb <<ComboboxSelected>> \
+ "$this change_port_config s \[$conf_frame.stop_cb get\]"
+ set_status_tip $stop_cb [mc "Number of stop bits"]
+ grid $stop_cb -row 6 -column 2 -sticky w
+ $conf_frame.stop_cb current [lsearch [$conf_frame.stop_cb cget -values] $stop_conf]
+ # Bottom frame in configuration frame
+ set bottom_frame [frame $conf_frame.bottom_frame]
+ # - Enable reception
+ set enable_reception_chb [checkbutton $bottom_frame.enable_reception_chb\
+ -text [mc "Enable reception"] -onvalue 1 -offvalue 0 \
+ -command "$this reception_ena_dis" \
+ -variable "::RS232Debugger::enable_reception${obj_idx}" \
+ ]
+ set_status_tip $enable_reception_chb [mc "Display incoming data or discard them"]
+ set ::RS232Debugger::enable_reception${obj_idx} $reception_enabled
+ pack $enable_reception_chb -side left
+ # - Close connection
+ set close_connection_button [ttk::button \
+ $bottom_frame.close_connection_button \
+ -text [mc "Close"] \
+ -compound left \
+ -width 5 \
+ -image ::ICONS::16::fileclose \
+ -command "$this safely_terminate_connection" \
+ ]
+ set_status_tip $close_connection_button [mc "Terminate connection"]
+ pack $close_connection_button -side right -padx 5
+
+ grid $bottom_frame -row 7 -column 1 -sticky we -columnspan 3
+ }
+
+ ## Create bottom frame (hexadecimal editors)
+ # @parm Widget target_frame - Parent frame
+ # @return void
+ private method create_bottom_frame {target_frame} {
+ # Create headers ("Data to send", "Received data")
+ grid [label $target_frame.lbl_a \
+ -text [mc "Data to send"] \
+ -compound right \
+ -image ::ICONS::16::forward \
+ -padx 15 -font $bold_font \
+ ] -row 0 -column 1 -columnspan 2
+ grid [label $target_frame.lbl_b \
+ -text [mc "Received data"] \
+ -compound left \
+ -image ::ICONS::16::forward \
+ -padx 15 -font $bold_font \
+ ] -row 0 -column 3 -columnspan 2
+
+ # Create hexadecimal editors
+ set send_hexeditor [HexEditor #auto \
+ $target_frame.send_hexeditor 8 32 2 \
+ hex 1 1 5 256 \
+ ]
+ [$send_hexeditor getLeftView] configure -exportselection 0
+ $send_hexeditor bindSelectionAction "$this hexeditor_selection s"
+ grid $target_frame.send_hexeditor -row 1 -column 1 -columnspan 2
+
+ set receive_hexeditor [HexEditor #auto \
+ $target_frame.receive_hexeditor 8 32 2 \
+ hex 1 1 5 256 \
+ ]
+ [$send_hexeditor getLeftView] configure -exportselection 0
+ $receive_hexeditor bindSelectionAction "$this hexeditor_selection r"
+ grid $target_frame.receive_hexeditor -row 1 -column 3 -columnspan 2
+
+ # Create buttons "Send selected" and "Clear selected" in send part
+ set send_selected_button [ttk::button \
+ $target_frame.send_selected_button \
+ -text [mc "Send selected"] \
+ -image ::ICONS::16::forward \
+ -command "$this send_selected" \
+ -compound left \
+ -state disabled \
+ ]
+ set clear_selected_snd_button [ttk::button \
+ $target_frame.clear_selected_snd_button \
+ -text [mc "Clear selected"] \
+ -image ::ICONS::16::eraser \
+ -command "$this clear_selected_snd" \
+ -compound left \
+ -state disabled \
+ ]
+ set_status_tip $send_selected_button [mc "Send selected data"]
+ set_status_tip $clear_selected_snd_button [mc "Remove selected data"]
+ grid $send_selected_button -row 2 -column 1 -sticky we
+ grid $clear_selected_snd_button -row 2 -column 2 -sticky we
+
+ # Create buttons "Receive here" and "Clear selected" in reception part
+ set receive_here_button [ttk::button \
+ $target_frame.receive_here_button \
+ -text [mc "Receive here"] \
+ -image ::ICONS::16::down0 \
+ -command "$this receive_here" \
+ -compound left \
+ ]
+ set clear_selected_rec_button [ttk::button \
+ $target_frame.clear_selected_rec_button \
+ -text [mc "Clear selected"] \
+ -image ::ICONS::16::eraser \
+ -command "$this clear_selected_rec" \
+ -compound left \
+ -state disabled \
+ ]
+ set_status_tip $receive_here_button [mc "Receive data on current cursor position"]
+ set_status_tip $clear_selected_rec_button [mc "Remove selected data"]
+ grid $receive_here_button -row 2 -column 3 -sticky we
+ grid $clear_selected_rec_button -row 2 -column 4 -sticky we
+ }
+
+ ## Accept new device file
+ # @return void
+ public method port_combobox_accept {} {
+ change_port_file [$port_combobox get]
+ }
+
+ ## Validate contetnts of port combo box
+ # @parm String content - String to validate
+ # @return Bool - Allways true
+ public method port_combobox_validate {content} {
+ # Empty string
+ if {![string length $content]} {
+ $port_combobox configure -style TCombobox
+ return 1
+ }
+
+ # Exiting file
+ if {[file exists $content]} {
+ if {$port_filename == $content} {
+ $port_combobox configure -style RS232Debugger_FileInUse.TCombobox
+ } {
+ $port_combobox configure -style RS232Debugger_FileFound.TCombobox
+ }
+ # Not exiting file
+ } else {
+ $port_combobox configure -style RS232Debugger_FileNotFound.TCombobox
+ }
+
+ return 1
+ }
+
+ ## Refresh list of possible values on port combobox
+ # @return void
+ public method port_combobox_refresh {} {
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ $port_combobox configure -values \
+ [lsort -decreasing \
+ [glob -directory {/dev} -nocomplain -type {c} -- {tty{S,USB}*}] \
+ ]
+
+ } else { ;# Microsoft Widnows way
+ set available_ms_windows_ports [list]
+
+ for {set i 0} {$i < 10} {incr i} {
+ if {[file exists "COM${i}"]} {
+ lappend available_ms_windows_ports "COM${i}"
+ }
+ }
+
+ $port_combobox configure -values $available_ms_windows_ports
+ }
+ }
+
+ ## Change current device file
+ # @parm String filename - Path to the new device file
+ # @return void
+ private method change_port_file {filename} {
+ # File name is the same at the one already in use -> abort
+ if {$port_filename == $filename} {
+ return
+ }
+
+ # Safely terminate current connection
+ set channel_prev $channel
+ safely_terminate_connection
+ if {$channel_prev != {}} {
+ catch {
+ close $channel_prev
+ }
+ }
+
+ ## Try to open the device file
+ if {[catch {
+ if {!$::MICROSOFT_WINDOWS} { ;# POSIX way
+ set channel [open $filename {RDWR BINARY NONBLOCK}]
+ } { ;# MS Windows does not support NONBLOCK
+ set channel [open $filename {RDWR BINARY}]
+ }
+
+ # -> Fail
+ } reason]} then {
+ safely_terminate_connection
+ after idle "
+ set reason {$reason}
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon error \
+ -title {[mc {Access Error}]} \
+ -message \"[mc {Unable to open the specified file}]\n\n\${reason}\""
+ # -> Success
+ } else {
+ # Try to configure opened channel acording to specified parameters
+ if {[catch {
+ fconfigure $channel \
+ -handshake none \
+ -buffersize 0 \
+ -mode $baud_conf,$parity_conf,$data_conf,$stop_conf
+
+ fileevent $channel readable "$this receive_data"
+
+ set pool_timer [after $POOL_INTERVAL "catch {$this pool_ttystatus}"]
+ set_tty_controls_state 1
+
+ # -> Fail
+ } reason]} then {
+ safely_terminate_connection
+ after idle "
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon error \
+ -title {[mc {Access Error}]} \
+ -message \"[mc {Unable to use the specified file}]\""
+ # -> Success
+ } else {
+ $port_combobox configure -style RS232Debugger_FileInUse.TCombobox
+ set port_filename $filename
+ }
+ }
+ }
+
+ ## Modify comlink attributes
+ # @parm Char what - Attribute ID
+ # @parm String value - Attribute value
+ # @return void
+ public method change_port_config {what value} {
+ switch -- $what {
+ {b} { ;# Baud rate
+ set baud_conf $value
+ }
+ {p} { ;# Parity bit
+ switch -- $value {
+ {none} {
+ set value {n}
+ }
+ {odd} {
+ set value {o}
+ }
+ {even} {
+ set value {e}
+ }
+ {mark} {
+ set value {m}
+ }
+ {space} {
+ set value {s}
+ }
+ }
+ set parity_conf $value
+ }
+ {d} { ;# Data bits
+ set data_conf $value
+ }
+ {s} { ;# Stop bits
+ set stop_conf $value
+ }
+ }
+
+ # Cancel if there is no channel opened
+ if {$channel == {}} {
+ return
+ }
+
+ # Change channel configuration
+ if {[catch {
+ fconfigure $channel -mode $baud_conf,$parity_conf,$data_conf,$stop_conf
+ } reason]} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon error \
+ -title [mc "Uknown failure"] \
+ -message [mc "Unable to change port configuration"]
+ }
+ }
+
+ ## Handle selection event in hexeditor
+ # @parm Char editor - Editor ID
+ # @parm Bool anything_selected - 1 == anything selected; 0 == Nothing selected
+ # @return void
+ public method hexeditor_selection {editor anything_selected} {
+ if {$anything_selected} {
+ set state {normal}
+ } {
+ set state {disabled}
+ }
+
+ if {$editor == {s}} {
+ $send_selected_button configure -state $state
+ $clear_selected_snd_button configure -state $state
+ } {
+ $clear_selected_rec_button configure -state $state
+ }
+ }
+
+ ## Clear selected data in send hexeditor
+ # @return void
+ public method clear_selected_snd {} {
+ # Get range of text indexes determinating the selection
+ set rangeofselection [$send_hexeditor getRangeOfSelection]
+ if {$rangeofselection == {}} {
+ return
+ }
+
+ # Determinate index of the start and end cell
+ set start_cell [lindex $rangeofselection 0]
+ set end_cell [lindex $rangeofselection 1]
+
+ # Clear all selected cell one by one
+ for {set i $start_cell} {$i <= $end_cell} {incr i} {
+ $send_hexeditor setValue $i {}
+ }
+ }
+
+ ## Send selected data over RS232 interface
+ # @return void
+ public method send_selected {} {
+ # Get range of text indexes determinating the selection
+ set rangeofselection [$send_hexeditor getRangeOfSelection]
+ if {$rangeofselection == {}} {
+ return
+ }
+
+ # Abort if there was no channel opened
+ if {$channel == {}} {
+ tk_messageBox \
+ -parent $win \
+ -title [mc "IO Error"] \
+ -type ok -icon warning \
+ -message [mc "No port opened."]
+ return
+ }
+
+ # Generate binary data from the selected hexadecimal string
+ set data {}
+ set start_cell [lindex $rangeofselection 0]
+ set end_cell [lindex $rangeofselection 1]
+ foreach value [$send_hexeditor get_values $start_cell $end_cell] {
+ if {$value == {}} {
+ continue
+ }
+ append data [format %c $value]
+ }
+
+ # Send the generated binary data
+ if {[catch {
+ puts -nonewline $channel $data
+ flush $channel
+ } reason]} {
+ tk_messageBox \
+ -parent $win \
+ -title [mc "IO Error"] \
+ -type ok -icon warning \
+ -message [mc "Unable to send the data\n\n%s" $reason]
+ }
+ }
+
+ ## Change reception adddress to address of the current cell
+ # @return void
+ public method receive_here {} {
+ set cell [$receive_hexeditor getCurrentCell]
+ set reception_address $cell
+
+ $receive_hexeditor clearBgHighlighting 0
+ $receive_hexeditor set_bg_hg $cell 1 0
+ }
+
+ ## Receive data from the channel
+ # This function is trigered automatically by fileevent facitily
+ # @return void
+ public method receive_data {} {
+ # Read binary data
+ set data [read $channel]
+
+ # Discard the data if reception is not enabled
+ if {!$reception_enabled} {
+ return
+ }
+
+ # Check if the data has non zero length
+ if {![string length $data]} {
+ unknown_port_io_error
+ return
+ }
+
+ # Load the data into hexadecimal editor
+ set len [string bytelength $data]
+ $receive_hexeditor clearBgHighlighting 1
+ for {set i 0} {$i < $len} {incr i} {
+ if {$reception_address >= 256} {
+ receive_buffer_overflow_warning_dialog
+ break
+ }
+
+ scan [string index $data $i] %c byte
+ $receive_hexeditor setValue $reception_address $byte
+
+ incr reception_address
+ }
+ $receive_hexeditor set_bg_hg [expr {$reception_address - 1}] 1 1
+ $receive_hexeditor seeCell [expr {$reception_address - 1}]
+ }
+
+ ## Diaply dialog "Not enough space in the receive buffer !"
+ # @return void
+ private method receive_buffer_overflow_warning_dialog {} {
+ if {[winfo exists .data_lost_dialog]} {
+ return
+ }
+ set dialog [toplevel .data_lost_dialog -class [mc "Error message"] -bg {#EEEEEE}]
+
+ pack [label $dialog.label \
+ -font $bold_font -compound left -padx 5 \
+ -text [mc "Not enough space in the receive buffer !"] \
+ -image ::ICONS::22::stop \
+ ] -fill x -pady 5 -padx 5
+
+ pack [frame $dialog.frm] -pady 5
+ pack [ttk::button $dialog.frm.ok_button \
+ -text [mc "Ok"] \
+ -command "
+ grab release $dialog
+ destroy $dialog
+ " \
+ ] -side left
+
+ pack [ttk::separator $dialog.sep -orient horizontal] -fill x -pady 10
+ pack [checkbutton $dialog.enable_reception_chb \
+ -text [mc "Keep reception enabled"] -onvalue 1 -offvalue 0 \
+ -command "$this reception_ena_dis" \
+ -variable "::RS232Debugger::enable_reception${obj_idx}" \
+ ] -anchor w
+
+ # Set window attributes
+ wm iconphoto $dialog ::ICONS::16::status_unknown
+ wm title $dialog [mc "Data lost"]
+ wm resizable $dialog 0 0
+ wm transient $dialog $win
+ catch {grab $dialog}
+ wm protocol $dialog WM_DELETE_WINDOW "
+ grab release $dialog
+ destroy $dialog
+ "
+ raise $dialog
+ focus -force $dialog.frm.ok_button
+ tkwait window $dialog
+ }
+
+ ## Clear selected data in receive hexeditor
+ # @return void
+ public method clear_selected_rec {} {
+ set rangeofselection [$receive_hexeditor getRangeOfSelection]
+ if {$rangeofselection == {}} {
+ return
+ }
+
+ set start_cell [lindex $rangeofselection 0]
+ set end_cell [lindex $rangeofselection 1]
+
+ for {set i $start_cell} {$i <= $end_cell} {incr i} {
+ $receive_hexeditor setValue $i {}
+ }
+ }
+
+ ## Enable/Disable reception
+ # @return void
+ public method reception_ena_dis {} {
+ set reception_enabled [subst "\$::RS232Debugger::enable_reception${obj_idx}"]
+ }
+
+ ## Read TTY status from the interface and update GUI accordingly
+ # @return void
+ public method pool_ttystatus {} {
+ # Setup the pool timer
+ set pool_timer [after $POOL_INTERVAL "catch {$this pool_ttystatus}"]
+
+ # Read TTY status
+ if {[catch {
+ set ttystatus [fconfigure $channel -ttystatus]
+ }]} {
+ unknown_port_io_error
+ return
+ }
+
+ # Check whether any change occured
+ if {$prev_tty_status(0) == $ttystatus} {
+ return
+ } {
+ set prev_tty_status(0) $ttystatus
+ }
+
+ # Transform values read to these four variables:
+ set cts {}
+ set dsr {}
+ set ri {}
+ set dcd {}
+ set ts_len [llength $ttystatus]
+ for {set i 0; set j 1} {$i < $ts_len} {incr i 2; incr j 2} {
+ set key [lindex $ttystatus $i]
+ set val [lindex $ttystatus $j]
+
+ switch -- $key {
+ {CTS} {set cts $val}
+ {DSR} {set dsr $val}
+ {RING} {set ri $val}
+ {DCD} {set dcd $val}
+ }
+ }
+
+ # Update GUI accordingly
+ show_new_ttystatus $cts $dsr $ri $dcd
+ }
+
+ ## Show new TTY status in the GUI
+ # @parm Bool cts - CTS line state
+ # @parm Bool dsr - DSR line state
+ # @parm Bool ri - RI line state
+ # @parm Bool dcd - DCD line state
+ # @return void
+ private method show_new_ttystatus args {
+ foreach signal {cts dsr ri dcd} value $args {
+ if {$prev_tty_status($signal) == $value} {
+ continue
+ } {
+ set prev_tty_status($signal) $value
+ }
+
+ switch -- $value {
+ 0 {
+ set color {#FF0000}
+ set image ledred
+ }
+ 1 {
+ set color {#00FF00}
+ set image ledgreen
+ }
+ default {
+ set color {#888888}
+ set image ledgray
+ }
+ }
+
+ $connector_canvas itemconfigure ${signal}_wire -fill $color
+ $leds($signal) configure -image ::ICONS::16::$image
+ }
+ }
+
+ ## Report an unknown IO error occured on the interface
+ # Plus disable reception and safely terminate connection
+ # @return void
+ private method unknown_port_io_error {} {
+ # Disable reception
+ set reception_enabled 0
+ set ::RS232Debugger::enable_reception${obj_idx} 0
+
+ # Safely terminate connection
+ safely_terminate_connection
+ $port_combobox configure -style RS232Debugger_FileFound.TCombobox
+
+ # Display the error message
+ tk_messageBox \
+ -parent $win \
+ -title [mc "IO Error"] \
+ -type ok -icon warning \
+ -message [mc "There is something wrong with the port. Closing connection and disabling reception on this channel !"]
+
+ update
+ }
+
+ ## Safely terminate connection to the HW interface
+ # @return void
+ public method safely_terminate_connection {} {
+ catch {fileevent $channel readable {}}
+ catch {
+ after cancel $pool_timer
+ }
+ set prev_tty_status(0) {}
+ set channel {}
+ set port_filename {}
+
+ show_new_ttystatus {} {} {} {}
+ set_tty_controls_state 0
+ $port_combobox configure -style RS232Debugger_FileFound.TCombobox
+ }
+
+ ## Enable or disable TTY controls
+ # @parm Bool enabled - 1 == Enable; 0 == Disable
+ # @return void
+ private method set_tty_controls_state {enabled} {
+ if {$enabled} {
+ set state {normal}
+ set state2 {readonly}
+ set_tty_controls_to_defaults
+ } {
+ set state {disabled}
+ set state2 {disabled}
+ set_tty_controls_to_unknown_state
+ }
+
+ $dtr_button configure -state $state
+ $rts_button configure -state $state
+ $break_button configure -state $state
+
+ $enable_reception_chb configure -state $state
+ $close_connection_button configure -state $state
+
+ $baud_cb configure -state $state2
+ $parity_cb configure -state $state2
+ $data_cb configure -state $state2
+ $stop_cb configure -state $state2
+ }
+
+ ## Set tty controls to defaults
+ # @return void
+ private method set_tty_controls_to_defaults {} {
+ set_new_tty_status dtr 0
+ set_new_tty_status rts 0
+ set_new_tty_status break 0
+ }
+
+ ## Set tty controls to unknown state
+ # @return void
+ private method set_tty_controls_to_unknown_state {} {
+ set_new_tty_status dtr {}
+ set_new_tty_status rts {}
+ set_new_tty_status break {}
+ }
+
+ ## Invert tty status bit
+ # @parm String wire - Bit/Wire ID
+ # @return void
+ public method invert_tty_status_bit {wire} {
+ if {$prev_tty_status($wire) == {}} {
+ return
+ }
+
+ set_new_tty_status $wire [expr {!$prev_tty_status($wire)}]
+ }
+
+ ## Change color of the specified color
+ # @parm String wire - Wire ID
+ # @parm String value - New value (e.g. 0 or {})
+ # @return void
+ private method set_new_tty_status {wire value} {
+ set prev_tty_status($wire) $value
+
+ switch -- $value {
+ 0 { ;# Loical 0
+ if {$wire == {break}} {
+ [subst "\${${wire}_button}"] configure -text {Break} \
+ -style RS232Debugger_SignalTxDFalse.TButton
+ $connector_canvas itemconfigure txd_wire -fill {#0000FF}
+ } {
+ [subst "\${${wire}_button}"] configure -text {1} \
+ -style RS232Debugger_SignalNormalFalse.TButton
+ $connector_canvas itemconfigure ${wire}_wire -fill {#FF0000}
+ }
+ }
+ 1 { ;# Logical 1
+ if {$wire == {break}} {
+ [subst "\${${wire}_button}"] configure -text {BREAK} \
+ -style RS232Debugger_SignalTxDTrue.TButton
+ $connector_canvas itemconfigure txd_wire -fill {#00FF00}
+ } {
+ [subst "\${${wire}_button}"] configure -text {0} \
+ -style RS232Debugger_SignalNormalTrue.TButton
+ $connector_canvas itemconfigure ${wire}_wire -fill {#00FF00}
+ }
+ }
+ default { ;# Unknown state
+ if {$wire == {break}} {
+ [subst "\${${wire}_button}"] configure -text {Break} \
+ -style RS232Debugger_SignalAllDefault.TButton
+ $connector_canvas itemconfigure txd_wire -fill {#0000FF}
+ } {
+ [subst "\${${wire}_button}"] configure -text {-} \
+ -style RS232Debugger_SignalAllDefault.TButton
+ $connector_canvas itemconfigure ${wire}_wire -fill {#888888}
+ }
+ return
+ }
+ }
+
+ if {[catch {
+ fconfigure $channel -ttycontrol [list $wire $value]
+ }]} {
+ unknown_port_io_error
+ return
+ }
+ }
+
+ ## Handle "<Enter>" event on wire
+ # @parm String wire - Wire ID
+ # @return void
+ public method wire_enter {wire} {
+ $connector_canvas itemconfigure ${wire}_wire -width 2
+ $connector_canvas itemconfigure ${wire}_pin -fill {#000000}
+ $connector_canvas itemconfigure ${wire}_num -font $tiny_font_bold
+
+ set text {}
+ switch -- $wire {
+ {gnd} {set text [mc "RS232 pin: GND -- Common ground"]}
+ {dcd} {set text [mc "RS232 pin: DCD -- Carrier Detect"]}
+ {dsr} {set text [mc "RS232 pin: DSR -- Data Set Ready"]}
+ {cts} {set text [mc "RS232 pin: CTS -- Clear To Send"]}
+ {ri} {set text [mc "RS232 pin: RI -- Ring Indicator"]}
+ {dtr} {set text [mc "RS232 pin: DTR -- Data Terminal Ready"]}
+ {rts} {set text [mc "RS232 pin: RTS -- Request To Send"]}
+ {txd} {set text [mc "RS232 pin: TxD -- Transmitted Data"]}
+ {rxd} {set text [mc "RS232 pin: RxD -- Received Data"]}
+ }
+ $status_bar_label configure -text $text
+ }
+
+ ## Handle "<Leave>" event on wire
+ # @parm String wire - Wire ID
+ # @return void
+ public method wire_leave {wire} {
+ $connector_canvas itemconfigure ${wire}_wire -width 1
+ $connector_canvas itemconfigure ${wire}_pin -fill {#EEEEEE}
+ $connector_canvas itemconfigure ${wire}_num -font $tiny_font
+
+ $status_bar_label configure -text {}
+ }
+}
diff --git a/lib/utilities/speccalc.tcl b/lib/utilities/speccalc.tcl
new file mode 100755
index 0000000..67a9430
--- /dev/null
+++ b/lib/utilities/speccalc.tcl
@@ -0,0 +1,2390 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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 PARTMCULAR 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. #
+############################################################################
+
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Special calculator for computaions related to 8051 microcontroller
+# Functions:
+# * Timers preset (0, 1, 2)
+# * SPI
+# * Wait loops (code generation)
+# --------------------------------------------------------------------------
+
+class SpecCalc {
+ ## COMMON
+ common count 0 ;# Int: Counter of class instances
+ common diagram_counter 0 ;# Int: Counter of diagram dialogs instances
+ # List of pages descriptors for PagesManager
+ common page_list {
+ loops timer01 timer2 spi
+ }
+ # Configuration list
+ common config $::CONFIG(SPEC_CALC)
+
+ ## PRIVATE
+ private variable win ;# Widget: The dialog window
+ private variable obj_idx ;# Int: Object index
+ private variable pages_manager ;# Widget: PagesManager
+ private variable pages ;# Array of Widget: Pages in the PagesManager
+ private variable buttons ;# Array of Widget: Buttons to switch between pages
+ private variable widgets ;# Array of Widget: Widgets present in separate pages
+ private variable page_created ;# Array of Bool: Page GUI created
+
+ private variable status_bar ;# Widget: Left status bar (main)
+ private variable status_bar2 ;# Widget: Right status bar (complementary)
+
+ private variable calc_in_progress 0 ;# Bool: Calculation in progress
+
+ private variable active_page ;# String: ID of currently active page
+
+ ## Object constructor
+ constructor {} {
+ incr count
+ set obj_idx $count
+
+ # Configure ttk styles
+ ttk::style configure SpecCalc_RedBg.TCombobox -fieldbackground {#FFCCCC}
+
+ ttk::style configure SpecCalc_Flat.TButton -background {#FFFFFF} -padding 0 -borderwidth 1 -relief flat
+ ttk::style map SpecCalc_Flat.TButton -relief [list active raised] -background [list disabled {#EEEEEE} active {#EEEEFF}]
+
+ ttk::style configure SpecCalc_Spec.TButton -background {#CCCCFF} -padding 0
+ ttk::style map SpecCalc_Spec.TButton -background [list disabled {#EEEEEE} active {#DDDDFF}]
+
+ create_gui
+ }
+
+ ## Object destructor
+ destructor {
+ # Hide dialog window
+ wm withdraw $win
+ update
+
+ # Create configuration list
+ set config [list \
+ [list [$widgets(loops,time_ent) get] \
+ [$widgets(loops,time_cb) current] \
+ [$widgets(loops,clock_cb) get] \
+ [$widgets(loops,clock_type_cb) current] \
+ [$widgets(loops,reg_ent0) get] \
+ [$widgets(loops,reg_ent1) get] \
+ [$widgets(loops,reg_ent2) get] \
+ [$widgets(loops,reg_ent3) get] \
+ [$widgets(loops,reg_ent4) get] \
+ [$widgets(loops,reg_ent5) get] \
+ [$widgets(loops,reg_ent6) get] \
+ [$widgets(loops,reg_ent7) get] \
+ ] [list \
+ [$widgets(timer01,time_ent) get] \
+ [$widgets(timer01,time_cb) current] \
+ [$widgets(timer01,clock_cb) get] \
+ [$widgets(timer01,clock_type_cb) current] \
+ [$widgets(timer01,mode_cb) current] \
+ [$widgets(timer01,psc_cb) current] \
+ [subst "\${::SpecCalc::spec_chb_$obj_idx}"] \
+ ] [list \
+ [$widgets(timer2,time_ent) get] \
+ [$widgets(timer2,time_cb) current] \
+ [$widgets(timer2,clock_cb) get] \
+ [$widgets(timer2,clock_type_cb) current] \
+ [$widgets(timer2,mode_cb) current] \
+
+ ] [list \
+ [subst "\$::SpecCalc::timer2_clk_fosc_$obj_idx"]\
+ [subst "\$::SpecCalc::timer2_clk_freq_$obj_idx"]\
+ [subst "\$::SpecCalc::timer2_clk_x2_$obj_idx"] \
+ ] [list \
+ [wm geometry $win] \
+ $active_page \
+ ] [list \
+ [subst "\${::SpecCalc::double_chb_$obj_idx}"] \
+ [$widgets(spi,sck_ent00) get] \
+ ]
+ ]
+
+ # Destroy dialog window
+ destroy $win
+ }
+
+ ## Set status bar tip for certain widget
+ # @parm Widget widget - Some button or label ...
+ # @parm String text - Status tip
+ # @return void
+ private method set_status_tip {widget text} {
+ bind $widget <Enter> "$status_bar configure -fg black -text {$text}"
+ bind $widget <Leave> "$status_bar configure -text {}"
+ }
+
+ ## Show certain text on the right status bar for 10 seconds
+ # @parm String text - Text to display
+ # @return void
+ public method status_tip {text} {
+ $status_bar2 configure -text $text -fg red
+ after 10000 "catch {$status_bar2 configure -text {} -fg black}"
+ }
+
+ ## Create dialog GUI
+ # @return void
+ private method create_gui {} {
+ # Create dialog window and the main frame
+ set win [toplevel .spec_calc$count -class [mc "Special Calculator - MCU 8051 IDE"] -bg {#EEEEEE}]
+ set main_frame [frame $win.main_frame]
+
+ # Create status bar
+ set sbar_frame [frame $win.sbar_frame]
+ set status_bar [label $sbar_frame.status_bar \
+ -justify left -anchor w -padx 5 \
+ ]
+ # Create status bar
+ set status_bar2 [label $sbar_frame.status_bar2 \
+ -justify right -anchor w -padx 5 \
+ ]
+
+ # Create left frame
+ set left_frame [frame $main_frame.left_frame -bg white]
+ create_left_frame $left_frame
+ pack $left_frame -side left -fill y
+
+ # Create separator between left and right frame
+ pack [ttk::separator $main_frame.sep \
+ -orient vertical \
+ ] -side left -fill y
+
+ # Create right frame
+ set right_frame [frame $main_frame.right_frame]
+ create_right_frame $right_frame
+ pack $right_frame -side left -fill both -expand 1
+
+ # Pack status bar on the bottom
+ pack $sbar_frame -side bottom -fill x -anchor nw
+ pack $status_bar2 -side right -anchor ne
+ pack $status_bar -side left -fill x -anchor nw
+
+ # Pack the main frame
+ pack $main_frame -fill both -expand 1
+
+ wm title $win [mc "Special Calculator - MCU 8051 IDE"]
+ wm iconphoto $win ::ICONS::16::_blockdevice
+ wm minsize $win 400 350
+ wm protocol $win WM_DELETE_WINDOW "delete object $this"
+
+ if {[llength $config]} {
+ wm geometry $win [lindex $config {4 0}]
+ switch_page [lindex $config {4 1}]
+ } {
+ wm geometry $win 400x350
+ switch_page loops
+ }
+
+ # Create all pages when system "calms down"
+ after idle "catch {
+ foreach page {$page_list} {
+ update
+ $this create_page \$page
+ }
+ }"
+ }
+
+ ## Create left part of the GUI
+ # @parm Widget target_frame - Frame widget in which the GUI should be created
+ # @return void
+ private method create_left_frame {target_frame} {
+ foreach name {
+ {Loops} {Timer 0/1} {Timer 2} {SPI}
+ } icon {
+ fsview history history2 _kcmdf
+ } stip {
+ {}
+ {Calculate timer preset}
+ {Calculate timer preset}
+ {}
+ } page $page_list \
+ {
+ set buttons($page) [ttk::button $target_frame.${page}_button \
+ -image ::ICONS::22::$icon \
+ -text [mc $name] -compound top \
+ -command "$this switch_page $page" \
+ -style Flat.TButton \
+ ]
+ pack $buttons($page) -anchor n
+ set_status_tip $buttons($page) [mc $stip]
+ }
+ }
+
+ ## Create right part of the GUI
+ # @parm Widget target_frame - Frame widget in which the GUI should be created
+ # @return void
+ private method create_right_frame {target_frame} {
+ set pages_manager [PagesManager $target_frame.pages_manager -background {#eeeeee}]
+ pack $pages_manager -fill both -expand 1
+
+ foreach page $page_list {
+ set pages($page) [$pages_manager add $page]
+ set page_created($page) 0
+ }
+ }
+
+ ## Switch active page
+ # @parm String page - Page ID
+ # @return void
+ public method switch_page {page} {
+ if {!$page_created($page)} {
+ create_page $page
+ }
+ $pages_manager raise $page
+ foreach p $page_list {
+ $buttons($p) configure -style SpecCalc_Flat.TButton
+ }
+ $buttons($page) configure -style SpecCalc_Spec.TButton
+
+ set active_page $page
+ }
+
+ ## Create page for computing wait loops
+ # @return void
+ private method create_page_loops {} {
+ # Create frames
+ set page {loops}
+ set top_frame [frame $pages($page).top_frame]
+ set regs_frame [frame $pages($page).regs_frame]
+ set bottom_frame [frame $pages($page).bottom_frame]
+
+ # - Time
+ grid [label $top_frame.time_lbl \
+ -text [mc "Time"] \
+ ] -row 0 -column 0 -sticky w
+ set widgets(loops,time_ent) [ttk::entry $top_frame.time_ent \
+ -validatecommand "$this calc loops time_ent %P" \
+ -validate key \
+ -width 9 \
+ ]
+ grid $widgets(loops,time_ent) -row 0 -column 1 -sticky we
+ set widgets(loops,time_cb) [ttk::combobox $top_frame.time_cb \
+ -values {ns us ms s} \
+ -state readonly \
+ -width 7 \
+ ]
+ bind $widgets(loops,time_cb) <<ComboboxSelected>> \
+ "$this calc loops time_cb \[$top_frame.time_cb get\]"
+ grid $widgets(loops,time_cb) -row 0 -column 2 -sticky w
+ set_status_tip $widgets(loops,time_cb) [mc "Time unit"]
+
+ # - Clock
+ grid [label $top_frame.clock_lbl \
+ -text [mc "Clock \[kHz\]"] \
+ ] -row 1 -column 0 -sticky w
+ set widgets(loops,clock_cb) [ttk::combobox $top_frame.clock_cb \
+ -validate key \
+ -width 9 \
+ -validatecommand "$this calc loops clock_cb %P" \
+ -values {
+ 6000.0 11059.2 12000.0 14745.6
+ 16000.0 20000.0 24000.0 33000.0
+ } \
+ ]
+ set_status_tip $widgets(loops,clock_cb) [mc "MCU clock"]
+ grid $widgets(loops,clock_cb) -row 1 -column 1 -sticky we
+ set widgets(loops,clock_type_cb) [ttk::combobox \
+ $top_frame.clock_type_cb \
+ -values {{12 / MC} {6 / MC} {1 / MC}} \
+ -width 7 \
+ -state readonly \
+ ]
+ bind $widgets(loops,clock_type_cb) <<ComboboxSelected>> \
+ "$this calc loops clock_type_cb \[$top_frame.clock_type_cb get\]"
+ DynamicHelp::add $widgets(loops,clock_type_cb) \
+ -text [mc "Clock cycles per machine cycle\n 12 - Common 8051\n 6 - Core 51X2\n 1 - Single cycle core"]
+ set_status_tip $widgets(loops,clock_type_cb) [mc "Clock cycles per machine cycle"]
+ grid $widgets(loops,clock_type_cb) -row 1 -column 2 -sticky w
+
+ # - Registers to use
+ grid [label $regs_frame.regs_lbl \
+ -text [mc "Registers to use"] \
+ ] -row 0 -column 0 -columnspan 8 -sticky w
+ set i 0
+ foreach r {1 2} {
+ foreach c {0 2 4 6} {
+ grid [label $regs_frame.reg_lbl$i \
+ -text " $i:" \
+ ] -row $r -column $c -sticky e
+ incr c
+
+ set widgets(loops,reg_ent$i) [ttk::entry $regs_frame.reg_ent$i \
+ -validatecommand "$this calc loops reg_ent$i %P" \
+ -validate key \
+ -width 1 \
+ ]
+ grid $widgets(loops,reg_ent$i) -row $r -column $c -sticky we
+ grid columnconfigure $regs_frame $c -weight 1
+
+ incr i
+ }
+ }
+
+ # - Source code
+ set bottom_frame_t [frame $bottom_frame.top]
+ set bottom_frame_b [frame $bottom_frame.bottom]
+ pack [label $bottom_frame_t.label \
+ -text [mc "Source code:"] \
+ ] -side left
+ set widgets(loops,compute_but) [ttk::button $bottom_frame_t.comp_but \
+ -text [mc "Evaluate"] \
+ -compound left \
+ -image ::ICONS::16::exec \
+ -command "$this calc loops compute_but {}" \
+ ]
+ pack $widgets(loops,compute_but) -side right
+ set widgets(loops,copy_but) [ttk::button $bottom_frame_t.copy_but \
+ -text [mc "Copy"] \
+ -compound left \
+ -state disabled \
+ -image ::ICONS::16::editcopy \
+ -command "$this calc loops copy_but {}" \
+ ]
+ pack $widgets(loops,copy_but) -side right
+ set widgets(loops,results) [text $bottom_frame_b.text \
+ -state disabled -width 0 -height 0 -bg white \
+ -yscrollcommand "$bottom_frame_b.scrollbar set" \
+ -takefocus 1 -font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -14 \
+ ] \
+ ]
+ ASMsyntaxHighlight::create_tags $widgets(loops,results) 14 $::DEFAULT_FIXED_FONT
+ bind $widgets(loops,results) <Button-1> "focus %W"
+ pack $widgets(loops,results) -fill both -expand 1 -side left
+ pack [ttk::scrollbar $bottom_frame_b.scrollbar \
+ -orient vertical \
+ -command "$widgets(loops,results) yview" \
+ ] -fill y -side right -after $widgets(loops,results)
+
+ pack $bottom_frame_t -fill x
+ pack $bottom_frame_b -fill both -expand 1
+
+ # Configure bindings
+ foreach w {time_ent time_cb clock_cb clock_type_cb compute_but} {
+ bind $widgets(loops,$w) <Return> "$this calc loops compute_but {}"
+ bind $widgets(loops,$w) <KP_Enter> "$this calc loops compute_but {}"
+ }
+ for {set i 0} {$i < 8} {incr i} {
+ bind $widgets(loops,reg_ent$i) <Return> "$this calc loops compute_but {}"
+ bind $widgets(loops,reg_ent$i) <KP_Enter> "$this calc loops compute_but {}"
+ }
+
+
+ # Create page header
+ pack [label $pages($page).header \
+ -text [mc "Create a wait loop"] \
+ -font [font create \
+ -family {helvetica} \
+ -size -17 \
+ -weight bold \
+ ] \
+ ] -pady 5
+ pack $top_frame -anchor nw
+ pack $regs_frame -anchor nw -fill x
+ pack [ttk::separator $pages($page).sep \
+ -orient horizontal \
+ ] -fill x -pady 5
+ pack $bottom_frame -anchor nw -fill both -expand 1
+
+ # Insert values from the last session
+ if {[llength $config]} {
+ $widgets(loops,time_ent) insert 0 [lindex $config {0 0}]
+ $widgets(loops,time_cb) current [lindex $config {0 1}]
+ $widgets(loops,clock_cb) delete 0 end
+ $widgets(loops,clock_cb) insert 0 [lindex $config {0 2}]
+ $widgets(loops,clock_type_cb) current [lindex $config {0 3}]
+
+ for {set i 0; set k 4} {$i < 8} {incr i; incr k} {
+ $widgets(loops,reg_ent$i) insert 0 [lindex $config [list 0 $k]]
+ }
+
+ } {
+ $widgets(loops,time_cb) current 1
+ $widgets(loops,clock_cb) current 2
+ $widgets(loops,clock_type_cb) current 0
+
+ for {set i 0} {$i < 8} {incr i} {
+ $widgets(loops,reg_ent$i) insert 0 "R$i"
+ }
+ }
+ }
+
+ ## Create page for computing timer 0/1 preset values
+ # @return void
+ private method create_page_timer01 {} {
+ # Create page frames
+ set page {timer01}
+ set top_frame [frame $pages($page).top_frame]
+ set bottom_frame [frame $pages($page).bottom_frame]
+
+ # - Time
+ grid [label $top_frame.time_lbl \
+ -text [mc "Time"] \
+ ] -row 0 -column 0 -sticky w
+ set widgets(timer01,time_ent) [ttk::entry $top_frame.time_ent \
+ -validatecommand "$this calc timer01 time_ent %P" \
+ -validate key \
+ -width 9 \
+ ]
+ grid $widgets(timer01,time_ent) -row 0 -column 1 -sticky we
+ set widgets(timer01,time_cb) [ttk::combobox $top_frame.time_cb \
+ -values {ns us ms s} \
+ -state readonly \
+ -width 7 \
+ ]
+ bind $widgets(timer01,time_cb) <<ComboboxSelected>> \
+ "$this calc timer01 time_cb \[$top_frame.time_cb get\]"
+ grid $widgets(timer01,time_cb) -row 0 -column 2 -sticky w
+ set_status_tip $widgets(timer01,time_cb) [mc "Time unit"]
+
+ # - Clock
+ grid [label $top_frame.clock_lbl \
+ -text [mc "Clock \[kHz\]"] \
+ ] -row 1 -column 0 -sticky w
+ set widgets(timer01,clock_cb) [ttk::combobox $top_frame.clock_cb\
+ -validate key \
+ -width 9 \
+ -validatecommand "$this calc timer01 clock_cb %P" \
+ -values {
+ 6000.0 11059.2 12000.0 14745.6
+ 16000.0 20000.0 24000.0 33000.0
+ } \
+ ]
+ set_status_tip $widgets(timer01,clock_cb) [mc "MCU clock"]
+ grid $widgets(timer01,clock_cb) -row 1 -column 1 -sticky we
+ set widgets(timer01,clock_type_cb) [ttk::combobox \
+ $top_frame.clock_type_cb \
+ -values {{12 / MC} {6 / MC} {1 / MC}} \
+ -width 7 \
+ -state readonly \
+ ]
+ bind $widgets(timer01,clock_type_cb) <<ComboboxSelected>> \
+ "$this calc timer01 clock_type_cb \[$top_frame.clock_type_cb get\]"
+ DynamicHelp::add $widgets(timer01,clock_type_cb) \
+ -text [mc "Clock cycles per machine cycle\n 12 - Common 8051\n 6 - Core 51X2\n 1 - Single cycle core"]
+ set_status_tip $widgets(timer01,clock_type_cb) [mc "Clock cycles per machine cycle"]
+ grid $widgets(timer01,clock_type_cb) -row 1 -column 2 -sticky w
+
+ # - Mode
+ grid [label $top_frame.mode_lbl \
+ -text [mc "Mode"] \
+ ] -row 2 -column 0 -sticky w
+ set widgets(timer01,mode_cb) [ttk::combobox $top_frame.mode_cb \
+ -width 18 \
+ -state readonly \
+ -values {
+ {0 - 13 bit}
+ {1 - 16 bit}
+ {2 - 8 bit auto r.}
+ } \
+ ]
+ bind $widgets(timer01,mode_cb) <<ComboboxSelected>> \
+ "$this calc timer01 mode_cb \[$top_frame.mode_cb get\]"
+ set_status_tip $widgets(timer01,mode_cb) [mc "Timer mode"]
+ grid $widgets(timer01,mode_cb) -row 2 -column 1 -sticky we -columnspan 2
+ grid [ttk::button $top_frame.show_diagram_button \
+ -image ::ICONS::16::info \
+ -style Flat.TButton \
+ -command "$this show_diagram timer01 {}" \
+ ] -row 2 -column 3 -sticky w
+ set_status_tip $top_frame.show_diagram_button [mc "Show functional block diagram"]
+
+ # - Enhanced timer/counter
+ set widgets(timer01,spec_chb) [checkbutton $top_frame.spec_chb \
+ -text [mc "Enhanced timer/counter"] -onvalue 1 -offvalue 0 \
+ -variable ::SpecCalc::spec_chb_$obj_idx \
+ -command "$this calc timer01 spec_chb \${::SpecCalc::spec_chb_$obj_idx}" \
+ ]
+ set_status_tip $widgets(timer01,spec_chb) [mc "Calculate for enhanced timers"]
+ grid $widgets(timer01,spec_chb) -row 3 -column 0 -sticky w -columnspan 3
+
+ # - PSC
+ set widgets(timer01,psc_lbl) [ \
+ label $top_frame.psc_lbl \
+ -text "PSC" \
+ ]
+ set widgets(timer01,psc_cb) [ttk::combobox $top_frame.psc_cb \
+ -values {0 1 2 3 4 5 6 7} \
+ -width 1 \
+ ]
+ bind $widgets(timer01,psc_cb) <<ComboboxSelected>> \
+ "$this calc timer01 psc_cb \[$top_frame.psc_cb get\]"
+ set_status_tip $widgets(timer01,psc_cb) [mc "The number of active bits in TL1 minus 1"]
+
+ ## Results ...
+ # Labels
+ grid [label $bottom_frame.res_lbl \
+ -text [mc "Results:"] \
+ ] -row 0 -column 0 -columnspan 3 -sticky w
+ grid [label $bottom_frame.th_l_lbl \
+ -text [mc "TH"] \
+ ] -row 1 -column 1 -sticky e
+ grid [label $bottom_frame.tl_l_lbl \
+ -text [mc "TL"] \
+ ] -row 2 -column 1 -sticky e
+ set widgets(timer01,rh_l) [label $bottom_frame.rh_l_lbl \
+ -text [mc "RH"] \
+ ]
+ set widgets(timer01,rl_l) [label $bottom_frame.rl_l_lbl \
+ -text [mc "RL"] \
+ ]
+ grid [label $bottom_frame.rep_l_lbl \
+ -text [mc "Repeats"] \
+ ] -row 5 -column 1 -sticky e
+ grid [label $bottom_frame.rest_l_lbl \
+ -text [mc "Rest"] \
+ ] -row 6 -column 1 -sticky e
+ # ":="
+ for {set i 1} {$i < 7} {incr i} {
+ set widgets(timer01,eq$i) \
+ [label $bottom_frame.equal_s_l$i -text ":="]
+ grid $widgets(timer01,eq$i) -row $i -column 2
+ }
+ grid forget $widgets(timer01,eq3)
+ grid forget $widgets(timer01,eq4)
+ ## Entryboxes with results themselfs
+ # - TH
+ set widgets(timer01,th) [ \
+ entry $bottom_frame.th_r_lbl -state readonly \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ -fg {#888888} -bg {#EEEEEE} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer01_th_$obj_idx \
+ ]
+ set ::SpecCalc::timer01_th_$obj_idx [mc "Do not change"]
+ grid $widgets(timer01,th) -row 1 -column 3 -sticky w
+ # - TL
+ set widgets(timer01,tl) [ \
+ entry $bottom_frame.tl_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer01_tl_$obj_idx \
+ ]
+ set ::SpecCalc::timer01_tl_$obj_idx [mc "Do not change"]
+ grid $widgets(timer01,tl) -row 2 -column 3 -sticky w
+ # - RH
+ set widgets(timer01,rh) [ \
+ entry $bottom_frame.rh_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer01_rh_$obj_idx \
+ ]
+ set ::SpecCalc::timer01_rh_$obj_idx [mc "Do not change"]
+ # - RL
+ set widgets(timer01,rl) [ \
+ entry $bottom_frame.rl_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer01_rl_$obj_idx \
+ ]
+ set ::SpecCalc::timer01_rl_$obj_idx [mc "Do not change"]
+ # - Repeats
+ set widgets(timer01,repeats) [ \
+ entry $bottom_frame.reps_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer01_repeats_$obj_idx\
+ ]
+ set ::SpecCalc::timer01_repeats_$obj_idx [mc "Zero"]
+ grid $widgets(timer01,repeats) -row 5 -column 3 -sticky w
+ # - Rest
+ set widgets(timer01,rest) [ \
+ entry $bottom_frame.rest_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer01_rest_$obj_idx \
+ ]
+ set ::SpecCalc::timer01_rest_$obj_idx [mc "none"]
+ grid $widgets(timer01,rest) -row 6 -column 3 -sticky w
+
+ # Configure grid layout
+ grid columnconfigure $bottom_frame 0 -minsize 15
+
+
+ # Create page header
+ pack [label $pages($page).header \
+ -text [mc "Calculate timer 0/1 preset"] \
+ -font [font create \
+ -family {helvetica} \
+ -size -17 \
+ -weight bold \
+ ] \
+ ] -pady 5
+ pack $top_frame -anchor nw
+ pack [ttk::separator $pages($page).sep \
+ -orient horizontal \
+ ] -fill x -pady 5
+ pack $bottom_frame -anchor nw -padx 10
+
+ # Restore values from the last session
+ set load_failure 1
+ catch {
+ if {[llength $config]} {
+ $widgets(timer01,time_ent) insert 0 [lindex $config {1 0}]
+ $widgets(timer01,time_cb) current [lindex $config {1 1}]
+ $widgets(timer01,clock_cb) delete 0 end
+ $widgets(timer01,clock_cb) insert 0 [lindex $config {1 2}]
+ $widgets(timer01,clock_type_cb) current [lindex $config {1 3}]
+ $widgets(timer01,mode_cb) current [lindex $config {1 4}]
+ $widgets(timer01,psc_cb) current [lindex $config {1 5}]
+ set ::SpecCalc::spec_chb_$obj_idx [lindex $config {1 6}]
+ if {[lindex $config {1 6}]} {
+ calc timer01 spec_chb 1
+ }
+ set load_failure 0
+ }
+ }
+ if {$load_failure} {
+ $widgets(timer01,time_cb) current 1
+ $widgets(timer01,clock_cb) current 2
+ $widgets(timer01,clock_type_cb) current 0
+ $widgets(timer01,mode_cb) current 1
+ $widgets(timer01,psc_cb) current 4
+ }
+ }
+
+ ## Create page for computing timer 2 preset values
+ # @return void
+ private method create_page_timer2 {} {
+ # Create notebook
+ set page {timer2}
+ set nb [NoteBook $pages($page).nb -side top -arcradius 4 -bg {#EEEEEE}]
+ # - Page "Preset"
+ set preset_frame [$nb insert end {Preset} \
+ -text [mc "Preset"] \
+ -image ::ICONS::16::player_time \
+ ]
+ # - Page "Clock"
+ set clock_out_frame [$nb insert end {Clock} \
+ -text [mc "Clock out"] \
+ -image ::ICONS::16::kcmpci \
+ ]
+
+
+ #
+ ## Create "Preset" page
+ #
+
+ # Create frames
+ set top_frame [frame $preset_frame.top_frame]
+ set bottom_frame [frame $preset_frame.bottom_frame]
+
+ # - Time
+ grid [label $top_frame.time_lbl \
+ -text [mc "Time"] \
+ ] -row 0 -column 0 -sticky w
+ set widgets(timer2,time_ent) [ttk::entry $top_frame.time_ent \
+ -validatecommand "$this calc timer2 time_ent %P" \
+ -validate key \
+ -width 9 \
+ ]
+ grid $widgets(timer2,time_ent) -row 0 -column 1 -sticky we
+ set widgets(timer2,time_cb) [ttk::combobox $top_frame.time_cb \
+ -values {ns us ms s} \
+ -state readonly \
+ -width 7 \
+ ]
+ bind $widgets(timer2,time_cb) <<ComboboxSelected>> \
+ "$this calc timer2 time_cb \[$top_frame.time_cb get\]"
+ grid $widgets(timer2,time_cb) -row 0 -column 2 -sticky w
+ set_status_tip $widgets(timer2,time_cb) [mc "Time unit"]
+
+ # - Clock
+ grid [label $top_frame.clock_lbl \
+ -text [mc "Clock \[kHz\]"] \
+ ] -row 1 -column 0 -sticky w
+ set widgets(timer2,clock_cb) [ttk::combobox $top_frame.clock_cb \
+ -validate key \
+ -width 9 \
+ -validatecommand "$this calc timer2 clock_cb %P" \
+ -values {
+ 6000.0 11059.2 12000.0 14745.6
+ 16000.0 20000.0 24000.0 33000.0
+ } \
+ ]
+ set_status_tip $widgets(timer2,clock_cb) [mc "MCU clock"]
+ grid $widgets(timer2,clock_cb) -row 1 -column 1 -sticky we
+ set widgets(timer2,clock_type_cb) [ttk::combobox \
+ $top_frame.clock_type_cb \
+ -values {{12 / MC} {6 / MC} {1 / MC}} \
+ -width 7 -state readonly \
+ -state readonly \
+ ]
+ bind $widgets(timer2,clock_type_cb) <<ComboboxSelected>> \
+ "$this calc timer2 clock_type_cb \[$top_frame.clock_type_cb get\]"
+ DynamicHelp::add $widgets(timer2,clock_type_cb) \
+ -text [mc "Clock cycles per machine cycle\n 12 - Common 8051\n 6 - Core 51X2\n 1 - Single cycle core"]
+ set_status_tip $widgets(timer2,clock_type_cb) [mc "Clock cycles per machine cycle"]
+ grid $widgets(timer2,clock_type_cb) -row 1 -column 2 -sticky w
+
+ # - Mode
+ grid [label $top_frame.mode_lbl \
+ -text [mc "Mode"] \
+ ] -row 2 -column 0 -sticky w
+ set widgets(timer2,mode_cb) [ttk::combobox $top_frame.mode_cb \
+ -state readonly \
+ -width 18 \
+ -values {
+ {UP counter (auto reload)}
+ {DOWN counter (auto reload)}
+ } \
+ ]
+ bind $widgets(timer2,mode_cb) <<ComboboxSelected>> \
+ "$this calc timer2 mode_cb \[$top_frame.mode_cb get\]"
+ set_status_tip $widgets(timer2,mode_cb) [mc "Timer mode"]
+ grid $widgets(timer2,mode_cb) -row 2 -column 1 -sticky we -columnspan 2
+ grid [ttk::button $top_frame.show_diagram_button \
+ -image ::ICONS::16::info \
+ -command "$this show_diagram timer2 0" \
+ -style Flat.TButton \
+ ] -row 2 -column 3 -sticky w
+ set_status_tip $top_frame.show_diagram_button [mc "Show functional block diagram"]
+
+ ## Results ...
+ # Labels
+ grid [label $bottom_frame.res_lbl \
+ -text [mc "Results:"] \
+ ] -row 0 -column 0 -columnspan 3 -sticky w
+ grid [label $bottom_frame.rcal2h_l_lbl \
+ -text [mc "RCAL2H"] \
+ ] -row 1 -column 1 -sticky e
+ grid [label $bottom_frame.rcal2l_l_lbl \
+ -text [mc "RCAL2L"] \
+ ] -row 2 -column 1 -sticky e
+ grid [label $bottom_frame.t2h_l_lbl \
+ -text [mc "T2H"] \
+ ] -row 3 -column 1 -sticky e
+ grid [label $bottom_frame.t2l_l_lbl \
+ -text [mc "T2L"] \
+ ] -row 4 -column 1 -sticky e
+ grid [label $bottom_frame.repeats_l_lbl \
+ -text [mc "Repeats"] \
+ ] -row 5 -column 1 -sticky e
+ grid [label $bottom_frame.rest_l_lbl \
+ -text [mc "Rest"] \
+ ] -row 6 -column 1 -sticky e
+ # ":="
+ for {set i 1} {$i < 7} {incr i} {
+ grid [label $bottom_frame.equal_s_l$i -text ":="] -row $i -column 2
+ }
+ ## Entryboxes with results themselfs
+ # - RCAL2H
+ set widgets(timer2,rcal2h) [
+ entry $bottom_frame.rcal2h_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer2_rcal2h_$obj_idx \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ ]
+ set ::SpecCalc::timer2_rcal2h_$obj_idx [mc "Do not change"]
+ grid $widgets(timer2,rcal2h) -row 1 -column 3 -sticky w
+ # - RCAL2L
+ set widgets(timer2,rcal2l) [
+ entry $bottom_frame.rcal2l_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer2_rcal2l_$obj_idx \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ ]
+ set ::SpecCalc::timer2_rcal2l_$obj_idx [mc "Do not change"]
+ grid $widgets(timer2,rcal2l) -row 2 -column 3 -sticky w
+ # - T2H
+ set widgets(timer2,t2h) [
+ entry $bottom_frame.t2h_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer2_t2h_$obj_idx \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ ]
+ set ::SpecCalc::timer2_t2h_$obj_idx [mc "Do not change"]
+ grid $widgets(timer2,t2h) -row 3 -column 3 -sticky w
+ # - T2L
+ set widgets(timer2,t2l) [
+ entry $bottom_frame.t2l_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -textvariable ::SpecCalc::timer2_t2l_$obj_idx \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ ]
+ set ::SpecCalc::timer2_t2l_$obj_idx [mc "Do not change"]
+ grid $widgets(timer2,t2l) -row 4 -column 3 -sticky w
+ # - Repeats
+ set widgets(timer2,repeats) [ \
+ entry $bottom_frame.repeats_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ -textvariable ::SpecCalc::timer2_repeats_$obj_idx \
+ ]
+ set ::SpecCalc::timer2_repeats_$obj_idx [mc "none"]
+ grid $widgets(timer2,repeats) -row 5 -column 3 -sticky w
+ # - Rest
+ set widgets(timer2,rest) [ \
+ entry $bottom_frame.rest_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} \
+ -relief flat -highlightthickness 0 -bd 0 \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ -textvariable ::SpecCalc::timer2_rest_$obj_idx \
+ ]
+ set ::SpecCalc::timer2_rest_$obj_idx [mc "none"]
+ grid $widgets(timer2,rest) -row 6 -column 3 -sticky w
+
+ # Configure grid layout
+ grid columnconfigure $bottom_frame 0 -minsize 15
+
+
+ # Create page header
+ pack [label $preset_frame.header \
+ -text [mc "Calculate timer 2 preset"] \
+ -font [font create \
+ -family {helvetica} \
+ -size -17 \
+ -weight bold \
+ ] \
+ ] -pady 5
+ pack $top_frame -pady 5 -anchor nw
+ pack [ttk::separator $preset_frame.sep \
+ -orient horizontal \
+ ] -fill x -pady 10
+ pack $bottom_frame -anchor nw -padx 10
+
+ # Restore values from the last session
+ if {[llength $config]} {
+ $widgets(timer2,time_ent) insert 0 [lindex $config {2 0}]
+ $widgets(timer2,time_cb) current [lindex $config {2 1}]
+ $widgets(timer2,clock_cb) delete 0 end
+ $widgets(timer2,clock_cb) insert 0 [lindex $config {1 2}]
+ $widgets(timer2,clock_type_cb) current [lindex $config {2 3}]
+ $widgets(timer2,mode_cb) current [lindex $config {2 4}]
+ } {
+ $widgets(timer2,time_cb) current 1
+ $widgets(timer2,clock_cb) current 2
+ $widgets(timer2,clock_type_cb) current 0
+ $widgets(timer2,mode_cb) current 0
+ }
+ set bottom_frame [frame $clock_out_frame.bottom_frame]
+
+
+ #
+ ## Create "Clock" page
+ #
+
+ # Labes ...
+ grid [label $bottom_frame.freq_l_lbl \
+ -text [mc "Frequency"] \
+ ] -row 1 -column 1 -sticky e
+ grid [label $bottom_frame.fosc_l_lbl \
+ -text [mc "F osc"] \
+ ] -row 2 -column 1 -sticky e
+ grid [label $bottom_frame.x2_l_lbl \
+ -text [mc "X2"] \
+ ] -row 3 -column 1 -sticky e
+ grid [label $bottom_frame.hex_lbl \
+ -text [mc "HEX"] -font $::smallfont \
+ ] -row 5 -column 2
+ grid [label $bottom_frame.dec_lbl \
+ -text [mc "DEC"] -font $::smallfont \
+ ] -row 5 -column 3
+ grid [label $bottom_frame.rcap2h_l_lbl \
+ -text [mc "RCAP2H"] \
+ ] -row 6 -column 1 -sticky e
+ grid [label $bottom_frame.rcap2l_l_lbl \
+ -text [mc "RCAP2L"] \
+ ] -row 7 -column 1 -sticky e
+ grid [label $bottom_frame.error_l_lbl \
+ -text [mc "Error"] \
+ ] -row 8 -column 1 -sticky e
+
+ # Separator
+ grid [ttk::separator $bottom_frame.sep \
+ -orient horizontal \
+ ] -row 4 -column 1 -sticky we -columnspan 3 -pady 5
+
+ ## EntryBoxes
+ # - Frequency
+ set widgets(timer2,clk_freq) [ttk::entry \
+ $bottom_frame.clk_freq_r_lbl \
+ -validate key \
+ -width 12 \
+ -textvariable ::SpecCalc::timer2_clk_freq_$obj_idx \
+ -validatecommand "$this calc clk_timer2 clk_freq %P" \
+ ]
+ grid $widgets(timer2,clk_freq) -row 1 -column 2 -sticky w -columnspan 3
+ set widgets(timer2,clk_fosc) [ttk::entry \
+ $bottom_frame.clk_fosc_r_lbl \
+ -validate key \
+ -width 12 \
+ -textvariable ::SpecCalc::timer2_clk_fosc_$obj_idx \
+ -validatecommand "$this calc clk_timer2 clk_fosc %P" \
+ ]
+ grid $widgets(timer2,clk_fosc) -row 2 -column 2 -sticky w -columnspan 3
+ # - X2
+ set widgets(timer2,clk_x2_cb) [ttk::combobox $bottom_frame.clock_type_cb \
+ -values {0 1} \
+ -width 1 \
+ -state readonly \
+ -textvariable ::SpecCalc::timer2_clk_x2_$obj_idx \
+ ]
+ bind $widgets(timer2,clk_x2_cb) <<ComboboxSelected>> \
+ "$this calc clk_timer2 clk_x2_cb \[$bottom_frame.clock_type_cb get\]"
+ set ::SpecCalc::timer2_clk_x2_$obj_idx {0}
+ grid $widgets(timer2,clk_x2_cb) -row 3 -column 2 -sticky w -columnspan 3
+ # - RCAL2H
+ set widgets(timer2,clk_rcal2h) [
+ entry $bottom_frame.clk_rcal2h_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} -validate key \
+ -relief flat -highlightthickness 0 -bd 0 -width 5 \
+ -textvariable ::SpecCalc::timer2_clk_rcal2h_$obj_idx \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ ]
+ set ::SpecCalc::timer2_clk_rcal2h_$obj_idx "--"
+ grid $widgets(timer2,clk_rcal2h) -row 6 -column 2 -sticky w
+ # - RCAL2L
+ set widgets(timer2,clk_rcal2l) [
+ entry $bottom_frame.clk_rcal2l_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} -validate key \
+ -relief flat -highlightthickness 0 -bd 0 -width 5 \
+ -textvariable ::SpecCalc::timer2_clk_rcal2l_$obj_idx \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ ]
+ set ::SpecCalc::timer2_clk_rcal2l_$obj_idx "--"
+ grid $widgets(timer2,clk_rcal2l) -row 7 -column 2 -sticky w
+ # RCAL2H
+ set widgets(timer2,clk_rcal2h_d) [
+ entry $bottom_frame.clk_rcal2h_d_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} -validate key \
+ -relief flat -highlightthickness 0 -bd 0 -width 5 \
+ -textvariable ::SpecCalc::timer2_clk_rcal2h_d_$obj_idx \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ ]
+ set ::SpecCalc::timer2_clk_rcal2h_d_$obj_idx "--"
+ grid $widgets(timer2,clk_rcal2h_d) -row 6 -column 3 -sticky w
+ # - RCAL2L
+ set widgets(timer2,clk_rcal2l_d) [
+ entry $bottom_frame.clk_rcal2l_d_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} -validate key \
+ -relief flat -highlightthickness 0 -bd 0 -width 5 \
+ -textvariable ::SpecCalc::timer2_clk_rcal2l_d_$obj_idx \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ ]
+ set ::SpecCalc::timer2_clk_rcal2l_d_$obj_idx "--"
+ grid $widgets(timer2,clk_rcal2l_d) -row 7 -column 3 -sticky w
+ # - Error
+ set widgets(timer2,clk_error) [
+ entry $bottom_frame.clk_error_r_lbl -state readonly \
+ -fg {#888888} -bg {#EEEEEE} -validate key \
+ -relief flat -highlightthickness 0 -bd 0 -width 12 \
+ -textvariable ::SpecCalc::timer2_clk_error_$obj_idx \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ ]
+ set ::SpecCalc::timer2_clk_error_$obj_idx "--"
+ grid $widgets(timer2,clk_error) -row 8 -column 2 -sticky w -columnspan 2
+
+ # Clear entry boxes with results
+ calculate_timer2_clk_clear_results
+
+ # Load values from the last session
+ if {[llength $config]} {
+ set ::SpecCalc::timer2_clk_fosc_$obj_idx [lindex $config {3 0}]
+ set ::SpecCalc::timer2_clk_freq_$obj_idx [lindex $config {3 1}]
+ set ::SpecCalc::timer2_clk_x2_$obj_idx [lindex $config {3 2}]
+ } {
+ set ::SpecCalc::timer2_clk_fosc_$obj_idx {}
+ set ::SpecCalc::timer2_clk_freq_$obj_idx {}
+ set ::SpecCalc::timer2_clk_x2_$obj_idx {0}
+ }
+
+ # Create page header
+ pack [label $clock_out_frame.header \
+ -text [mc "Calculate clock output"] \
+ -font [font create \
+ -family {helvetica} \
+ -size -17 \
+ -weight bold \
+ ] \
+ ] -pady 5
+ pack [label $clock_out_frame.math \
+ -image [image create photo \
+ -format png \
+ -file "${::LIB_DIRNAME}/../icons/other/math0.png" \
+ ] \
+ ] -pady 5
+ pack $bottom_frame -anchor nw
+ $nb raise {Preset}
+ pack $nb -fill both -expand 1
+ }
+
+ ## Create page for calculating SPI related values
+ # @return void
+ private method create_page_spi {} {
+ # Create page frames
+ set page {spi}
+ set top_frame [frame $pages($page).top_frame]
+ set bottom_frame [frame $pages($page).bottom_frame]
+
+ # - Mode X2 or single cycle core
+ set widgets(spi,double_chb) [ \
+ checkbutton $top_frame.double_chb \
+ -text [mc "Mode X2 or single cycle core"] \
+ -onvalue 1 -offvalue 2 \
+ -variable ::SpecCalc::double_chb_$obj_idx \
+ -command "$this calc spi double_chb \${::SpecCalc::double_chb_$obj_idx}" \
+ ]
+ grid $widgets(spi,double_chb) -row 0 -column 0 -columnspan 3 -sticky w
+
+ # Labels ...
+ grid [label $top_frame.spr1_lbl \
+ -text "SPR1" \
+ ] -row 1 -column 0
+ grid [label $top_frame.spr0_lbl \
+ -text "SPR0" \
+ ] -row 1 -column 1
+ grid [label $top_frame.sck_lbl \
+ -text [mc "SCK \[kHz\]"] \
+ ] -row 1 -column 2
+
+ grid [label $top_frame.spr1_0_lbl \
+ -text "0" \
+ ] -row 2 -column 0
+ grid [label $top_frame.spr0_0_lbl \
+ -text "0" \
+ ] -row 2 -column 1
+ set widgets(spi,sck_ent00) [ttk::entry $top_frame.sck_0_ent \
+ -width 9 \
+ -validate key \
+ -validatecommand "$this calc spi sck_ent00 %P" \
+ ]
+ grid $widgets(spi,sck_ent00) -row 2 -column 2
+
+ grid [label $top_frame.spr1_1_lbl \
+ -text "0" \
+ ] -row 3 -column 0
+ grid [label $top_frame.spr0_1_lbl \
+ -text "1" \
+ ] -row 3 -column 1
+ set widgets(spi,sck_ent01) [ttk::entry $top_frame.sck_1_ent \
+ -width 9 \
+ -validate key \
+ -validatecommand "$this calc spi sck_ent01 %P" \
+ ]
+ grid $widgets(spi,sck_ent01) -row 3 -column 2
+
+ grid [label $top_frame.spr1_2_lbl \
+ -text "1" \
+ ] -row 4 -column 0
+ grid [label $top_frame.spr0_2_lbl \
+ -text "0" \
+ ] -row 4 -column 1
+ set widgets(spi,sck_ent10) [ttk::entry $top_frame.sck_2_ent \
+ -width 9 \
+ -validate key \
+ -validatecommand "$this calc spi sck_ent10 %P" \
+ ]
+ grid $widgets(spi,sck_ent10) -row 4 -column 2
+
+ grid [label $top_frame.spr1_3_lbl \
+ -text "1" \
+ ] -row 5 -column 0
+ grid [label $top_frame.spr0_3_lbl \
+ -text "1" \
+ ] -row 5 -column 1
+ set widgets(spi,sck_ent11) [ttk::entry $top_frame.sck_3_ent \
+ -width 9 \
+ -validate key \
+ -validatecommand "$this calc spi sck_ent11 %P" \
+ ]
+ grid $widgets(spi,sck_ent11) -row 5 -column 2
+
+
+ pack [label $bottom_frame.res_lbl0 \
+ -text [mc "Set MCU oscillator to "] \
+ ] -side left
+ set widgets(spi,result) [ \
+ entry $bottom_frame.result_ent \
+ -readonlybackground {#EEEEEE} \
+ -disabledforeground {#000000} \
+ -bg {#EEEEEE} -width 0 -bd 1 -state readonly \
+ -relief flat -highlightthickness 0 \
+ -textvariable ::SpecCalc::spi_result_$obj_idx \
+ ]
+ pack $widgets(spi,result) -side left
+ pack [label $bottom_frame.res_lbl1 \
+ -text [mc " kHz"] \
+ ] -side left
+
+ pack [label $pages($page).header \
+ -text [mc "Calculate oscillator frequency"] \
+ -font [font create \
+ -family {helvetica} \
+ -size -17 \
+ -weight bold \
+ ] \
+ ] -pady 5
+ pack $top_frame -pady 5 -anchor nw
+ pack [ttk::separator $pages($page).sep \
+ -orient horizontal \
+ ] -fill x -pady 10
+ pack $bottom_frame -anchor nw -padx 10
+
+ set ::SpecCalc::spi_result_$obj_idx "--"
+
+ if {[llength $config]} {
+ set ::SpecCalc::double_chb_$obj_idx [lindex $config {5 0}]
+ calc spi double_chb [lindex $config {5 0}]
+
+ $widgets(spi,sck_ent00) delete 0 end
+ $widgets(spi,sck_ent00) insert 0 [lindex $config {5 1}]
+ }
+ }
+
+ ## Create GUI for page specified by parameter
+ # @parm String page -Page ID
+ # @return void
+ public method create_page {page} {
+ if {$page_created($page)} {return}
+ set page_created($page) 1
+
+ switch -- $page {
+ {loops} { ;# Wait loops
+ create_page_loops
+ }
+ {timer01} { ;# Timer 0/1
+ create_page_timer01
+ }
+ {timer2} { ;# Timer 2
+ create_page_timer2
+ }
+ {spi} { ;# SPI (Serial Peripheral Interface)
+ create_page_spi
+ }
+ }
+ }
+
+ ## Auxiliary procedure for procedure "calculate_loops"
+ # @parm float time
+ # @parm float rest
+ # @parm Bool is_spec
+ # @return List
+ private method calculate_loops_AUX {time rest is_spec} {
+ array set res {0 {} 1 {} 2 {} 3 {} 4 {} 5 {} 6 {} 7 {}}
+ set len 0
+ set div_all 1
+ for {set len 0} {$len < 9} {incr len} {
+ if {$len == 8} {
+ status_tip [mc "Unable to evaluate"]
+ calculate_loops_clear_results
+ return 0
+ } elseif {$len} {
+ set init 256
+ } else {
+ set init 257
+ }
+
+ set mod $init
+ set div $init
+ for {set i $init} {$i >= 2} {incr i -1} {
+ if {($time % $i) < $mod} {
+ set mod [expr {$time % $i}]
+ set div $i
+ }
+ }
+
+ set rest [expr {$rest + ($mod * $div_all)}]
+ set div_all [expr {$div_all * $div}]
+ set time [expr {$time / $div}]
+ if {$res($len) == 256} {
+ set res($len) 0
+ } {
+ set res($len) $div
+ }
+
+ if {$time == 1} {
+ break
+ }
+ }
+ incr len
+ if {$len > 1} {
+ incr res(0) -2
+ } {
+ incr res(0) -1
+ }
+ set correction 0
+ if {$len == 1} {
+ if {[lindex $is_spec 0]} {
+ set correction -1
+ }
+ }
+ for {set i 1} {$i < $len} {incr i} {
+ set div $res($i)
+ set div_all [expr {$div_all * $div}]
+
+ if {$i == 1} {
+ if {[lindex $is_spec $i]} {
+ set correction 1
+ } {
+ set correction 2
+ }
+ } {
+ if {[lindex $is_spec $i]} {
+ set correction [expr {($correction * $res($i)) + ($res($i) * 2) + 1}]
+ } {
+ set correction [expr {($correction * $res($i)) + ($res($i) * 3) + 2}]
+ }
+ }
+ }
+
+ set rest [expr {(2.0 * $rest) - $correction}]
+ return [list $rest $len [array get res]]
+ }
+
+ ## Report an error occured during evaluation of the wait loop
+ # @return void
+ private method calculate_loops_evaluation_error {} {
+ error "Please report this bug. Method ::SpecCalc::calculate_loops --> Evaluation error. Dump: \n\$widgets(loops,time_ent) == $widgets(loops,time_ent)\n\$widgets(loops,time_cb) == $widgets(loops,time_cb)\n\$widgets(loops,clock_cb) == $widgets(loops,clock_cb)\n\$widgets(loops,clock_type_cb) == $widgets(loops,clock_type_cb)\n\$widgets(loops,reg_ent0) == $widgets(loops,reg_ent0)\n\$widgets(loops,reg_ent1) == $widgets(loops,reg_ent1)\n\$widgets(loops,reg_ent2) == $widgets(loops,reg_ent2)\n\$widgets(loops,reg_ent3) == $widgets(loops,reg_ent3)\n\$widgets(loops,reg_ent4) == $widgets(loops,reg_ent4)\n\$widgets(loops,reg_ent5) == $widgets(loops,reg_ent5)\n\$widgets(loops,reg_ent6) == $widgets(loops,reg_ent6)\n\$widgets(loops,reg_ent7) == $widgets(loops,reg_ent7)"
+ }
+
+ ## Generate wait loop acoring to specified criteria
+ # @return void
+ private method calculate_loops {} {
+ $widgets(loops,results) configure -state normal
+ $widgets(loops,results) delete 0.0 end
+
+ set note {}
+
+ set is_spec [list]
+ for {set i 0} {$i < 8} {incr i} {
+ set reg($i) [$widgets(loops,reg_ent$i) get]
+
+ if {[lsearch -ascii -exact {R0 R1 R2 R3 R4 R5 R6 R7 A} [string toupper $reg($i)]] != -1} {
+ lappend is_spec 1
+ } {
+ lappend is_spec 0
+ }
+ }
+
+ set time [$widgets(loops,time_ent) get]
+ if {$time == {}} {
+ set time 1
+ append note [mc "ERROR: Missing time\n"]
+ } elseif {$time == 0} {
+ append note [mc "ERROR: Time rate cannot be 0\n"]
+ }
+
+ set clock [$widgets(loops,clock_cb) get]
+ if {$clock == {}} {
+ set clock 1
+ append note [mc "ERROR: Missing MCU clock rate\n"]
+ } elseif {$clock == 0} {
+ append note [mc "ERROR: MCU clock rate cannot be 0\n"]
+ }
+
+ if {[string length $note]} {
+ $widgets(loops,results) insert end $note
+ $widgets(loops,results) configure -state disabled
+ return 0
+ }
+
+ set time [expr {$time * [lindex {1.0 1000.0 1000000.0 1000000000.0} [$widgets(loops,time_cb) current]] / 2.0}]
+ set clock [expr {[lindex {12.0 6.0 1.0} [$widgets(loops,clock_type_cb) current]] / $clock}]
+ set time [expr {$time * $clock}]
+
+ set time_org $time
+ set i 0
+ set result [list]
+ set lowes_rest $time
+ set last_rest {}
+ set result_c {}
+ set result_fin_i 0
+ for {set i 0} {$i < 8} {incr i} {
+
+ set rest $time_org
+ set time [expr {int($time)}]
+ set rest [expr {$rest - $time}]
+
+ set result_c [calculate_loops_AUX $time $rest $is_spec]
+ if {$result_c == {0}} {
+ return 0
+ }
+ lappend result $result_c
+
+ if {$lowes_rest == {}} {
+ set lowes_rest [lindex $result_c 0]
+
+ } elseif {($lowes_rest < 0) && ([lindex $result_c 0] >= 0)} {
+ set result_fin_i $i
+ set lowes_rest [lindex $result_c 0]
+
+ } elseif {abs($lowes_rest) > abs([lindex $result_c 0])} {
+ set result_fin_i $i
+ set lowes_rest [lindex $result_c 0]
+ }
+
+ if {$last_rest == [lindex $result_c 0] || ![lindex $result_c 0]} {
+ break
+ }
+ set last_rest [lindex $result_c 0]
+ set time [expr {$time_org + ($last_rest / 2.0)}]
+ }
+ set time $time_org
+ set rest [lindex $result [list $result_fin_i 0]]
+ set len [lindex $result [list $result_fin_i 1]]
+ array set res [lindex $result [list $result_fin_i 2]]
+
+
+ for {set i 0} {$i < $len} {incr i} {
+ set error 0
+ if {![string length $reg($i)]} {
+ set error 1
+ $widgets(loops,results) insert end \
+ [mc "ERROR: Missing register name %s\n" $i]
+ } elseif {[$widgets(loops,reg_ent$i) cget -style] == {StringNotFound.TEntry}} {
+ set error 1
+ $widgets(loops,results) insert end \
+ [mc "ERROR: Ambiguous register name %s\n" $i]
+ }
+
+ if {$error} {
+ $widgets(loops,results) configure -state disabled
+ return 0
+ }
+ }
+ $widgets(loops,results) insert end [mc "; START: Wait loop, time: %s %s\n; Clock: %s kHz (%s)\n; Used registers: " [$widgets(loops,time_ent) get] [$widgets(loops,time_cb) get] [$widgets(loops,clock_cb) get] [$widgets(loops,clock_type_cb) get]]
+ for {set i 0} {$i < $len} {incr i} {
+ if {$i} {
+ $widgets(loops,results) insert end ", "
+ }
+ $widgets(loops,results) insert end $reg($i)
+ }
+ $widgets(loops,results) insert end "\n"
+
+ set last_branch 0
+ set branch 0
+ for {set i 0} {$i < $len} {incr i} {
+ set branch $last_branch
+ set val $res($i)
+
+ set val [string range [format {%X} $res($i)] end-1 end]
+ set val "[string repeat {0} [expr {3 - [string length $val]}]]$val"
+
+ set cmp {}
+ if {[lindex $is_spec $i]} {
+ if {!$i} {
+ set cmp "\n\tNOP"
+ incr branch 1
+ }
+ } {
+ incr branch 2
+ }
+ incr branch 4
+
+ set last_branch $branch
+ if {!$i} {
+ set branch 0
+ incr last_branch -4
+ }
+
+ if {$branch == {0}} {
+ set branch {}
+ } {
+ set branch "-$branch"
+ }
+
+ set res($i) [list \
+ "\tDJNZ\t$reg($i), \$$branch" \
+ "\tMOV\t$reg($i), #${val}h$cmp" \
+ ]
+ }
+
+ for {set i [expr {$len - 1}]} {$i >= 0} {incr i -1} {
+ $widgets(loops,results) insert end "[lindex $res($i) 1]\n"
+ }
+
+ for {set i 0} {$i < $len} {incr i} {
+ $widgets(loops,results) insert end "[lindex $res($i) 0]\n"
+ }
+
+ if {$rest <= 4} {
+ for {set i 0} {$i < 5} {incr i} {
+ if {int(ceil($rest)) > 0.5} {
+ $widgets(loops,results) insert end "\tNOP\n"
+ set rest [expr {$rest - 1}]
+ }
+ }
+ } {
+ if {[lindex $is_spec 0]} {
+ set rest [expr {$rest - 1}]
+ } {
+ set rest [expr {$rest - 2}]
+ }
+ set val [expr {int($rest / 2)}]
+ set rest [expr {$rest - ($val * 2.0)}]
+ if {$val == 256} {
+ set val 0
+ } elseif {$val > 256} {
+ status_tip [mc "Unable to evaluate"]
+ calculate_loops_clear_results
+ return 0
+ }
+ set val [string range [format {%X} $val] end-1 end]
+ set val "[string repeat {0} [expr {3 - [string length $val]}]]$val"
+
+ $widgets(loops,results) insert end "\tMOV\t$reg(0), #${val}h\n"
+ $widgets(loops,results) insert end "\tDJNZ\t$reg(0), \$\n"
+ if {int(ceil($rest)) > 0.5} {
+ $widgets(loops,results) insert end "\tNOP\n"
+ set rest [expr {$rest - 1}]
+ }
+ }
+ set rest [expr {$rest * 1.0 / $clock}]
+ $widgets(loops,results) insert end [mc "; Rest: %s\n" [adjust_rest $rest]]
+
+ $widgets(loops,results) insert end [mc "; END: Wait loop"]
+
+ set end [expr {int([$widgets(loops,results) index end])}]
+ for {set i 1} {$i < $end} {incr i} {
+ ASMsyntaxHighlight::highlight $widgets(loops,results) $i
+ }
+ $widgets(loops,results) configure -state disabled
+
+ return 1
+ }
+
+ ## Clear results of the last wait loop calculation
+ # @return void
+ private method calculate_loops_clear_results {} {
+ $widgets(loops,results) configure -state normal
+ $widgets(loops,results) delete 0.0 end
+ $widgets(loops,results) configure -state disabled
+
+ calculate_loops_enable_copy 0
+ }
+
+ ## Enable "Copy" button in page "Wait loops"
+ # @parm Bool enable - 1 == Enable; 0 == Disable
+ # @return void
+ private method calculate_loops_enable_copy {enable} {
+ if {$enable} {
+ set enable {normal}
+ } {
+ set enable {disabled}
+ }
+ $widgets(loops,copy_but) configure -state $enable
+ }
+
+ ## Calulate time 0 or 1 preset values
+ # @return void
+ public method calculate_timer01 {} {
+ set time [$widgets(timer01,time_ent) get]
+ if {$time == {} || $time == 0} {
+ status_tip [mc "Invalid time"]
+ return 0
+ }
+
+ set clock [$widgets(timer01,clock_cb) get]
+ if {$clock == {} || $clock == 0} {
+ status_tip [mc "Invalid clock rate"]
+ return 0
+ }
+ status_tip ""
+
+ set ::SpecCalc::timer01_th_$obj_idx [mc "Do not change"]
+ set ::SpecCalc::timer01_tl_$obj_idx [mc "Do not change"]
+ set ::SpecCalc::timer01_rh_$obj_idx [mc "Do not change"]
+ set ::SpecCalc::timer01_rl_$obj_idx [mc "Do not change"]
+ set ::SpecCalc::timer01_repeats_$obj_idx [mc "Zero"]
+ set ::SpecCalc::timer01_rest_$obj_idx [mc "none"]
+
+ foreach w {th tl rh rl repeats rest} {
+ $widgets(timer01,$w) configure -fg {#888888}
+ }
+
+ set time [expr {$time * [lindex {1.0 1000.0 1000000.0 1000000000.0} [$widgets(timer01,time_cb) current]]}]
+ set clock [expr {[lindex {12.0 6.0 1.0} [$widgets(timer01,clock_type_cb) current]] / $clock}]
+ set time [expr {$time * $clock}]
+ set time_int [expr {int($time)}]
+
+ set enhanced [subst "\$::SpecCalc::spec_chb_$obj_idx"]
+ set prescaler [$widgets(timer01,psc_cb) current]
+
+ # Set default results
+ set low 0
+ set high 0
+ set repeats 0
+ set rest 0
+
+ switch -- [$widgets(timer01,mode_cb) current] {
+ {0} { ;# 9 -> 16 bit counter
+ if {$enhanced} {
+ set bits [expr {$prescaler + 9}]
+ } {
+ set bits 13
+ }
+ set capacity [expr {1 << $bits}]
+ set full_mask [expr {$capacity - 1}]
+ set low_mask [expr {$full_mask >> 8}]
+
+ # Determinate apparent number of repeats
+ set repeats [expr {($time_int >> $bits) + 1}]
+ # Calculate tempotary results
+ if {[expr {!($time_int & $full_mask)}]} {
+ incr repeats -1
+ set stepsPerIter $full_mask
+ } {
+ set stepsPerIter [expr {$time_int / $repeats}]
+ set tmp [expr {$capacity - $stepsPerIter}]
+ set low [expr {$tmp & $low_mask}]
+ set high [expr {$tmp >> 5}]
+ set rest [expr {$time_int - (($full_mask - $tmp) * $repeats)}]
+ }
+
+ # Perform correction
+ if {$rest >= $stepsPerIter} {
+ incr repeats [expr {$rest / $stepsPerIter}]
+ set rest [expr {$rest % $stepsPerIter}]
+ }
+
+ set rest [expr {($rest + $time - $time_int) / $clock}]
+ set rest [adjust_rest $rest]
+
+ if {$repeats > 1} {
+ status_tip [mc "Value is too high"]
+ return 0
+ }
+
+ set low [format {%X} $low]
+ set low "[string repeat {0} [expr {3 - [string length $low]}]]${low}h"
+ set high [format {%X} $high]
+ set high "[string repeat {0} [expr {3 - [string length $high]}]]${high}h"
+
+ set ::SpecCalc::timer01_tl_$obj_idx $low
+ set ::SpecCalc::timer01_th_$obj_idx $high
+ set ::SpecCalc::timer01_rest_$obj_idx $rest
+ set ::SpecCalc::timer01_repeats_$obj_idx "One"
+
+ foreach w {th tl rest} {
+ $widgets(timer01,$w) configure -fg {#000000}
+ }
+ }
+ {1} { ;# 16 bit (maybe auto-reload)
+
+ # Determinate apparent number of repeats
+ set repeats [expr {($time_int >> 16) + 1}]
+ # Calculate tempotary results
+ if {[expr {!($time_int & 0xFFFF)}]} {
+ incr repeats -1
+ set stepsPerIter 0xFFFF
+ set tmp 0
+ } {
+ set stepsPerIter [expr {$time_int / $repeats}]
+ set tmp [expr {0x10000 - $stepsPerIter}]
+ set low [expr {$tmp & 0xFF}]
+ set high [expr {$tmp >> 8}]
+ set rest [expr {$time_int - ((0xFFFF - $tmp) * $repeats)}]
+ }
+
+ # Perform correction
+ if {$rest >= $stepsPerIter} {
+ incr repeats [expr {$rest / $stepsPerIter}]
+ set rest [expr {$rest % $stepsPerIter}]
+ }
+
+ incr tmp -$rest
+ if {$tmp < 0} {
+ set rest [expr {abs($tmp)}]
+ set tmp 0
+ } {
+ set rest 0
+ }
+ set tmp [expr {$tmp & 0x0FFFF}]
+ set low_p [expr {$tmp & 0xFF}]
+ set high_p [expr {$tmp >> 8}]
+
+ set rest [expr {($rest + $time - $time_int) / $clock}]
+ set rest [adjust_rest $rest]
+
+ set low [format {%X} $low]
+ set low "[string repeat {0} [expr {3 - [string length $low]}]]${low}h"
+ set high [format {%X} $high]
+ set high "[string repeat {0} [expr {3 - [string length $high]}]]${high}h"
+ set low_p [format {%X} $low_p]
+ set low_p "[string repeat {0} [expr {3 - [string length $low_p]}]]${low_p}h"
+ set high_p [format {%X} $high_p]
+ set high_p "[string repeat {0} [expr {3 - [string length $high_p]}]]${high_p}h"
+
+ if {$enhanced} {
+ set ::SpecCalc::timer01_tl_$obj_idx $low_p
+ set ::SpecCalc::timer01_th_$obj_idx $high_p
+ set ::SpecCalc::timer01_rl_$obj_idx $low
+ set ::SpecCalc::timer01_rh_$obj_idx $high
+ set ::SpecCalc::timer01_rest_$obj_idx $rest
+ set ::SpecCalc::timer01_repeats_$obj_idx $repeats
+ foreach w {rh rl tl th rest repeats} {
+ $widgets(timer01,$w) configure -fg {#000000}
+ }
+ } {
+ if {$repeats > 1} {
+ status_tip [mc "Value is too high"]
+ return 0
+ }
+ set ::SpecCalc::timer01_tl_$obj_idx $low
+ set ::SpecCalc::timer01_th_$obj_idx $high
+ set ::SpecCalc::timer01_rest_$obj_idx $rest
+ set ::SpecCalc::timer01_repeats_$obj_idx [mc "One"]
+ foreach w {th tl rest} {
+ $widgets(timer01,$w) configure -fg {#000000}
+ }
+ }
+ }
+ {2} { ;# 8 bit auto reload
+
+ # Determinate apparent number of repeats
+ set repeats [expr {($time_int >> 8) + 1}]
+ # Calculate tempotary results
+ if {[expr {!($time_int & 0xFF)}]} {
+ incr repeats -1
+ set stepsPerIter 0xFF
+ } {
+ set stepsPerIter [expr {$time_int / $repeats}]
+ set low [expr {0x100 - $stepsPerIter}]
+ set high $low
+ set rest [expr {$time_int - ((0xFF - $low) * $repeats)}]
+ }
+
+ # Perform correction
+ if {$rest >= $stepsPerIter} {
+ incr repeats [expr {$rest / $stepsPerIter}]
+ set rest [expr {$rest % $stepsPerIter}]
+ }
+
+ incr low -$rest
+ if {$low < 0} {
+ set rest [expr {abs($low)}]
+ set low 0
+ } {
+ set rest 0
+ }
+
+ set rest [expr {($rest + $time - $time_int) / $clock}]
+ set rest [adjust_rest $rest]
+
+ set low [format {%X} $low]
+ set low "[string repeat {0} [expr {3 - [string length $low]}]]${low}h"
+ set high [format {%X} $high]
+ set high "[string repeat {0} [expr {3 - [string length $high]}]]${high}h"
+
+ set ::SpecCalc::timer01_tl_$obj_idx $low
+ set ::SpecCalc::timer01_th_$obj_idx $high
+ set ::SpecCalc::timer01_rest_$obj_idx $rest
+ set ::SpecCalc::timer01_repeats_$obj_idx $repeats
+
+ foreach w {th tl rest repeats} {
+ $widgets(timer01,$w) configure -fg {#000000}
+ }
+ }
+ }
+
+ return 1
+ }
+
+ ## Calulate time 2 preset values
+ # @return void
+ public method calculate_timer2 {} {
+ set time [$widgets(timer2,time_ent) get]
+ if {$time == {} || $time == 0} {
+ status_tip [mc "Invalid time"]
+ return 0
+ }
+
+ set clock [$widgets(timer2,clock_cb) get]
+ if {$clock == {} || $clock == 0} {
+ status_tip [mc "Invalid clock rate"]
+ return 0
+ }
+ status_tip ""
+
+ set ::SpecCalc::timer2_rcal2h_$obj_idx [mc "Do not change"]
+ set ::SpecCalc::timer2_rcal2l_$obj_idx [mc "Do not change"]
+ set ::SpecCalc::timer2_t2l_$obj_idx [mc "Do not change"]
+ set ::SpecCalc::timer2_t2h_$obj_idx [mc "Do not change"]
+ set ::SpecCalc::timer2_repeats_$obj_idx [mc "Zero"]
+ set ::SpecCalc::timer2_rest_$obj_idx [mc "none"]
+
+ foreach w {rcal2h rcal2l t2h t2l repeats rest} {
+ $widgets(timer2,$w) configure -fg {#888888}
+ }
+
+ set time [expr {$time * [lindex {1.0 1000.0 1000000.0 1000000000.0} [$widgets(timer2,time_cb) current]]}]
+ set clock [expr {[lindex {12.0 6.0 1.0} [$widgets(timer2,clock_type_cb) current]] / $clock}]
+ set time [expr {$time * $clock}]
+ set time_int [expr {int($time)}]
+ set mode [$widgets(timer2,mode_cb) current]
+
+ # Set default results
+ set low 0
+ set high 0
+ set repeats 0
+ set rest 0
+
+ # Determinate apparent number of repeats
+ set repeats [expr {($time_int >> 16) + 1}]
+
+ if {$mode} {
+ set tmp [expr {$time_int & 0xFFFF}]
+ set low [expr {$tmp & 0xFF}]
+ set high [expr {$tmp >> 8}]
+ set rest [expr {$time - $time_int}]
+
+ set low_p $low
+ set high_p $high
+ } {
+ # Calculate tempotary results
+ if {[expr {!($time_int & 0xFFFF)}]} {
+ incr repeats -1
+ set stepsPerIter 0xFFFF
+ set tmp 0
+ } {
+ set stepsPerIter [expr {$time_int / $repeats}]
+ set tmp [expr {0x10000 - $stepsPerIter}]
+ set rest [expr {$time_int - ((0x10000 - $tmp) * $repeats)}]
+ set low [expr {$tmp & 0xFF}]
+ set high [expr {$tmp >> 8}]
+ }
+
+ # Perform correction
+ if {$rest >= $stepsPerIter} {
+ incr repeats [expr {$rest / $stepsPerIter}]
+ set rest [expr {$rest % $stepsPerIter}]
+ }
+
+ incr tmp -$rest
+ if {$tmp < 0} {
+ set rest [expr {abs($tmp)}]
+ set tmp 0
+ } {
+ set rest 0
+ }
+ set tmp [expr {$tmp & 0x0FFFF}]
+ set low_p [expr {$tmp & 0xFF}]
+ set high_p [expr {$tmp >> 8}]
+
+ }
+ set rest [expr {($rest + $time - $time_int) / $clock}]
+ set rest [adjust_rest $rest]
+
+ set low [format {%X} $low]
+ set low "[string repeat {0} [expr {3 - [string length $low]}]]${low}h"
+ set high [format {%X} $high]
+ set high "[string repeat {0} [expr {3 - [string length $high]}]]${high}h"
+ set low_p [format {%X} $low_p]
+ set low_p "[string repeat {0} [expr {3 - [string length $low_p]}]]${low_p}h"
+ set high_p [format {%X} $high_p]
+ set high_p "[string repeat {0} [expr {3 - [string length $high_p]}]]${high_p}h"
+
+ if {!$mode} {
+ set ::SpecCalc::timer2_rcal2l_$obj_idx $low
+ set ::SpecCalc::timer2_rcal2h_$obj_idx $high
+ }
+ set ::SpecCalc::timer2_t2l_$obj_idx $low_p
+ set ::SpecCalc::timer2_t2h_$obj_idx $high_p
+ set ::SpecCalc::timer2_rest_$obj_idx $rest
+ set ::SpecCalc::timer2_repeats_$obj_idx $repeats
+ foreach w {rest repeats t2h t2l} {
+ $widgets(timer2,$w) configure -fg {#000000}
+ }
+ if {!$mode} {
+ foreach w {rcal2h rcal2l} {
+ $widgets(timer2,$w) configure -fg {#000000}
+ }
+ }
+
+ return 1
+ }
+
+ ## Convert number of nano-seconds to something like this: "10 s"
+ # @parm Int rest_in_ns - Some amount of nano-seconds
+ # @return String - Human readable string
+ private method adjust_rest {rest_in_ns} {
+ set tmp $rest_in_ns
+
+ if {$tmp == 0.0} {
+ return "0"
+ }
+
+ set tmp [expr {ceil($tmp * 1000.0) / 1000.0}]
+
+ set tmp_o $tmp
+ set tmp [expr ($tmp / 1000.0)]
+ if {$tmp != int($tmp)} {
+ return "$tmp_o ns"
+ }
+
+ set tmp_o $tmp
+ set tmp [expr ($tmp / 1000.0)]
+ if {$tmp != int($tmp)} {
+ return "$tmp_o us"
+ }
+
+ set tmp_o $tmp
+ set tmp [expr ($tmp / 1000.0)]
+ if {$tmp != int($tmp)} {
+ return "$tmp_o ms"
+ }
+
+ return "$tmp s"
+ }
+
+ ## Clear results from the last calculaton of timer 0/1 preset
+ # @return void
+ private method calculate_timer01_clear_results {} {
+ foreach w {rest rh rl th tl} {
+ $widgets(timer01,$w) delete 0
+ }
+ }
+
+ ## Clear results from the last calculaton of timer 2 preset
+ # @return void
+ private method calculate_timer2_clear_results {} {
+ foreach w {rest rcal2l rcal2h} {
+ $widgets(timer2,$w) delete 0
+ }
+ }
+
+ ## Clear results from the last calculaton of timer 2 clock output preset
+ # @return void
+ private method calculate_timer2_clk_clear_results {} {
+ set ::SpecCalc::timer2_clk_rcal2h_$obj_idx {--}
+ set ::SpecCalc::timer2_clk_rcal2l_$obj_idx {--}
+ set ::SpecCalc::timer2_clk_rcal2h_d_$obj_idx {--}
+ set ::SpecCalc::timer2_clk_rcal2l_d_$obj_idx {--}
+ set ::SpecCalc::timer2_clk_error_$obj_idx {--}
+
+ foreach w {rcal2h rcal2l rcal2h_d rcal2l_d error} {
+ $widgets(timer2,clk_${w}) configure -fg {#888888}
+ }
+ }
+
+ ## Perform calculation intented for page "Timer 2 clock output"
+ # @return void
+ public method calculate_timer2_clk {} {
+ set o [subst "\$::SpecCalc::timer2_clk_fosc_$obj_idx"]
+ set f [subst "\$::SpecCalc::timer2_clk_freq_$obj_idx"]
+ set x [subst "\$::SpecCalc::timer2_clk_x2_$obj_idx"]
+ if {
+ ![string length $o] || ![string length $f] || ![string length $x] ||
+ $f == 0 || $o == 0
+ } then {
+ calculate_timer2_clk_clear_results
+ return 0
+ }
+
+ set hl [expr {int(0x10000 - ($o * 1.0 * pow(2,$x))/(2.0 * $f))}]
+ set fr [expr {($o * 1.0 * pow(2,$x)) / (2.0 * (0x10000 - $hl))}]
+ set e [expr {round(($fr - $f) * 100000.0 / $f) / 1000.0}]
+
+ set h [expr {$hl >> 8}]
+ set l [expr {$hl & 0x0FF}]
+
+ set ::SpecCalc::timer2_clk_rcal2h_d_$obj_idx $h
+ set ::SpecCalc::timer2_clk_rcal2l_d_$obj_idx $l
+ set v [format {%X} $h]
+ set v "[string repeat {0} [expr {3 - [string length $v]}]]${v}h"
+ set ::SpecCalc::timer2_clk_rcal2h_$obj_idx $v
+ set v [format {%X} $l]
+ set v "[string repeat {0} [expr {3 - [string length $v]}]]${v}h"
+ set ::SpecCalc::timer2_clk_rcal2l_$obj_idx $v
+ set ::SpecCalc::timer2_clk_error_$obj_idx "$e %"
+
+
+ foreach w {rcal2h rcal2l rcal2h_d rcal2l_d error} {
+ $widgets(timer2,clk_${w}) configure -fg {#000000}
+ }
+ }
+
+ ## Perform calculation intented for page "SPI"
+ # @parm
+ # @parm
+ # @return void
+ private method calculate_spi {type value} {
+ set const [subst "\$::SpecCalc::double_chb_$obj_idx"]
+
+ switch -- $type {
+ {sck_ent00} {
+ set freq [expr {$value * $const * 2}]
+ }
+ {sck_ent01} {
+ set freq [expr {$value * $const * 8}]
+ }
+ {sck_ent10} {
+ set freq [expr {$value * $const * 32}]
+ }
+ {sck_ent11} {
+ set freq [expr {$value * $const * 64}]
+ }
+ {double_chb} {
+ set const $value
+
+ set freq [$widgets(spi,sck_ent00) get]
+ if {![string length $freq]} {
+ return 0
+ }
+ set freq [expr {$freq * ($const == 2 ? 1 : 2) * 2}]
+ }
+ default {
+ return 0
+ }
+ }
+
+ if {![string equal $type {sck_ent00}]} {
+ $widgets(spi,sck_ent00) delete 0 end
+ $widgets(spi,sck_ent00) insert end [expr {$freq / $const / 2.0}]
+ }
+ if {![string equal $type {sck_ent01}]} {
+ $widgets(spi,sck_ent01) delete 0 end
+ $widgets(spi,sck_ent01) insert end [expr {$freq / $const / 8.0}]
+ }
+ if {![string equal $type {sck_ent10}]} {
+ $widgets(spi,sck_ent10) delete 0 end
+ $widgets(spi,sck_ent10) insert end [expr {$freq / $const / 32.0}]
+ }
+ if {![string equal $type {sck_ent11}]} {
+ $widgets(spi,sck_ent11) delete 0 end
+ $widgets(spi,sck_ent11) insert end [expr {$freq / $const / 64.0}]
+ }
+
+ set ::SpecCalc::spi_result_$obj_idx $freq
+ return 1
+ }
+
+ ## Perform certain calculation
+ # @parm String page - Page ID
+ # @parm String type - Orininator ID
+ # @parm String value - Originator value
+ # @return void
+ public method calc {page type value} {
+ if {$calc_in_progress} {return 1}
+ set calc_in_progress 1
+
+ switch -- $page {
+ {loops} {
+ switch -glob -- $type {
+ {time_ent} {
+ if {![regexp {^[0-9]*(\.[0-9]*)?$} $value]} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {![string length $value]} {
+ $widgets(loops,time_ent) configure -style StringNotFound.TEntry
+
+ } else {
+ $widgets(loops,time_ent) configure -style TEntry
+ }
+
+
+ if {![string equal [$widgets(loops,$type) get] $value]} {
+ calculate_loops_clear_results
+ }
+ }
+ {time_cb} {
+ calculate_loops_clear_results
+ }
+ {clock_cb} {
+ if {![regexp {^[0-9]*(\.[0-9]*)?$} $value] || [string length $value] > 9} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {![string length $value]} {
+ $widgets(loops,clock_cb) configure -style SpecCalc_RedBg.TCombobox
+
+ } else {
+ $widgets(loops,clock_cb) configure -style TCombobox
+ }
+
+ calculate_loops_clear_results
+ }
+ {clock_type_cb} {
+ calculate_loops_clear_results
+ }
+ {reg_ent?} {
+ for {set i 0} {$i < 8} {incr i} {
+ $widgets(loops,reg_ent$i) configure -style TEntry
+ }
+
+ for {set j 0} {$j < 8} {incr j} {
+ for {set i 0} {$i < 8} {incr i} {
+ if {[string equal "reg_ent$i" "reg_ent$j"]} {
+ continue
+ }
+
+ if {[string equal $type "reg_ent$j"]} {
+ set val $value
+ } else {
+ set val [$widgets(loops,reg_ent$j) get]
+ }
+
+ if {[string equal -nocase \
+ $val \
+ [$widgets(loops,reg_ent$i) get] \
+ ] \
+ } then {
+ $widgets(loops,reg_ent$i) configure -style StringNotFound.TEntry
+ $widgets(loops,reg_ent$j) configure -style StringNotFound.TEntry
+ }
+ }
+ }
+
+ if {![string equal [$widgets(loops,$type) get] $value]} {
+ calculate_loops_clear_results
+ }
+
+ set calc_in_progress 0
+ return 1
+ }
+ {compute_but} {
+ if {[catch {
+ if {[calculate_loops]} {
+ calculate_loops_enable_copy 1
+ } {
+ calculate_loops_enable_copy 0
+ }
+ }]} {
+ calculate_loops_evaluation_error
+ }
+ }
+ {copy_but} {
+ clipboard clear
+ clipboard append [$widgets(loops,results) get 0.0 end]
+ }
+ }
+ }
+ {timer01} {
+ switch -- $type {
+ {time_ent} {
+ if {![regexp {^[0-9]*(\.[0-9]*)?$} $value]} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {![string length $value]} {
+ $widgets(timer01,time_ent) configure -style StringNotFound.TEntry
+
+ } else {
+ $widgets(timer01,time_ent) configure -style TEntry
+ }
+
+
+ if {![string equal [$widgets(timer01,$type) get] $value]} {
+ calculate_timer01_clear_results
+ }
+ }
+ {time_cb} {
+ if {![string equal [$widgets(timer01,$type) get] $value]} {
+ calculate_timer01_clear_results
+ }
+ }
+ {clock_cb} {
+ if {![regexp {^[0-9]*(\.[0-9]*)?$} $value] || [string length $value] > 9} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {![string length $value]} {
+ $widgets(timer01,clock_cb) configure -style SpecCalc_RedBg.TCombobox
+ } else {
+ $widgets(timer01,clock_cb) configure -style TCombobox
+ }
+
+ if {![string equal [$widgets(timer01,$type) get] $value]} {
+ calculate_timer01_clear_results
+ }
+ }
+ {clock_type_cb} {
+ if {![string equal [$widgets(timer01,$type) get] $value]} {
+ calculate_timer01_clear_results
+ }
+ }
+ {mode_cb} {
+ if {![string equal [$widgets(timer01,$type) get] $value]} {
+ calculate_timer01_clear_results
+ }
+ }
+ {spec_chb} {
+ if {$value} {
+ grid $widgets(timer01,psc_lbl) -row 4 -column 0 -sticky w
+ grid $widgets(timer01,psc_cb) -row 4 -column 1 -sticky w
+ grid $widgets(timer01,rh_l) -row 3 -column 1 -sticky e
+ grid $widgets(timer01,rl_l) -row 4 -column 1 -sticky e
+ grid $widgets(timer01,rh) -row 3 -column 3 -sticky w
+ grid $widgets(timer01,rl) -row 4 -column 3 -sticky w
+ grid $widgets(timer01,eq3) -row 3 -column 2
+ grid $widgets(timer01,eq4) -row 4 -column 2
+ } {
+ grid forget $widgets(timer01,psc_lbl)
+ grid forget $widgets(timer01,psc_cb)
+ grid forget $widgets(timer01,rh_l)
+ grid forget $widgets(timer01,rl_l)
+ grid forget $widgets(timer01,rh)
+ grid forget $widgets(timer01,rl)
+ grid forget $widgets(timer01,eq3)
+ grid forget $widgets(timer01,eq4)
+ }
+ calculate_timer01_clear_results
+ }
+ {psc_cb} {
+ if {![regexp {^[[:digit:]]{0,3}$} $value]} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {$value > 255} {
+ set calc_in_progress 0
+ return 0
+ }
+
+
+ if {![string equal [$widgets(timer01,$type) get] $value]} {
+ calculate_timer01_clear_results
+ }
+ }
+ }
+
+ after idle "catch {$this calculate_timer01}"
+ set calc_in_progress 0
+ return 1
+ }
+
+ {timer2} {
+ switch -- $type {
+ {time_ent} {
+ if {![regexp {^[0-9]*(\.[0-9]*)?$} $value]} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {![string length $value]} {
+ $widgets(timer2,time_ent) configure -style StringNotFound.TEntry
+
+ } else {
+ $widgets(timer2,time_ent) configure -style TEntry
+ }
+
+
+ if {![string equal [$widgets(timer2,$type) get] $value]} {
+ calculate_timer2_clear_results
+ }
+ }
+ {time_cb} {
+ if {![string equal [$widgets(timer2,$type) get] $value]} {
+ calculate_timer2_clear_results
+ }
+ }
+ {clock_cb} {
+ if {![regexp {^[0-9]*(\.[0-9]*)?$} $value] || [string length $value] > 9} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {![string length $value]} {
+ $widgets(timer2,clock_cb) configure -style SpecCalc_RedBg.TCombobox
+
+ } else {
+ $widgets(timer2,clock_cb) configure -style TCombobox
+ }
+
+
+ if {![string equal [$widgets(timer2,$type) get] $value]} {
+ calculate_timer2_clear_results
+ }
+ }
+ {clock_type_cb} {
+ if {![string equal [$widgets(timer2,$type) get] $value]} {
+ calculate_timer2_clear_results
+ }
+ }
+ {mode_cb} {
+ if {![string equal [$widgets(timer2,$type) get] $value]} {
+ calculate_timer2_clear_results
+ }
+ }
+ }
+
+ after idle "catch {$this calculate_timer2}"
+ set calc_in_progress 0
+ return 1
+ }
+ {clk_timer2} {
+ switch -- $type {
+ {clk_freq} {
+ if {![regexp {^[0-9]*(\.[0-9]*)?$} $value]} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {![string length $value]} {
+ $widgets(timer2,clk_freq) configure -style StringNotFound.TEntry
+
+ } else {
+ $widgets(timer2,clk_freq) configure -style TEntry
+ }
+ }
+ {clk_fosc} {
+ if {![regexp {^[0-9]*(\.[0-9]*)?$} $value]} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {![string length $value]} {
+ $widgets(timer2,clk_fosc) configure -style StringNotFound.TEntry
+
+ } else {
+ $widgets(timer2,clk_fosc) configure -style TEntry
+ }
+ }
+ {clk_x2_cb} {
+ }
+ }
+
+ after idle "catch {$this calculate_timer2_clk}"
+ set calc_in_progress 0
+ return 1
+ }
+ {spi} {
+ switch -regexp $type -- {
+ {double_chb} {
+ }
+ {(sck_ent00)|(sck_ent01)|(sck_ent10)|(sck_ent11)} {
+ if {![regexp {^[0-9]*(\.[0-9]*)?$} $value]} {
+ set calc_in_progress 0
+ return 0
+
+ } elseif {![string length $value]} {
+ $widgets(spi,$type) configure -style StringNotFound.TEntry
+
+ } else {
+ $widgets(spi,$type) configure -style TEntry
+ }
+ }
+ }
+
+ if {[string length $value]} {
+ $this calculate_spi $type $value
+ }
+
+ set calc_in_progress 0
+ return 1
+ }
+
+ }
+
+ set calc_in_progress 0
+ return 1
+ }
+
+ ## Show functional diagram of something
+ # @parm String section - Section ID
+ # @parm String which - More specific ID
+ # @return void
+ public method show_diagram {section which} {
+ switch -- $section {
+ {timer01} {
+ switch -- [$widgets(timer01,mode_cb) current] {
+ 0 {
+ set title [mc "Timer 0/1 in mode 0"]
+ if {[subst "\${::SpecCalc::spec_chb_$obj_idx}"]} {
+ set image {timer_01_0e}
+ } {
+ set image {timer_01_0}
+ }
+ }
+ 1 {
+ set title [mc "Timer 0/1 in mode 1"]
+ if {[subst "\${::SpecCalc::spec_chb_$obj_idx}"]} {
+ set image {timer_01_1e}
+ } {
+ set image {timer_01_1}
+ }
+ }
+ 2 {
+ set title [mc "Timer 0/1 in mode 2"]
+ if {[subst "\${::SpecCalc::spec_chb_$obj_idx}"]} {
+ set image {timer_01_2e}
+ } {
+ set image {timer_01_2}
+ }
+ }
+ }
+ }
+ {timer2} {
+ set image {timer2_updown}
+ set title [mc "Timer 2 as up/down counter"]
+ }
+ {uart} {
+ switch -- $which {
+ {0} {
+ set image {timer_brg}
+ set title [mc "Timer 1/2 as UART baud rate generator"]
+ }
+ {1} {
+ set image {timer_brg}
+ set title [mc "Timer 1/2 as UART baud rate generator"]
+ }
+ {2} {
+ set image {ibrg_brg}
+ set title [mc "Internal baud rate generator"]
+ }
+ default {
+ return
+ }
+ }
+ }
+ }
+
+ set dlg [toplevel .spec_calc_diagram_$diagram_counter -class [mc "Diagram or formula"] -bg {#EEEEEE}]
+ pack [label $dlg.image \
+ -image [image create photo -format png -file "${::LIB_DIRNAME}/../icons/other/$image.png"]
+ ] -fill both
+
+ wm title $dlg $title
+ wm iconphoto $dlg ::ICONS::16::info
+ wm resizable $dlg 0 0
+
+ incr diagram_counter
+ }
+}
diff --git a/lib/utilities/symbol_viewer.tcl b/lib/utilities/symbol_viewer.tcl
new file mode 100755
index 0000000..3df57b4
--- /dev/null
+++ b/lib/utilities/symbol_viewer.tcl
@@ -0,0 +1,837 @@
+#!/usr/bin/tclsh
+# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net )
+
+############################################################################
+# Copyright (C) 2007-2009 by Martin Ošmera #
+# martin.osmera@gmail.com #
+# #
+# 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. #
+############################################################################
+
+# --------------------------------------------------------------------------
+# DESCRIPTION
+# Implements assembly language symbols viewer (from code listing)
+# --------------------------------------------------------------------------
+
+class SymbolViewer {
+ ## Class variables
+ # Int: Counter of object intances
+ common count 0
+ # Font: Just normal font used in the table
+ common normal_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -15 \
+ -weight normal \
+ ]
+ # Font: Bold font (the same size as $normal_font)
+ common bold_font [font create \
+ -family $::DEFAULT_FIXED_FONT \
+ -size -15 \
+ -weight bold \
+ ]
+ # Dialog configuration
+ common config_list $::CONFIG(SYMBOL_VIEWER_CONFIG)
+
+ ## Private object variables
+ private variable obj_idx ;# Int: Current object number
+ private variable symbol_table_data {} ;# List: Data loaded from the code listing (see func. open_file)
+ private variable current_line {} ;# List: Current line data (selected lide in the table)
+ private variable opened_file {} ;# String: Full file name of the currently loaded code listing file
+ private variable win ;# Widget: Dialog window
+ private variable menu ;# Widget: Popup menu for the text widget
+ private variable main_frame ;# Widget: Dialog main frame
+ private variable reload_but ;# Widget: Button "Reload"
+ private variable search_entry ;# Widget: EntryBox "Search"
+ private variable clear_but ;# Widget: Button "Clear search entrybox"
+ private variable status_bar_lbl ;# Widget: Status bar label widget
+ private variable opened_file_lbl ;# Widget: Label on statusbar showing name of currently opened file
+ private variable text_widget ;# Widget: Text widget containing the table of symbols
+
+ constructor {} {
+ # Create dialog window
+ set win [toplevel .symbolviewer$count -class {Defined symbols} -bg {#EEEEEE}]
+ set obj_idx $count
+ incr count
+
+ # Create dialog GUI
+ set main_frame [frame $win.main_frame]
+ create_gui ;# Create widgets
+ create_menus ;# Create menus
+ create_tags ;# Create text tags
+ create_bindings ;# Set event bindings
+
+ # Set values for checkboxes in panel "Display"
+ set i 0
+ foreach name {DATA IDATA XDATA CODE BIT Number used unused} {
+ set ::SymbolViewer::display_${obj_idx}($name) [lindex $config_list $i]
+ incr i
+ }
+ # Set values for radiobuttons in panel "Sort by"
+ set ::SymbolViewer::sort_by_${obj_idx} [lindex $config_list $i]
+ incr i
+ set ::SymbolViewer::sort_by_order_${obj_idx} [lindex $config_list $i]
+ incr i
+
+ # Finalize GUI
+ pack $main_frame -fill both -expand 1 -padx 5 -pady 5
+ bindtags $win [list $win Toplevel all .]
+ focus -force $search_entry
+
+ # Configure dialog window
+ wm iconphoto $win ::ICONS::16::symbol
+ wm title $win [mc "Assembly symbol table - MCU 8051 IDE"]
+ wm minsize $win 620 350
+ wm protocol $win WM_DELETE_WINDOW "$this close_window"
+ catch {
+ wm geometry $win [lindex $config_list $i]
+ }
+
+ # Set ...
+ incr i
+ set ::SymbolViewer::display_${obj_idx}(Special) [lindex $config_list $i]
+ if {[subst "\$::SymbolViewer::display_${obj_idx}(Special)"] == {}} {
+ set ::SymbolViewer::display_${obj_idx}(Special) 1
+ }
+ }
+
+ destructor {
+ # Save tool configuration
+ if {[llength $config_list] < 12} {
+ set config_list [list {} {} {} {} {} {} {} {} {} {} {} {}]
+ }
+ set i 0
+ foreach name {DATA IDATA XDATA CODE BIT Number used unused} {
+ lset config_list $i [subst "\$::SymbolViewer::display_${obj_idx}($name)"]
+ incr i
+ }
+ lset config_list $i [subst "\$::SymbolViewer::sort_by_${obj_idx}"]
+ incr i
+ lset config_list $i [subst "\$::SymbolViewer::sort_by_order_${obj_idx}"]
+ incr i
+ lset config_list $i [wm geometry $win]
+ incr i
+ lset config_list $i [subst "\$::SymbolViewer::display_${obj_idx}(Special)"]
+
+ # Clean up
+ unset ::SymbolViewer::sort_by_${obj_idx}
+ unset ::SymbolViewer::sort_by_order_${obj_idx}
+ array unset ::SymbolViewer::display_${obj_idx}
+
+ # Remove dialog window
+ destroy $win
+ }
+
+ ## Create menus
+ # @return void
+ private method create_menus {} {
+ ## Create text widget popup menu
+ set menu [menu $text_widget.menu]
+ $menu add command -label [mc "Copy symbol name"] -compound left \
+ -underline 12 -command "$this text_copy_proc name"
+ $menu add command -label [mc "Copy hex value"] -compound left \
+ -underline 5 -command "$this text_copy_proc hex"
+ $menu add command -label [mc "Copy dec value"] -compound left \
+ -underline 5 -command "$this text_copy_proc dec"
+ $menu add separator
+ $menu add command -label [mc "Copy line"] -compound left \
+ -underline 1 -command "$this text_copy_proc line" \
+ -image ::ICONS::16::editcopy -accelerator {Ctrl+C}
+ }
+
+ ## Set event bindings for window widgets
+ # @return void
+ private method create_bindings {} {
+ bind $text_widget <ButtonRelease-3> "$this invoke_popup_menu %X %Y %x %y; break"
+ bind $text_widget <<Selection>> "false_selection $text_widget; break"
+ bind $text_widget <Button-1> "focus %W; $this select_line %x %y"
+ bind $text_widget <Key-Down> "$this key_down"
+ bind $text_widget <Key-Up> "$this key_up"
+ bind $text_widget <Control-Key-c> "$this text_copy_proc line; break"
+
+ bind $win <Control-Key-o> "$this open_file_dialog; break"
+ bind $win <Key-F5> "$this reload; break"
+ bind $win <Control-Key-q> "$this close_window; break"
+
+ bindtags $search_entry [list $search_entry TEntry $win all .]
+ bindtags $text_widget [list $text_widget Text $win all .]
+ }
+
+ ## Create text tags
+ # @return void
+ private method create_tags {} {
+ $text_widget tag configure type_DATA -foreground {#00DD00}
+ $text_widget tag configure type_IDATA -foreground {#0000DD}
+ $text_widget tag configure type_XDATA -foreground {#DD0000}
+ $text_widget tag configure type_CODE -foreground {#00DDDD}
+ $text_widget tag configure type_BIT -foreground {#AA8800}
+ $text_widget tag configure type_Special -foreground {#AA00FF}
+ $text_widget tag configure type_Number -foreground {#DD00DD}
+ $text_widget tag configure used_YES -foreground {#00DD00}
+ $text_widget tag configure used_NO -foreground {#DD0000}
+ $text_widget tag configure tag_sel -background {#DDDDDD} -font $bold_font
+ $text_widget tag configure nth_row -background {#EEEEEE}
+
+ $text_widget tag raise tag_sel nth_row
+ }
+
+ ## Create window widgets
+ # @return void
+ private method create_gui {} {
+ # Create window frames
+ set top_frame [frame $main_frame.top_frame] ;# Button "Open"+"Reload" + Search bar
+ set middle_frame [frame $main_frame.middle_frame] ;# Table of symbols
+ set bottom_frame [frame $main_frame.bottom_frame] ;# Display options
+ set sbar_frame [frame $main_frame.sbar_frame] ;# Status bar
+
+ ## Create status bar
+ set status_bar_lbl [label $sbar_frame.main_lbl \
+ -justify left -anchor w \
+ ]
+ set opened_file_lbl [label $sbar_frame.opened_file_lbl -fg {#0000DD}]
+ pack $status_bar_lbl -fill x -side left
+ pack $opened_file_lbl -side right -after $status_bar_lbl
+
+ ## Create top frame
+ # Button "Open file"
+ pack [ttk::button $top_frame.open_but \
+ -image ::ICONS::16::fileopen \
+ -text [mc "Open *.LST"] \
+ -compound left \
+ -command "$this open_file_dialog" \
+ ] -side left
+ DynamicHelp::add $top_frame.open_but \
+ -text [mc "Load table of symbols from list file (*.lst)\n\tOnly for: ASEM-51, MCU8051IDE and ASM51"]
+ set_locat_status_tip $top_frame.open_but [mc "Open code listing"]
+ # Button "Reload"
+ set reload_but [ttk::button $top_frame.reload_but \
+ -image ::ICONS::16::reload \
+ -text [mc "Reload"] \
+ -compound left \
+ -command "$this reload" \
+ -state disabled \
+ ]
+ pack $reload_but -side left -padx 5
+ set_locat_status_tip $reload_but [mc "Reload opened file"]
+ ## Create search bar
+ set top_r_frame [frame $top_frame.right_frame]
+ # - Label
+ pack [label $top_r_frame.search_lbl \
+ -text [mc "Search:"] \
+ ] -side left
+ # - Entry
+ set search_entry [ttk::entry $top_r_frame.search_entry \
+ -validate all \
+ -validatecommand "$this search_validate %P" \
+ ]
+ DynamicHelp::add $search_entry \
+ -text [mc "Search for symbol by its name or value"]
+ set_locat_status_tip $search_entry [mc "Search for symbol"]
+ pack $search_entry -side left
+ # - Button
+ set clear_but [ttk::button $top_r_frame.clear_but \
+ -state disabled \
+ -style Flat.TButton \
+ -image ::ICONS::16::clear_left \
+ -command "$search_entry delete 0 end" \
+ ]
+ set_locat_status_tip $clear_but [mc "Clear search entry box"]
+ pack $clear_but -side left
+ pack $top_r_frame -side right
+
+ ## Create table of symbols
+ set middle_l_frame [frame $middle_frame.left_frame -bd 1 -relief sunken]
+ pack [label $middle_l_frame.header_lbl \
+ -bg white -padx 0 -pady 0 -width 0 \
+ -text [mc "Symbol\t\t\t\tType\tHEX\tDEC\tUsed"] \
+ -font $bold_font -anchor w -justify left \
+ ] -fill x
+ pack [ttk::separator $middle_l_frame.sep \
+ -orient horizontal \
+ ] -fill x
+ set text_widget [text $middle_l_frame.text \
+ -bg white -width 0 -height 0 -bd 0 -relief flat \
+ -yscrollcommand "$middle_frame.scrollbar set" \
+ -cursor left_ptr -font $normal_font \
+ -state disabled \
+ ]
+ pack $text_widget -fill both -expand 1
+
+ pack $middle_l_frame -side left -fill both -expand 1
+ pack [ttk::scrollbar $middle_frame.scrollbar \
+ -orient vertical -command "$text_widget yview" \
+ ] -fill y -side right -after $middle_l_frame
+
+ ## Create display options
+ set main_opt_frame [ttk::labelframe \
+ $bottom_frame.main_opt_frm \
+ -text [mc "Display"] \
+ -padding 10 \
+ ]
+ set row 0
+ set col 0
+ set i 0
+ foreach name {DATA IDATA XDATA CODE BIT Number Special} {
+ if {$col > 2} {
+ set col 0
+ incr row
+ }
+ grid [checkbutton $main_opt_frame.cb_x_$i \
+ -text $name -onvalue 1 -offvalue 0 \
+ -variable ::SymbolViewer::display_${obj_idx}($name) \
+ -command "$this refresh" \
+ ] -sticky w -row $row -column $col
+ incr i
+ incr col
+ }
+ incr row
+ grid [ttk::separator $main_opt_frame.sep \
+ -orient horizontal \
+ ] -sticky we -row $row -column 0 -columnspan 3
+ incr row
+ grid [checkbutton $main_opt_frame.cb_x_us \
+ -text [mc "Used symbols"] -onvalue 1 -offvalue 0 \
+ -variable ::SymbolViewer::display_${obj_idx}(used) \
+ -command "$this refresh" \
+ ] -sticky w -row $row -column 0 -columnspan 3
+ incr row
+ grid [checkbutton $main_opt_frame.cb_x_uus \
+ -text [mc "Unused symbols"] -onvalue 1 -offvalue 0 \
+ -variable ::SymbolViewer::display_${obj_idx}(unused) \
+ -command "$this refresh" \
+ ] -sticky w -row $row -column 0 -columnspan 3
+ pack $main_opt_frame -side left -fill y -anchor n -padx 5
+
+ # Create frame "Sort by"
+ set sort_by_frame [ttk::labelframe \
+ $bottom_frame.sort_by_frm \
+ -text [mc "Sort by"] \
+ -padding 10 \
+ ]
+ set row 0
+ set col 0
+ set i 0
+ foreach name {{Symbol name} Type {Hex value} {Dec value} {Usage}} {
+ if {$col > 2} {
+ set col 0
+ incr row
+ }
+ grid [radiobutton $sort_by_frame.rb_x_$i \
+ -text $name -value $i \
+ -variable ::SymbolViewer::sort_by_${obj_idx} \
+ -command "$this refresh" \
+ ] -sticky w -row $row -column $col
+ incr i
+ incr col
+ }
+ incr row
+ grid [ttk::separator $sort_by_frame.sep \
+ -orient horizontal \
+ ] -sticky we -row $row -column 0 -columnspan 3
+ incr row
+ grid [radiobutton $sort_by_frame.rb_x_inc \
+ -text [mc "Incremental order"] -value 0 \
+ -variable ::SymbolViewer::sort_by_order_${obj_idx} \
+ -command "$this refresh" \
+ ] -sticky w -row $row -column 0 -columnspan 3
+ incr row
+ grid [radiobutton $sort_by_frame.rb_x_dec \
+ -text [mc "Decremental order"] -value 1 \
+ -variable ::SymbolViewer::sort_by_order_${obj_idx} \
+ -command "$this refresh" \
+ ] -sticky w -row $row -column 0 -columnspan 3
+ pack $sort_by_frame -side left -fill y -anchor n -padx 10
+
+ # Pack window frames
+ pack $top_frame -fill x
+ pack $middle_frame -fill both -expand 1 -pady 7
+ pack $bottom_frame -fill x
+ pack $sbar_frame -fill x
+ }
+
+ ## Set local statusbar tip
+ # @parm Widget widget - Target widget
+ # @parm String text - Statusbar tip itselft
+ # @return void
+ private method set_locat_status_tip {widget text} {
+ bind $widget <Enter> [list $status_bar_lbl configure -text $text]
+ bind $widget <Leave> [list $status_bar_lbl configure -text {}]
+ }
+
+ ## Close dialog window
+ # @return void
+ public method close_window {} {
+ ::itcl::delete object $this
+ }
+
+ ## Invoke file selection dialog to load a new table of symbols for LST file
+ # @return void
+ public method open_file_dialog {} {
+ # Determinate initial directory
+ if {$opened_file == {}} {
+ if {${::X::project_menu_locked}} {
+ set directory {~}
+ } {
+ set directory [${::X::actualProject} cget -projectPath]
+ }
+ } {
+ set directory [file dirname $opened_file]
+ }
+
+ # Invoke project selection dialog
+ KIFSD::FSD ::fsd \
+ -title [mc "Load symbol table - MCU 8051 IDE"] \
+ -directory $directory -master $win \
+ -defaultmask 0 -multiple 0 -filetypes {
+ {{Code listing} {*.lst} }
+ {{All files} {*} }
+ }
+
+ # Open the selected after press of OK button
+ ::fsd setokcmd "
+ ::fsd deactivate
+ $this open_file 0 \[::fsd get\]"
+
+ ::fsd activate ;# Activate the dialog
+ }
+
+ ## Reload opened file if any
+ # @return void
+ public method reload {} {
+ open_file 0 $opened_file
+ }
+
+ ## Try to open LST file and load table of symbols from it
+ # @parm Bool ignore_errors - Ignore erros while opening the file
+ # @parm String filename - Name of file to load
+ # @return void
+ public method open_file {ignore_errors filename} {
+ if {[catch {
+ set file [open $filename r]
+ }]} {
+ if {!$ignore_errors} {
+ tk_messageBox \
+ -parent $win \
+ -type ok \
+ -icon warning \
+ -title [mc "Invalid file"] \
+ -message [mc "Unable to use selected file. Please check your permissions. File: '%s'" $filename]
+ }
+ return
+ }
+
+ # Parse file
+ set symbol_table_data {}
+ set read_line 0
+ set line {}
+ set name {}
+ set addr {}
+ set type {}
+ set used 1
+ while {![eof $file]} {
+ set used 1
+ set line [gets $file]
+
+ # Empty line - stop reading
+ if {![string length [string trimright $line "  \f"]]} {
+ set read_line 0
+ continue
+
+ # MCU 8051 IDE Assembler symbol table
+ } elseif {![string first {SYMBOL TABLE:} $line]} {
+ set read_line 1
+ continue
+
+ # ASEM-51 Assembler symbol table
+ } elseif {![string first {------------------------------------------------------------} $line]} {
+ set read_line 2
+ continue
+ }
+
+
+ # MCU 8051 IDE Assembler symbol
+ if {$read_line == 1} {
+ if {![regexp {^(\?\?)?\w+} $line name]} {
+ continue
+ }
+ if {![regexp {[\w\s]+$} $line line]} {
+ continue
+ }
+ set type [lindex $line 0]
+ if {$type == {S}} {
+ set addr [lindex $line end]
+ } {
+ set addr [string replace [lindex $line 2] end end]
+ }
+
+ # Determinate whether symbol is used
+ if {[lindex $line end-1] == {NOT} || [lindex $line end-2] == {NOT}} {
+ set used 0
+ }
+
+ # ASEM-51 Assembler symbol
+ } elseif {$read_line == 2} {
+ # Remove dangerous characters
+ regsub -all {\{\}\"\"} $line {} line
+
+ if {[llength $line] < 4} {
+ set used 0
+ }
+ set addr [lindex $line 2]
+ set name [lindex $line 0]
+ set type [string index [lindex $line 1] 0]
+
+ # Hexadecimal address must be 4 characters long
+ if {!($type == {S} || $type == {R})} {
+ set addr "[string repeat 0 [expr {4 - [string length $addr]}]]$addr"
+ }
+
+ # This line is not a part of symbol table
+ } else {
+ continue
+ }
+
+ # Address must be a valid hexadecimal value
+ if {![string is xdigit -strict $addr] && !($type == {S} || $type == {R})} {
+ continue
+ }
+
+ # Create new register watch
+ if {[string length $name] > 31} {
+ set name [string range $name 0 27]
+ append name {...}
+ }
+
+ if {$type == {S} || $type == {R}} {
+ lappend symbol_table_data [list $name $type $addr {0} $used]
+ } {
+ lappend symbol_table_data [list $name $type $addr [expr "0x$addr"] $used]
+ }
+ }
+
+ set opened_file $filename
+ $reload_but configure -state normal
+ $opened_file_lbl configure -text [file tail $filename]
+ close $file
+ refresh
+ }
+
+ ## Sort list of loaded symbols acording to user settings
+ # @return void
+ private method sort_table {} {
+ if {[subst "\$::SymbolViewer::sort_by_order_${obj_idx}"]} {
+ set order {-decreasing}
+ } {
+ set order {-increasing}
+ }
+ set index [subst "\$::SymbolViewer::sort_by_${obj_idx}"]
+ if {$index == 3} {
+ set type {-integer}
+ } {
+ set type {-dictionary}
+ }
+
+ set symbol_table_data [lsort $order $type -index $index $symbol_table_data]
+ }
+
+ ## Filter record with the given type and use flag
+ # @parm Char type - Record type
+ # @parm Bool used - Used flag
+ # @return List - {$long_type $long_used} or {0}
+ private method filter_record {type used} {
+ # Adjust symbol type
+ switch -- $type {
+ {D} {set type {DATA}}
+ {I} {set type {IDATA}}
+ {X} {set type {XDATA}}
+ {C} {set type {CODE}}
+ {B} {set type {BIT}}
+ {N} {set type {Number}}
+ {S} {set type {Special}}
+ {R} {set type {Special}}
+ }
+ if {![subst "\$::SymbolViewer::display_${obj_idx}($type)"]} {
+ return 0
+ }
+
+ # Adjust flag USED
+ if {$used} {
+ if {![subst "\$::SymbolViewer::display_${obj_idx}(used)"]} {
+ return 0
+ }
+ set used {YES}
+ } {
+ if {![subst "\$::SymbolViewer::display_${obj_idx}(unused)"]} {
+ return 0
+ }
+ set used {NO}
+ }
+
+ return [list $type $used]
+ }
+
+ ## Refresh table of symbols (reload contents of the text widget from $symbol_table_data)
+ # @return void
+ public method refresh {} {
+ # There must be something loaded
+ if {$opened_file == {}} {
+ return
+ }
+
+ # Save data of the selected line
+ if {$current_line != {}} {
+ set current_line [$text_widget get $current_line.0 [list $current_line.0 lineend]]
+ set current_line [list \
+ [lindex $current_line 0] [lindex $current_line 1] \
+ [lindex $current_line 2] [lindex $current_line 3] \
+ [lindex $current_line 4] \
+ ]
+
+ lset current_line 1 [string index [lindex $current_line 1] 0]
+ if {[lindex $current_line 4] == {YES}} {
+ lset current_line 4 1
+ } {
+ lset current_line 4 0
+ }
+ }
+
+ # Sort loaded table of symbols
+ sort_table
+
+ # Clear the text widget
+ $text_widget configure -state normal
+ $text_widget delete 0.0 end
+
+ # Load table of symbols to the text widget
+ set idx 0 ;# Int: Symbol number (just index in the table, nothing more)
+ set name {} ;# String: Symbol name defined in source code
+ set type {} ;# Char: Symbol type (see func. code)
+ set hexv {} ;# String: Hexadecimal symbol value
+ set decv {} ;# Int: Decimal symbol value
+ set used {} ;# Bool: Symbol used in source code
+ set cur_found 0 ;# Bool: Current line found
+ foreach symbol_def $symbol_table_data {
+ set name [lindex $symbol_def 0]
+ set type [lindex $symbol_def 1]
+ set hexv [lindex $symbol_def 2]
+ set decv [lindex $symbol_def 3]
+ set used [lindex $symbol_def 4]
+
+ # Filter record
+ set used [filter_record $type $used]
+ if {$used == {0}} {
+ continue
+ }
+ set type [lindex $used 0]
+ set used [lindex $used 1]
+
+ # Insert new record into the table
+ $text_widget insert insert $name
+ $text_widget insert insert [string repeat { } [expr {32 - [string length $name]}]]
+ $text_widget insert insert $type
+ $text_widget insert insert [string repeat { } [expr {8 - [string length $type]}]]
+ $text_widget tag add type_${type} insert-8c insert
+ if {$type == {Special}} {
+ $text_widget insert insert $hexv
+ $text_widget insert insert [string repeat { } [expr {16 - [string length $hexv]}]]
+ } {
+ $text_widget insert insert $hexv
+ $text_widget insert insert { }
+ $text_widget insert insert $decv
+ $text_widget insert insert [string repeat { } [expr {8 - [string length $decv]}]]
+ }
+ $text_widget insert insert $used
+ $text_widget tag add used_${used} insert-3c insert
+ $text_widget insert insert "\n"
+ if {!($idx % 3)} {
+ $text_widget tag add nth_row insert-1l insert
+ }
+
+ # Try to find the selected line
+ if {!$cur_found && [string equal $current_line $symbol_def]} {
+ set cur_found 1
+ set current_line $idx
+ incr current_line
+ }
+
+ incr idx
+ }
+
+ # Restore selection
+ if {$cur_found} {
+ $text_widget tag add tag_sel $current_line.0 $current_line.0+1l
+ $text_widget see $current_line.0
+ } {
+ set current_line {}
+ }
+
+ # Disable the text widget and clear search entrybox
+ $text_widget configure -state disabled
+ $search_entry delete 0 end
+ }
+
+ ## Select line in the table (event: <Button-1>)
+ # @parm Int x - Relative X coordinate
+ # @parm Int y - Relative Y coordinate
+ # @return void
+ public method select_line {x y} {
+ set current_line [expr {int([$text_widget index @$x,$y])}]
+ if {$current_line == int([$text_widget index end])-1} {
+ set current_line {}
+ return
+ }
+ $search_entry delete 0 end
+ $text_widget tag remove tag_sel 0.0 end
+ $text_widget tag add tag_sel $current_line.0 $current_line.0+1l
+ }
+
+ ## Search entrybox validator
+ # @parm String string - String to validate (search for)
+ # @return Bool - always 1
+ public method search_validate {string} {
+ # Not empty string
+ if {[string length $string]} {
+ set string [string tolower [string trimleft $string 0]]
+ $clear_but configure -state normal
+ # Empty string -> abort
+ } {
+ $search_entry configure -style TEntry
+ $clear_but configure -state disabled
+ return 1
+ }
+
+ # Search in the table
+ set i 0
+ set found_idx -1
+ foreach symbol_def $symbol_table_data {
+ set name [string tolower [lindex $symbol_def 0]]
+ set type [lindex $symbol_def 1]
+ set hexv [string trimleft [string tolower [lindex $symbol_def 2]] 0]
+ set decv [lindex $symbol_def 3]
+ set used [lindex $symbol_def 4]
+
+ if {[filter_record $type $used] == {0}} {
+ continue
+ }
+
+ if {![string first $string $name]} {
+ set found_idx $i
+ break
+ }
+ if {![string first $string $hexv]} {
+ set found_idx $i
+ break
+ }
+ if {![string first $string $decv]} {
+ set found_idx $i
+ break
+ }
+
+ incr i
+ }
+
+ set current_line {}
+ $text_widget tag remove tag_sel 0.0 end
+
+ # String not found
+ if {$found_idx == -1} {
+ $search_entry configure -style StringNotFound.TEntry
+ # String found
+ } {
+ set current_line [expr {$found_idx + 1}]
+ $text_widget tag add tag_sel $current_line.0 $current_line.0+1l
+ $text_widget see $current_line.0
+ $search_entry configure -style StringFound.TEntry
+ }
+
+ return 1
+ }
+
+ ## Event handler of the text widget <Key-Up>
+ # Select line above the currently selected one
+ # @return void
+ public method key_up {} {
+ if {$current_line == {} || $current_line < 2} {
+ return
+ }
+ incr current_line -1
+ $text_widget tag remove tag_sel 0.0 end
+ $text_widget tag add tag_sel $current_line.0 $current_line.0+1l
+ $search_entry delete 0 end
+ }
+
+ ## Event handler of the text widget <Key-Down>
+ # Select line below the currently selected one
+ # @return void
+ public method key_down {} {
+ if {$current_line == {} || $current_line >= ([$text_widget index end] - 2)} {
+ return
+ }
+ incr current_line
+ $text_widget tag remove tag_sel 0.0 end
+ $text_widget tag add tag_sel $current_line.0 $current_line.0+1l
+ $search_entry delete 0 end
+ }
+
+ ## Invoke text widget popup menu
+ # @parm Int X - Absolute mouse pointer X coordinate
+ # @parm Int Y - Absolute mouse pointer X coordinate
+ # @parm Int x - Relative mouse pointer X coordinate
+ # @parm Int y - Relative mouse pointer X coordinate
+ # @return void
+ public method invoke_popup_menu {X Y x y} {
+ select_line $x $y
+ if {$current_line == {}} {
+ set state disabled
+ } {
+ set state normal
+ }
+ foreach entry {{Copy symbol name} {Copy hex value} {Copy dec value} {Copy line}} {
+ $menu entryconfigure [::mc $entry] -state $state
+ }
+ tk_popup $menu $X $Y
+ }
+
+ ## Copy piece of the table into clipboard
+ # @parm Char mode - What to copy
+ # name - Symbol name
+ # hex - Symbol hexadecimal value
+ # dec - Symbol decimal value
+ # line - Whole symbol definition
+ # @return void
+ public method text_copy_proc {mode} {
+ switch -- $mode {
+ {name} {
+ set s 0
+ set e 31
+ }
+ {hex} {
+ set s 39
+ set e 44
+ }
+ {dec} {
+ set s 47
+ set e 52
+ }
+ {line} {
+ set s 0
+ set e 63
+ }
+ }
+
+ clipboard clear
+ clipboard append [string trim [$text_widget get $current_line.$s $current_line.$e]]
+ }
+}
diff --git a/make-launcher b/make-launcher
new file mode 100755
index 0000000..3eba053
--- /dev/null
+++ b/make-launcher
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Copyright (C) Martin Ošmera <martin.osmera@gmail.com>
+# Licence: GPL v2
+# Version: 1.1
+# Homepage: http://sourceforge.net/projects/mcu8051ide
+
+# Create launcher for MCU 8051 IDE
+
+# Place the created file into directory /usr/bin and just run mcu8051ide
+# Typical usage:
+# ./make-launcher --path-to-lib=/usr/share/mcu8051ide/lib
+
+
+print_help() {
+ echo "Create launcher for MCU 8051 IDE"
+ echo "Usage:"
+ echo "./make-launcher --path-to-lib=path_to_lib_directory"
+ exit
+}
+
+create_launcher() {
+cat > mcu8051ide << EOF
+#!/bin/sh
+cd $value
+exec tclsh8.5 main.tcl "\$@" || echo "Tcl 8.5 is not available on the system. Trying another version ..." && exec tclsh main.tcl || echo "FATAL ERROR: Tcl is not installed on the system! MCU 8051 IDE cannot run without it."
+EOF
+echo "Launcher successfuly created"
+}
+
+
+if [ -z "${1}" ]; then
+ print_help
+fi
+
+
+while [ -n "${1}" ]; do
+
+ key=`echo ${1} | sed -r -e 's/\=[^\=]+//'`
+ value=`echo $(echo ${1} | grep =) | sed -r -e 's/[^\=]+\=//;s/^"//;s/"$//'`
+
+ case "$key" in
+ --path-to-lib)
+ if [ -z $value ]; then
+ echo "Warning invalid value: $value"
+ echo "Using ~ as value"
+ value="~"
+ fi
+ create_launcher
+ chmod 0755 mcu8051ide
+ ;;
+ -h | --help | --usage)
+ print_help
+ ;;
+ *)
+ echo "Unrecognized option: ${1}"
+ ;;
+ esac
+ shift
+done
diff --git a/mcu8051ide.desktop b/mcu8051ide.desktop
new file mode 100644
index 0000000..3b8fa29
--- /dev/null
+++ b/mcu8051ide.desktop
@@ -0,0 +1,21 @@
+[Desktop Entry]
+Categories=Development;
+Comment=Graphical IDE for MCS-51 based microcontrollers
+Comment[en_US]=Graphical IDE for MCS-51 based microcontrollers
+Encoding=UTF-8
+Exec=mcu8051ide
+GenericName=MCU 8051 IDE
+GenericName[en_US]=MCU 8051 IDE
+Icon=mcu8051ide
+MimeType=
+Name=MCU 8051 IDE
+Name[en_US]=MCU 8051 IDE
+StartupNotify=false
+Terminal=false
+TerminalOptions=
+TryExec=mcu8051ide
+Type=Application
+Version=1.0
+X-DCOP-ServiceType=
+X-KDE-SubstituteUID=false
+X-KDE-Username=
diff --git a/mcu8051ide.png b/mcu8051ide.png
new file mode 100644
index 0000000..a528d73
--- /dev/null
+++ b/mcu8051ide.png
Binary files differ
diff --git a/test-lib.sh b/test-lib.sh
new file mode 100755
index 0000000..c3e359a
--- /dev/null
+++ b/test-lib.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# the next line restarts using tclsh \
+exec tclsh "$0" "$@" || echo "0"; exit 1
+
+# --------------------------------------------------------
+# Copyright (C) Martin Ošmera <P16F87504SP@seznam.cz>
+# Licence: GPL
+# Version: 1.0
+# Homepage: http://sourceforge.net/projects/mcu8051ide
+# --------------------------------------------------------
+#
+# Test for presence of a Tcl library
+# Usage:
+# ./test-lib LIBRARY [VERSION]
+#
+# --------------------------------------------------------
+
+if {$argv == {--help}} {
+ puts "Test for presence of Tcl library"
+ puts "Usage:"
+ puts "\t./test-lib LIBRARY [VERSION]"
+}
+
+if {$argc == 2} {
+ if [catch {package require [lindex $argv 0] [lindex $argv 1]}] {
+ puts {0}
+ exit 1
+ }
+} elseif {$argc == 1} {
+ if [catch {package require [lindex $argv 0]}] {
+ puts {0}
+ exit 1
+ }
+} else {
+ puts {0}
+ exit 1
+}
+
+puts {1}
+exit 0
+
diff --git a/translations/README b/translations/README
new file mode 100644
index 0000000..614a416
--- /dev/null
+++ b/translations/README
@@ -0,0 +1 @@
+This directory contains translation files for the MCU 8051 IDE \ No newline at end of file