📄 argand.tcl
字号:
# argand.tcl
#
# Argand diagram (=constellation plot) for two vectors or numbers.
# It will be linked to the wave display in ModelSim.
# created, Jonathan Bromley 24 Apr 2002
#
# revised, Jonathan Bromley 24 Jun 2002
# * improved comments for release on Doulos website
# * replaced all [string equal] tests with ![string compare]
# so it works OK with ModelSim pre-5.6 (Tcl 8.0)
# * replaced [string is double $x] tests with [catch {incr x 0}]
# so it works OK with ModelSim pre-5.6 (Tcl 8.0)
# * moved "No data" message to top left corner of display to
# simplify display maintenance
# * removed some old code from experimental versions
# ############################ SYNOPSIS ###############################
# #
# This file contains just two procs, argand and privArgand_proc. #
# It should be used in conjunction with the file modelsim.tcl #
# which provides the code needed to hook this functionality into #
# ModelSim's wave window. #
# #
# #
# ########### argand ########### #
# #
# is used to set up a new constellation-plot window. It will #
# typically be called from a menu item. It creates the window, #
# sets up all necessary data structures, and returns the newly #
# created window's pathname. #
# #
# #
# ########### privArgand_proc ########### #
# #
# provides one centralised entry point for all other functionality. #
# It is typically called from event handlers, to manage dynamic #
# updating and repainting of the plot display. #
# #
# #####################################################################
# ######################################################################
# #
# argand #
# #
# ######################################################################
#
# Accept any arguments. The first (and only!) argument is expected
# to be the name of the wave window in which we are created. If no
# argument, default to .wave
# Any arguments after the first are silently ignored.
#
proc argand {{win .wave} args} {
# Globals in ModelSim that we need to look at:
#
global PathSeparator
global vsimPriv
# We concentrate all our private data in one global array, to
# avoid creating lots of different variable names that might
# clash with existing variables:
#
global privArgand
# Append .tree to the window name so that we locate the signal list.
#
append win .tree
# Check that the required list window really exists, fail if not.
#
if {![winfo exists $win]} {
error "argand: source window $win doesn't exist"
}
if {[string compare WaveTree [winfo class $win]]} {
error "argand: source window $win isn't a WaveTree"
}
# We hope the user has selected the two signals they want us to plot.
# Find which signals are selected:
#
set selList [$win curselection]
# check that there are exactly two:
#
if {[llength $selList] != 2} {
error "argand: must select 2 signals to plot"
}
# Go through the (two!) signals checking they are appropriate
# and remembering their vital statistics
#
foreach sig $selList {
# check that they are both in decimal radix
# (and thus are fairly likely to be numbers!!!)
#
if {[string compare [$win itemcget $sig -radix] decimal]} {
error "argand: selected signals must have decimal radix"
}
# remember their full names, for display purposes later
#
lappend sigList [$win get4 $sig]
}
# Now we know the signal names, extract their tails (the
# HDL declared name of the signal) for annotating the display
#
foreach sig $sigList {
lappend tailList [lindex [split $sig $PathSeparator] end]
}
# Find an index number (small integer) to identify this plot
# uniquely. These indices simply increment as new plots are
# created; there is no need to recycle index numbers from
# plots that have been destroyed.
#
# The next unused index number is saved in our private global
# array as privArgand(nextIndex). If this is the first time
# the procedure has been run, that variable doesn't exist so
# it needs to be created with a suitable default value.
# Is this the first plot we have created?
#
if {![info exists privArgand(nextIndex)]} {
set privArgand(nextIndex) 0
}
# Capture the index number we will use to identify this plot,
# and increment nextIndex ready for the next one.
#
set index $privArgand(nextIndex)
incr privArgand(nextIndex)
# From now on, all data we create will be stored in elements
# of the privArgand() array, with subscripts beginning with
# the index integer followed by a comma.
# Save away the signal names and source window. We don't
# need to save the name tails; they are used only to create
# some text on the plot canvas.
#
set privArgand($index,fullNames) $sigList
set privArgand($index,tree) $win
# Create toplevel window, remember its name
#
set n [toplevel .argand$index]
set privArgand($index,toplevel) $n
# Create names for the enclosing frame (required for correct
# colouring of sunken relief on canvas) and the canvas itself
set privArgand($index,hull) $n.f
set privArgand($index,plot) $n.f.c
# Create the frame and canvas widgets
#
frame $n.f -borderwidth 2 -relief sunken -background white
canvas $n.f.c -background black -borderwidth 0 \
-highlightthickness 0 -width 200 -height 200
pack $n.f -padx 0 -pady 0 -ipadx 0 -ipady 0 -fill both -expand 1
pack $n.f.c -padx 0 -pady 0 -ipadx 0 -ipady 0 -fill both -expand 1
# Create axes with labels
#
$n.f.c create line 0 100 200 100 \
-width 2 -fill darkgray -arrow last -tags axisX
$n.f.c create line 100 200 100 0 \
-width 2 -fill darkgray -arrow last -tags axisY
$n.f.c create text 195 95 -anchor se -text [lindex $tailList 0] \
-tag labelX -fill white -font bold
$n.f.c create text 105 5 -anchor nw -text [lindex $tailList 1] \
-tag labelY -fill white -font bold
# Create "no data" error message
#
$n.f.c create text 5 2 -anchor nw -text "No data!" \
-tag noData -fill red -font bold
# Create polar plot:
# radius vector
#
$n.f.c create line 100 100 100 100 -width 1 -fill green -tags vector
# white cross at the end of it
#
$n.f.c create line 95 100 105 100 -width 3 -fill white -tags pointH
$n.f.c create line 100 95 100 105 -width 3 -fill white -tags pointV
# Set up variables describing the current location of the point.
# This information is needed when moving the point to a new position.
# Note the "uplevel #0" command to run privArgand_proc, since it is
# usually run as an event handler and therefore expects to run in
# the global context.
#
uplevel #0 privArgand_proc getValues $index
# Label the toplevel window
#
wm title $n "X=[lindex $tailList 0] Y=[lindex $tailList 1]"
# Set up for a repaint on size change
#
bind $n.f.c <Configure> [list privArgand_proc repaint $index]
# Hook it to wave window cursor changes by tracing changes
# in ModelSim variable "vsimPriv(acttime)". Remember details
# of the trace handler so that it's possible to cancel it later.
#
set privArgand($index,trace) \
[list privArgand_proc trace $index]
trace variable vsimPriv(acttime) w $privArgand($index,trace)
# Arrange cleanup on window destruction
#
wm protocol $n WM_DELETE_WINDOW [list privArgand_proc destroy $index]
# Fix the display for the first time
#
uplevel #0 privArgand_proc repaint $index
# Return the name of the toplevel window, in the same way that most
# Tk widget creation commands do.
#
return $n
}
# ######################################################################
# #
# privArgand_proc #
# #
# ######################################################################
#
# All the real work is done by one or more options of procedure
# privArgand_proc. By building just one "proc" with lots of options,
# we reduce the number of proc names that have to be added to the
# already crowded name space, and reduce the risk of clashing with
# a proc name that already exists.
# privArgand_proc has two compulsory arguments, option and index.
#
# * option:
# a string name specifying which function we want the proc
# to perform on this run. Valid names are:
# * getValues
# updates our internal copies of the plot's x,y signals
# at the currently selected moment of simulation time,
# by reading values from the appropriate wave window
# * replot
# re-create the display to account for changed x,y values
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -