diff options
Diffstat (limited to 'lib/simulator/simulator.tcl')
-rwxr-xr-x | lib/simulator/simulator.tcl | 1202 |
1 files changed, 1202 insertions, 0 deletions
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 + } +} |