diff options
author | Andrej Shadura <andrewsh@debian.org> | 2018-05-08 15:59:29 +0200 |
---|---|---|
committer | Andrej Shadura <andrewsh@debian.org> | 2018-05-08 15:59:29 +0200 |
commit | 5b8466f7fae0e071c0f4eda13051c93313910028 (patch) | |
tree | 7061957f770e5e245ba00666dad912a2d44e7fdc /lib/pale/pale.tcl |
Import Upstream version 1.3.7
Diffstat (limited to 'lib/pale/pale.tcl')
-rwxr-xr-x | lib/pale/pale.tcl | 991 |
1 files changed, 991 insertions, 0 deletions
diff --git a/lib/pale/pale.tcl b/lib/pale/pale.tcl new file mode 100755 index 0000000..3b4b61c --- /dev/null +++ b/lib/pale/pale.tcl @@ -0,0 +1,991 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 by Martin Ošmera # +# martin.osmera@gmail.com # +# # +# This program is free software; you can redistribute it and#or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +############################################################################ + + +# -------------------------------------------------------------------------- +# DESCRIPTION +# PALE (Peripheral Abstraction Layer Engine) - simulates virtual hardware +# -------------------------------------------------------------------------- + +# Load base class for Virtual HW components +source "${::LIB_DIRNAME}/pale/virtual_hw_component.tcl" + +# Load Virtual HW components +source "${::LIB_DIRNAME}/pale/ledpanel.tcl" +source "${::LIB_DIRNAME}/pale/leddisplay.tcl" +source "${::LIB_DIRNAME}/pale/ledmatrix.tcl" +source "${::LIB_DIRNAME}/pale/multiplexedleddisplay.tcl" +source "${::LIB_DIRNAME}/pale/simplekeypad.tcl" +source "${::LIB_DIRNAME}/pale/matrixkeypad.tcl" + +class Pale { + private variable scenario_file {} ;# String: Name of PALE scenario file + + private variable portLatch {} ;# List: Nx{5x{8x{...}}} States of port latches + private variable portState {} ;# List: Nx{5x{8x{...}}} True port states + private variable portOutput {} ;# List: Nx{5x{8x{...}}} True port outputs + private variable portInput {} ;# List: 5x{8x{...}} Port inputs + private variable special_func {} ;# List: Values of alternative port functions + private variable portConfig ;# Array of Int: Index 0..4, defines port pin functions + private variable portConfig_mod 0 ;# Bool: $portConfig contain special configuration + + private variable instruction_cycles 0 ;# Int: Nummber of instruction cycles performed during this simulation cycle + + private variable last_output {} ;# List: 5x{8x{...}} Last port outputs + private variable last_input {} ;# List: 5x{8x{...}} Last port inputs + private variable last_state {} ;# List: 5x{8x{...}} Last true port states + + private variable input_devices [list] ;# List of Object: Input devices (can affect true state) + private variable output_devices [list] ;# List of Object: Output devices (cannot affect true state) + private variable engaged_pins ;# Array of Lists of Objects: Output devices which uses pin specified by index (index: (port_num,pin_num)) + + private variable is_enabled 0 ;# Bool: PALE sysetem on-line + private variable modified 0 ;# Bool: Modified flag + + ## Object constructor + # Perform PALE sysetem reset + constructor {} { + pale_reset + + for {set p 0} {$p < 5} {incr p} { + for {set b 0} {$b < 8} {incr b} { + set engaged_pins($p,$b) {} + } + } + } + + ## Object destructor + # Save PALE scenarion file and destroy all PALE VHW components + destructor { + pale_save_scenario_file + + foreach dev [concat $output_devices $input_devices] { + delete object $dev + } + } + + ## Save PALE scenario under the specified file name + # @parm String filename - Name of the target file + # @return Bool - 1 upon success; 0 upon fail + public method pale_save_as {filename} { + set scenario_file_org $scenario_file + set scenario_file [file join [$this cget -ProjectDir] $filename] + + # Adjust file extension + if {![regexp {\.vhw$} $scenario_file]} { + append scenario_file {.vhw} + } + + if {[pale_save_scenario_file]} { + return 1 + } + + set scenario_file $scenario_file_org + return 0 + } + + ## Save PALE scenario to a file + # If there is no predefined file name then it will call "::X::__save_as_VHW" + # @return Bool - 1 upon success; 0 upon fail + public method pale_save {} { + if {$scenario_file == {}} { + ::X::__save_as_VHW + return 0 + } + return [pale_save_scenario_file] + } + + ## Save PALE scenario to a file + # @return void + public method pale_save_scenario_file {} { + # Abort on empty file name + if {$scenario_file == {}} { + return 0 + } + + # Create a backup file + catch { + file rename -force $scenario_file "$scenario_file~" + } + + # Try to open the file + if {[catch { + set file [open $scenario_file "w" 420] + }]} then { + puts stderr "Unable to save to file: \"$scenario_file\"" + return 0 + } + + # Save data to the file + puts $file "# MCU 8051 IDE: Virtual HW configuration file" + puts $file "# Date: [clock format [clock seconds] -format {%D}]" + puts $file "# Project: [string trim $this {:}]\n" + foreach dev [concat $output_devices $input_devices] { + puts $file [$dev get_config] + } + + # Finalize + catch { + close $file + } + set modified 0 + return 1 + } + + ## Get value of flag modified + # @return Bool - The modified flag + public method pale_modified {} { + return $modified + } + + ## Set flag modified + # @return Bool - Always 1 + public method pale_set_modified {} { + set modified 1 + + return 1 + } + + ## Get name of PALE scenarion file + # @return String - Name of the file + public method pale_get_scenario_filename {} { + # Determinate project root path + set prj_path [$this cget -projectPath] + append prj_path {/} + + # Return relative directory location + if {![string first $prj_path $scenario_file]} { + return [string range $scenario_file [string length $prj_path] end] + # Return absolute directory location + } { + return $scenario_file + } + } + + ## Remove all devices from the current scenarion + # @return void + public method pale_remove_all_devices {} { + foreach dev [concat $output_devices $input_devices] { + delete object $dev + } + } + + ## Reset pale to initial state + # @return void + public method pale_forget_all {} { + pale_remove_all_devices + set scenario_file {} + set modified 0 + } + + ## Open the specified PALE scenarion file + # @parm String filename - Source file + # @return Int - Exit status + # 0 - Ok + # 1 - Error + # 2 - File is not usable + public method pale_open_scenario {filename} { + set filename [file join [$this cget -ProjectDir] $filename] + if { + ![file exists $filename] || + ![file isfile $filename] || + (!$::MICROSOFT_WINDOWS && ![file readable $filename]) + } { + return 0 + } + + pale_remove_all_devices + + set scenario_file $filename + set modified 0 + return [pale_load_scenarion $filename] + } + + ## Import the specified PALE scenarion file + # @parm String filename - Source file + # @return Int - Exit status + # 0 - Ok + # 1 - Error + # 2 - File is not usable + public method pale_load_scenarion {filename} { + # Check for file usability + if {![file exists $filename] || ![file isfile $filename] || (!$::MICROSOFT_WINDOWS && ![file readable $filename])} { + return 2 + } + + # Try to open the specified file + if {[catch { + set file [open $filename {r}] + }]} then { + puts stderr "Unable to open file: \"$scenario_file\", that might not be important ..." + return 1 + } + + # Read the file line by line + set result 0 + while {![eof $file]} { + set line [gets $file] + + # Skip empty lines and comments + if {$line == {} || [regexp {^\s*#} $line]} {continue} + + # Decomposite file records + set obj [lindex $line 0] ;# VHW component class name + set conf [lindex $line 1] ;# VHW component configuration + + # Create component object and set its configuration + if {[catch { + set obj [$obj ::#auto $this] + $obj set_config $conf + # Error detected + }]} then { + puts stderr "Unable to create PALE object: \"$obj\", maybe you are using old version of MCU 8051 IDE\n" + puts stderr $::errorInfo + + catch { + delete object $obj + } + + set result 1 + } + } + + # Finalize ... + catch { + close $file + } + set modified 1 + return $result + } + + ## Reset whole PALE system + # @return void + public method pale_reset {} { + set portConfig_mod 0 + array set portConfig { + 0 {0 0 0 0 0 0 0 0} + 1 {0 0 0 0 0 0 0 0} + 2 {0 0 0 0 0 0 0 0} + 3 {0 0 0 0 0 0 0 0} + 4 {0 0 0 0 0 0 0 0} + } + set last_output [list \ + [list 1 1 1 1 1 1 1 1] \ + [list 1 1 1 1 1 1 1 1] \ + [list 1 1 1 1 1 1 1 1] \ + [list 1 1 1 1 1 1 1 1] \ + [list 1 1 1 1 1 1 1 1] \ + ] + set last_input $last_output + set last_state $last_output + set portState [list $last_output] + + foreach dev [concat $input_devices $output_devices] { + $dev reset + } + + pale_reevaluate_IO + } + + ## Withdraw windows of all PALE components + # Usefull to speedup exit program procedure + # @return void + public method pale_withdraw_all_windows {} { + foreach dev [concat $output_devices $input_devices] { + $dev withdraw_window + } + } + + ## Inform pale about interrupt comminted by simulatoe + # @parm Int vector - Interrupt vector + # @return void + public method pale_interrupt {vector} { + $this graph_draw_interrupt_line + } + + ## Perform one PALE simulation cycle + # @parm List - State of 5 port latches + # @return void + public method pale_simulation_cycle args { + if {!$is_enabled} {return} + + set ports [list] + foreach byte [lindex $args 0] { + set byte [NumSystem::dec2bin $byte] + set bin_len [string length $byte] + if {$bin_len < 8} { + set byte "[string repeat {0} [expr {8 - $bin_len}]]$byte" + } + + lappend ports [split $byte {}] + } + lappend portLatch $ports + incr instruction_cycles + } + + ## Set Line Special Function (Bypass port latch) + # @parm List port_and_bit - {port_number bit_number} + # @parm Int type - Function + # 0 - Nomal operation -- port latch is outputed + # 1 - Special logical IO function (UART, triggers, external memory, etc.) + # 2 - High speed digital output (possibly a few pulses per instruction cycle) + # 3 - PWM output (it's low speed logical output) + # 4 - Analog comparator input (accepts values between 0 and 1) + # 5 - External memory + # 6 - Not implemented pin + # @return void + public method pale_SLSF {port_and_bit type} { + # Modify ports configuration + lset portConfig([lindex $port_and_bit 0]) \ + [expr {7 - [lindex $port_and_bit 1]}] $type + + # Adjust flag portConfig_mod + set portConfig_mod 0 + for {set i 0} {$i < 5} {incr i} { + for {set j 0} {$j < 5} {incr j} { + if {[lindex $portConfig($i) $j] != 0} { + set portConfig_mod 1 + return + } + } + } + } + + ## Read Real Port Voltage - 8 bit value (0..255) + # @parm Int port - Port number + # @return Int - Port value + public method pale_RRPV {port} { + if {!$is_enabled} {return 255} + + set result_tmp [lindex $portState [list end $port]] + set result {} + foreach bit $result_tmp { + switch -- $bit { + {?} { ;# No volatge + append result [expr {rand() < 0.5}] + } + {X} { ;# Access to external memory + append result [expr {rand() < 0.5}] + } + {-} { ;# Undeterminable value (some noise) + append result [expr {rand() < 0.5}] + } + {|} { ;# High frequency + append result 1 + } + {=} { ;# High forced to low + append result 0 + } + default { + append result $bit + } + } + } + set result [NumSystem::bin2dec $result] + return $result + } + + ## Read Real Port Pin Voltage - 1 bit value (0 or 1) + # @parm List - {port_number bit_number} + # @parm Int = 0 - Position in history (positive number) + # @return Bool - Boolean value + public method pale_RRPPV args { + if {!$is_enabled} {return 1} + + # Parse input arguments + set port [lindex $args {0 0}] + set bit [lindex $args {0 1}] + set position [lindex $args 1] + + # Adjust arguments + if {![string length $position]} { + set position 0 + } elseif {$position < 0} { + set position [expr {[llength $portState] + $position}] + } + set bit [expr {7 - $bit}] + + # Evaluate result + set result [lindex $portState [list $position $port $bit]] + switch -- $result { + {?} { ;# No volatge + return [expr {rand() < 0.5}] + } + {X} { ;# Access to external memory + return [expr {rand() < 0.5}] + } + {|} { ;# High frequency + return 1 + } + {1} { ;# Logical 1 + return 1 + } + {0} { ;# Logical 0 + return 0 + } + {=} { ;# High forced to low + return 0 + } + default { + return 1 + } + } + } + + ## Write to port with bypassed latch (takes effect on next simulation cycle) + # @parm Int - Port number + # @parm List - New value -- list of 8 values {bit0 bit1 bit2 ... bit7} + # '0' - Logical 0 + # '1' - Logical 1 + # '|' - High frequency pulse + # 'X' - Access to external memory + # '?' - No volatge + # '-' - Undeterminable value (some noise) + # '=' - High forced to low + # @parm Int = 0 - Position in history (zero or negative number) + # @return void + public method pale_WPBL args { + if {!$is_enabled} {return} + + # Parse input arguments + set port [lindex $args 0] + set value [lindex $args 1] + set position [lindex $args 2] + + # Adjust arguments + if {![string length $position]} { + set position 0 + } + + # Set value + for {set bit 0} {$bit < 8} {incr bit} { + lappend special_func [list $port $bit $value $position] + } + } + + ## Write to port bit with bypassed latch + # @parm List - {port_number bit_number} + # @parm Char - New value + # '0' - Logical 0 + # '1' - Logical 1 + # '|' - High frequency pulse + # 'X' - Access to external memory + # '?' - No volatge + # '-' - Undeterminable value (some noise) + # '=' - High forced to low + # @parm Int = 0 - Position in history (zero or negative number) + # @return void + public method pale_WPBBL args { + if {!$is_enabled} {return} + + # Parse input arguments + set port [lindex $args {0 0}] + set bit [lindex $args {0 1}] + set value [lindex $args 1] + set position [lindex $args 2] + + # Adjust arguments + if {![string length $position]} { + set position 0 + } + set bit [expr {7 - $bit}] + + # Set value + lappend special_func [list $port $bit $value $position] + } + + ## Finalize this simulation cycle + # @return void + public method pale_finish_simulation_cycle {} { + if {!$is_enabled} {return} + + # --------------------------------------------------- + # DETERMINATE TRUE OUTPUT VALUES + # --------------------------------------------------- + set portOutput $portLatch + + if {$portConfig_mod} { + # Adjust port outputs to contain '#' where are the + #+ bits with active alternative function + for {set port 0} {$port < 5} {incr port} { + for {set bit 0} {$bit < 8} {incr bit} { + switch -- [lindex $portConfig($port) $bit] { + 0 { ;# Nomal operation -- port latch is outputed + } + 1 { ;# Special logical IO function (UART, triggers, external memory, etc.) + for {set i 0} {$i < $instruction_cycles} {incr i} { + lset portOutput [list $i $port $bit] {#} + } + } + 2 { ;# High speed digital output (possibly a few pulses per machine cycle) + for {set i 0} {$i < $instruction_cycles} {incr i} { + lset portOutput [list $i $port $bit] {#} + } + } + 3 { ;# PWM output (it's low speed logical output) + for {set i 0} {$i < $instruction_cycles} {incr i} { + lset portOutput [list $i $port $bit] {#} + } + } + 4 { ;# Analog comparator input (accepts values between 0 and 1) + for {set i 0} {$i < $instruction_cycles} {incr i} { + lset portOutput [list $i $port $bit] {?} + } + } + 5 { ;# Access to external memory + for {set i 0} {$i < $instruction_cycles} {incr i} { + lset portOutput [list $i $port $bit] {X} + } + } + 6 { ;# Not implemented pin + for {set i 0} {$i < $instruction_cycles} {incr i} { + lset portOutput [list $i $port $bit] {?} + } + } + } + } + } + # Adjust port outputs to contain values generated by alternaive functions + foreach spec $special_func { + set port [lindex $spec 0] + set bit [lindex $spec 1] + set value [lindex $spec 2] + set position [lindex $spec 3] + + incr position $instruction_cycles + incr position -1 + + lset portOutput [list $position $port $bit] $value + } + # Adjust port outputs to repeat previous values on + #+ bits with active alternative function. + #+ In other words, eliminate all '#' and replace them with reasonable values + for {set i -1; set j 0} {$j < $instruction_cycles} {incr i; incr j} { + if {$i < 0} { + set previous_output_state $last_output + } { + set previous_output_state [lindex $portOutput $i] + } + foreach prev $previous_output_state new [lindex $portOutput $j] port {0 1 2 3 4} { + if {[lsearch -ascii -exact $new {#}] != -1} { + foreach p $prev n $new bit {0 1 2 3 4 5 6 7} { + switch -- $n { + {#} { ;# Repeat last value + lset portOutput [list $j $port $bit] $p + } + } + } + } + } + } + } + + # --------------------------------------------------- + # DETERMINATE TRUE STATE + # --------------------------------------------------- + + # Call input devices to evaluate input values + read_port_input + + # Determinate true port states using function "pale_combine_values" + #+ and graw graphs + set graw_graph [expr {![$this sim_run_in_progress]}] + set portState [list] + set state_one_p [list] + set state_all_p [list] + for {set i 0} {$i < $instruction_cycles} {incr i} { + foreach output [lindex $portOutput $i] input [lindex $portInput $i] { + foreach out $output in $input { + lappend state_one_p [pale_combine_values $in $out] + } + + lappend state_all_p $state_one_p + set state_one_p [list] + } + + if {$graw_graph} { + $this graph_new_output_state L [lindex $portLatch $i] + $this graph_new_output_state O [lindex $portOutput $i] + $this graph_new_output_state S $state_all_p + } + + lappend portState $state_all_p + set state_all_p [list] + } + + # Clean up + set instruction_cycles 0 + set last_output [lindex $portOutput end] + set last_input [lindex $portInput end] + set last_state [lindex $portState end] + set portLatch [list] + set portOutput [list] + set portInput [list] + set special_func [list] + + # Inform output devices about the new port outputs + foreach dev $output_devices { + $dev new_state $last_state + update + } + } + + ## Determinate resulting value when two values clash on one wire + # @parm Char in0 - 1st wire state + # @parm Char in1 - The other wire state + # @return Char - Resulting state + public method pale_combine_values {in0 in1} { + if {$in1 == 0} { + return {0} + } elseif {$in1 == {}} { + return $in0 + } + switch -- $in0 { + {|} { ;# High frequency + if {$in1 == 1 || $in1 == {|} || $in1 == {?}} { + return {|} + } else { + return {-} + } + } + {X} { ;# Access to external memory + if {$in1 == 1 || $in1 == {X} || $in1 == {?}} { + return {X} + } else { + return {-} + } + } + {?} { ;# No volatge + return $in1 + } + {-} { ;# Undeterminable value (some noise) + return {-} + } + {=} { ;# High forced to low + return {=} + } + {0} { ;# Logical 0 + return 0 + } + {1} { ;# Logical 1 + if {$in1 == {?}} { + return 1 + } { + return $in1 + } + } + {} { ;# Not connected + return $in1 + } + default { + error "ERROR in function pale_combine_value\npale_combine_values {{$in0} {$in1}}" + } + } + } + + ## Reevaluate inputs & outputs for all PALE devices and the MCU + # @return void + public method pale_reevaluate_IO {} { + # Get last output + set input $last_output + + # Call all input devices + foreach dev $input_devices { + # Call device to change the current state + set input [$dev new_state $input] + update + + # Inform all other devices interconnected with this one + for {set p 0} {$p < 5} {incr p} { + for {set b 0} {$b < 8} {incr b} { + # Search for connected devices + set idx [lsearch -ascii -exact $engaged_pins($p,$b) $dev] + if {$idx == -1} { + continue + } + if {[llength $engaged_pins($p,$b)] == 1} { + continue + } + + # Call all affected devices + foreach affected_dev $engaged_pins($p,$b) { + if {$affected_dev == $dev} { + continue + } + + set input [$affected_dev new_state $input] + update + } + + # Again call the current device + set input [$dev new_state $input] + update + } + } + } + set last_input $input + + # Determinate true port states using function "pale_combine_values" + set state_one_p [list] + set last_state [list] + foreach output $last_output input $last_input { + foreach out $output in $input { + lappend state_one_p [pale_combine_values $in $out] + } + + lappend last_state $state_one_p + set state_one_p [list] + } + + # Update more complex information about true port states + set portState [lreplace $portState end end $last_state] + + # Inform output devices about the new port outputs + foreach dev $output_devices { + $dev new_state $last_state + update + } + } + + ## Call input devices to evaluate input values + # @return void + private method read_port_input {} { + # Get last output + set input [lindex $portOutput end] + + # Call all input devices + foreach dev $input_devices { + # Call device to change the current state + set input [$dev new_state $input] + update + + # Inform all other devices interconnected with this one + for {set p 0} {$p < 5} {incr p} { + for {set b 0} {$b < 8} {incr b} { + # Search for connected devices + set idx [lsearch -ascii -exact $engaged_pins($p,$b) $dev] + if {$idx == -1} { + continue + } + if {[llength $engaged_pins($p,$b)] == 1} { + continue + } + + # Call all affected devices + foreach affected_dev $engaged_pins($p,$b) { + if {$affected_dev == $dev} { + continue + } + + set input [$affected_dev new_state $input] + update + } + + # Again call the current device + set input [$dev new_state $input] + update + } + } + } + + # Fill in list of port onputs + for {set i 1} {$i < $instruction_cycles} {incr i} { + lappend portInput $last_input + } + lappend portInput $input + } + + ## Adjust PALE to new state "ON/OFF" + # @parm Bool _is_enabled - 1 == Turn on; 0 == Turn off + # @return void + public method pale_on_off {_is_enabled} { + set is_enabled $_is_enabled + + foreach dev [concat $input_devices $output_devices] { + $dev on_off $is_enabled + } + } + + ## Turn whole PALE system on or off + # @return void + public method pale_all_on_off {} { + $this graph_change_status_on + } + + ## Determinate whether PALE is on-line or not + # @return Bool - 1 == online; 0 - offline + public method pale_is_enabled {} { + return $is_enabled + } + + ## Inform PALE about new output device (device which CANNOT affect port inputs) + # Every output device must be registred in PALE system in + #+ this way otherwise it wont work ! + # @parm Object object - PALE VHW component object reference + # @return void + # + # Note: PALE VHW component must extend class "VirtualHWComponent" + public method pale_register_output_device {object} { + lappend output_devices $object + } + + ## Unregister device prevously registred by "pale_register_output_device" + # @parm Object object - PALE VHW component object reference + # @return void + public method pale_unregister_output_device {object} { + set idx [lsearch -ascii -exact $output_devices $object] + if {$idx == -1} { + return + } + set output_devices [lreplace $output_devices $idx $idx] + } + + ## Inform PALE about new input device (device which CAN affect port inputs) + # Every input device must be registred in PALE system in + #+ this way otherwise it wont work ! + # @parm Object object - PALE VHW component object reference + # @return void + # + # Note: PALE VHW component must extend class "VirtualHWComponent" + public method pale_register_input_device {object} { + lappend input_devices $object + } + + ## Unregister device prevously registred by "pale_register_input_device" + # @parm Object object - PALE VHW component object reference + # @return void + public method pale_unregister_input_device {object} { + # Find the specified device + set idx [lsearch -ascii -exact $input_devices $object] + if {$idx == -1} { + return + } + + # Unregister the device + set input_devices [lreplace $input_devices $idx $idx] + + # Disconnect the device from all other devices + for {set p 0} {$p < 5} {incr p} { + for {set b 0} {$b < 8} {incr b} { + pale_disengage_pin_by_input_device $p $b $object + } + } + } + + ## Inform PALE system about that than some input device is + #+ connected to the specified port and pin. + # + # THIS IS VERY IMPORTANT FUNCTION to achieve correct PALE + # system functionality !!! + # + # @parm Int port - Port number (0..4) + # @parm Int pin - Port bit number (0..7) + # @parm Object dev - Input device (PALE VHW component) + # @return void + # + # Notes: + # * PALE VHW component must extend class "VirtualHWComponent" + # * Input devices CAN affect port inputs, output cannot + public method pale_engage_pin_by_input_device {port pin dev} { + lappend engaged_pins($port,$pin) $dev + } + + ## Inform PALE system about that than some input device is + #+ no longer connected to the specified port and pin. + # In other words the right opposite of method + # "pale_engage_pin_by_input_device". + # + # THIS IS VERY IMPORTANT FUNCTION to achieve correct PALE + # system functionality !!! + # + # @parm Int port - Port number (0..4) + # @parm Int pin - Port bit number (0..7) + # @parm Object dev - Input device (PALE VHW component) + # @return void + # + # Notes: + # * PALE VHW component must extend class "VirtualHWComponent" + # * Input devices CAN affect port inputs, output cannot + public method pale_disengage_pin_by_input_device {port pin dev} { + set idx [lsearch -ascii -exact $engaged_pins($port,$pin) $dev] + if {$idx == -1} { + return + } + + set engaged_pins($port,$pin) \ + [lreplace $engaged_pins($port,$pin) $idx $idx] + } + + ## Determinate whether the specified port pin is engaged + # by any input device + # @parm Int port - Port number (0..4) + # @parm Int pin - Port bit number (0..7) + # @return void + # + # Note: Input devices CAN affect port inputs, output cannot + public method pale_is_engaged {port pin} { + return $engaged_pins($port,$pin) + } + + ## Get true port outputs (that means latches plus alternate functions) + # @return List of Char - 5 x {8 x $bit_val} -- {bit0 bit1 bit2 ... bit7} + # $bit_val can be one of the following values: + # '0' - Logical 0 + # '1' - Logical 1 + # '|' - High frequency pulse + # 'X' - Access to external memory + # '?' - No volatge + # '-' - Undeterminable value (some noise) + # '=' - High forced to low + public method pale_get_output_state {} { + return $last_output + } + + ## Get true port states + # @return List of Char - 5 x {8 x $bit_val} -- {bit0 bit1 bit2 ... bit7} + # $bit_val can be one of the following values: + # '0' - Logical 0 + # '1' - Logical 1 + # '|' - High frequency pulse + # 'X' - Access to external memory + # '?' - No volatge + # '-' - Undeterminable value (some noise) + # '=' - High forced to low + public method pale_get_true_state {} { + return $last_state + } + + ## Get list of avaliable port number on the current MCU + # @return List of Int - e.g. {1 3} + public method pale_get_avaliable_ports {} { + return [lindex [$this get_ports_info] 1] + } + + ## Inform PALE sysetem about MCU change + # @return void + public method pale_MCU_changed {} { + foreach dev [concat $input_devices $output_devices] { + $dev mcu_changed + } + } +} |