summaryrefslogtreecommitdiff
path: root/lib/simulator
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
Import Upstream version 1.3.7
Diffstat (limited to 'lib/simulator')
-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
21 files changed, 17761 insertions, 0 deletions
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
+}