summaryrefslogtreecommitdiff
path: root/lib/simulator/engine/engine_external_interface_management.tcl
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 /lib/simulator/engine/engine_external_interface_management.tcl
Import Upstream version 1.3.7
Diffstat (limited to 'lib/simulator/engine/engine_external_interface_management.tcl')
-rwxr-xr-xlib/simulator/engine/engine_external_interface_management.tcl1115
1 files changed, 1115 insertions, 0 deletions
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]
+}