1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
|
#!/usr/bin/tclsh
# Part of MCU 8051 IDE ( http://https://sourceforge.net/projects/mcu8051ide/ )
############################################################################
# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 by Martin Ošmera #
# martin.osmera@gmail.com #
# #
# Copyright (C) 2014 by Moravia Microsystems, s.r.o. #
# 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. #
############################################################################
# >>> File inclusion guard
if { ! [ info exists _ENGINE_EXTERNAL_INTERFACE_MANAGEMENT_TCL ] } {
set _ENGINE_EXTERNAL_INTERFACE_MANAGEMENT_TCL _
# <<< File inclusion guard
# --------------------------------------------------------------------------
# DESCRIPTION
# Part of simulator engine functionality.
#
# --------------------------------------------------------------------------
# EXTERNAL INTERFACE MANAGEMENT PROCEDURES
# --------------------------------------------------------------------------
## Get value of bit X2 in CLKREG/CKCON if available
# @return Bool - X2 value (if unavailable then 0)
public method get_X2 {} {
return $controllers_conf(X2)
}
## Get value of bit SMOD0 in PCON if available
# @return Bool - SMOD0 value (if unavailable then 0)
public method get_SMOD0 {} {
return $controllers_conf(SMOD0)
}
## Set value of bit FE in SCON if available
# @param Bool value - New value for SCON.FE (or SCON.SM0 if FE is not available)
# @return void
public method sim_engine_set_FE {value} {
if {$feature_available(smod0)} {
set controllers_conf(FE) $value
} else {
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 available
# @return Bool - FE value (if unavailable then {})
public method sim_engine_get_FE {} {
if {!$feature_available(smod0)} {
return {}
} else {
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
# @parm Int idx = {} - Index to the array ``run_statistics'', empty string means entire array
# @return List/Int - Array run_statistics converted to list or Int
public method get_run_statistics {{idx {}}} {
if {$idx == {}} {
return [array get run_statistics]
} else {
return $run_statistics($idx)
}
}
## 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_available(iph)} {
return 3
} else {
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_available(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
} else {
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
} else {
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
if {$::GUI_AVAILABLE} {
$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 {$::GUI_AVAILABLE} {
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
} else {
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_available(uart)} {lappend result RI TI}
if {$feature_available(spi)} {lappend result SPIF}
if {$feature_available(t2)} {lappend result TF2 EXF2}
if {$feature_available(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 hex editor
foreach reg $eeprom_prev {
::X::sync_eeprom_clear_bg_hg [lindex $reg 0] $this
}
# Adjust engine configuration
if {$::GUI_AVAILABLE} {
$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)
} else {
return {}
}
}
## Determinate list of all unreachable breakpoints in the code
# @return List - { { file_number line_number } ... }
public method simulator_getInvalidBreakpoints {} {
# Local variables
set ln 0 ;# Int: Line number
set fn 0 ;# Int: File number
set idx 0 ;# Index in list of breakpoints
set list_of_breakpoints [list]
foreach {f b} [array get breakpoints] {
foreach l $b {
lappend list_of_breakpoints [list $f $l]
}
}
foreach ln_fn [array names line2PC] {
scan $ln_fn {%d,%d} ln fn
set idx [lsearch -ascii -exact $list_of_breakpoints [list $fn $ln]]
if {$idx != -1} {
set list_of_breakpoints [lreplace $list_of_breakpoints $idx $idx]
}
}
set list_of_breakpoints [lsort -integer -index 0 $list_of_breakpoints]
set list_of_breakpoints [lsort -integer -index 1 $list_of_breakpoints]
return $list_of_breakpoints
}
## 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_available(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_available(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
if {$::GUI_AVAILABLE} {
$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 address 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
} else {
set controllers_conf(WRTINH) 0
}
}
}
# Adjust internal engine configuration
evaluate_sfr $addr 0
set stepback_ena $foo
# If address 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 enough program memory to load this program. Simulator will work but the loaded code is incomplete" [$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 Bool - 1 == Success; 0 == Failure
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 MCU clock frequency
# @return - clock frequency in kHz
public method getEngineClock {} {
return $clock_kHz
}
## 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
} else {
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 microseconds
set ms [expr {$ms / 1000}] ;# Number of miliseconds
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 {0} [expr {3 - $len}]]$ns"
} else {
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"
} else {
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"
} else {
set ms_s $ms
}
# Adjust seconds and minutes strings
if {[string length $s] == 1} {
set s_s " $s"
} else {
set s_s $s
}
if {[string length $m] == 1} {
set m_s " $m"
} else {
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}.${ns_s}µs"
}
# Done ...
return [string trim $result]
}
# >>> File inclusion guard
}
# <<< File inclusion guard
|