1
0
mirror of https://github.com/wfjm/w11.git synced 2026-02-10 02:20:29 +00:00
Files
wfjm.w11/tools/tcl/ibd_ibmon/util.tcl

403 lines
13 KiB
Tcl

# $Id: util.tcl 985 2018-01-03 08:59:40Z mueller $
#
# Copyright 2015-2017 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
#
# This program is free software; you may redistribute and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3, 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 complete details.
#
# Revision History:
# Date Rev Version Comment
# 2017-04-22 883 2.0.1 setup: now idempotent; move out imap_reg2addr
# 2017-04-16 880 2.0 revised interface, add suspend and repeat collect
# 2017-01-02 837 1.1.1 add procs ime,imf
# 2016-12-30 833 1.1 add proc filter
# 2015-12-28 721 1.0.2 add regmap_add defs; add symbolic register dump
# 2015-07-25 704 1.0.1 start: use args and args2opts
# 2015-04-25 668 1.0 Initial version
#
package provide ibd_ibmon 1.0
package require rutil
package require rlink
package require rw11
package require rw11util
namespace eval ibd_ibmon {
#
# setup register descriptions for ibd_ibmon
#
regdsc CNTL {rcolw 8} {rcolr 7} {wstop 6} \
{conena 5} {remena 4} {locena 3} \
{func 2 3 "s:NOOP:NOOP1:NOOP2:NOOP3:STO:STA:SUS:RES"}
regdsc STAT {bsize 15 3} {wrap 2} {susp 1} {run 0}
regdsc ADDR {laddr 15 14} {waddr 1 2}
#
regdsc DAT3 {burst 15} {tout 14} {nak 13} {ack 12} \
{busy 11} {we 9} {rmw 8} {ndlymsb 7 8}
regdsc DAT2 {ndlylsb 15 6} {nbusy 9 10}
regdsc DAT0 {be1 15} {be0 14} {racc 13} {addr 12 12} {cacc 0}
#
# 'pseudo register', describes 1st word in return list element of read proc
# all flag bits from DAT3 and DAT0
regdsc FLAGS {burst 11} {tout 10} {nak 9} {ack 8} \
{busy 7} {cacc 5} {racc 4} {rmw 3} {be1 2} {be0 1} {we 0}
#
rw11util::regmap_add ibd_ibmon im.cntl {r? CNTL}
rw11util::regmap_add ibd_ibmon im.stat {r? STAT}
rw11util::regmap_add ibd_ibmon im.addr {r? ADDR}
#
# setup: amap definitions for ibd_ibmon ------------------------------------
#
proc setup {{cpu "cpu0"} {base 0160000}} {
if {[$cpu imap -testname im.cntl $base]} {return}
$cpu imap -insert im.cntl [expr {$base + 000}]
$cpu imap -insert im.stat [expr {$base + 002}]
$cpu imap -insert im.hilim [expr {$base + 004}]
$cpu imap -insert im.lolim [expr {$base + 006}]
$cpu imap -insert im.addr [expr {$base + 010}]
$cpu imap -insert im.data [expr {$base + 012}]
}
#
# init: reset ibd_ibmon (stop, reset alim) ---------------------------------
#
proc init {{cpu "cpu0"}} {
$cpu cp \
-wibr im.cntl [regbld ibd_ibmon::CNTL {func "STO"}] \
-wibr im.hilim 0177776 \
-wibr im.lolim 0160000 \
-wibr im.addr 0x0000
}
#
# filter: setup filter window ----------------------------------------------
#
proc filter {{cpu "cpu0"} {lolim 0160000} {hilim 0177776}} {
if {$lolim < 0160000 || $hilim < 0160000} {
error "filter-E: bad lolim or hilim, must be >= 0160000"
}
if {$lolim > $hilim} {
error "filter-E: bad lolim.hilim, must be lolim <= hilim"
}
$cpu cp -wibr im.lolim $lolim \
-wibr im.hilim $hilim
}
#
# start: start the ibmon ---------------------------------------------------
#
proc start {{cpu "cpu0"} args} {
args2opts opts {rcolw 0 rcolr 0 wstop 0 conena 1 remena 1 locena 1} {*}$args
$cpu cp -wibr im.cntl [regbld ibd_ibmon::CNTL {func "STA"} \
[list rcolw $opts(rcolw)] \
[list rcolr $opts(rcolr)] \
[list wstop $opts(wstop)] \
[list locena $opts(locena)] \
[list remena $opts(remena)] \
[list conena $opts(conena)] \
]
}
#
# stop: stop the ibmon -----------------------------------------------------
#
proc stop {{cpu "cpu0"}} {
$cpu cp -wibr im.cntl [regbld ibd_ibmon::CNTL {func "STO"}]
}
#
# suspend: suspend the ibmon -----------------------------------------------
# returns 1 if already suspended
# that allows to implement nested suspend/resume properly
#
proc suspend {{cpu "cpu0"}} {
$cpu cp -ribr im.stat rstat \
-wibr im.cntl [regbld ibd_ibmon::CNTL {func "SUS"}]
return [regget ibd_ibmon::STAT(susp) $rstat]
}
#
# resume: resume the ibmon -------------------------------------------------
#
proc resume {{cpu "cpu0"}} {
$cpu cp -wibr im.cntl [regbld ibd_ibmon::CNTL {func "RES"}]
}
#
# read: read nent last entries (by default all) ----------------------------
#
proc read {{cpu "cpu0"} {nent -1}} {
# suspend and get address and status
$cpu cp -rreg im.stat rstatpre \
-wibr im.cntl [regbld ibd_ibmon::CNTL {func "SUS"}] \
-ribr im.cntl rcntl \
-ribr im.addr raddr \
-ribr im.stat rstat
# determine max number items
set bsize [regget ibd_ibmon::STAT(bsize) $rstat]
set amax [expr {( 512 << $bsize ) - 1}]
set nmax [expr { $amax + 1 } ]
if {$nent == -1} { set nent $nmax }
if {$nent > $nmax} { set nent $nmax }
# determine number of available items (check wrap flag)
set laddr [regget ibd_ibmon::ADDR(laddr) $raddr]
set nval $laddr
if {[regget ibd_ibmon::STAT(wrap) $rstat]} { set nval $nmax }
if {$nent > $nval} {set nent $nval}
# if wstop set use first nent items, otherwise last nent items
set caddr 0
if {![regget ibd_ibmon::CNTL(wstop) $rcntl]} {
set caddr [expr {( $laddr - $nent ) & $amax}]
}
$cpu cp -wibr im.addr [regbld ibd_ibmon::ADDR [list laddr $caddr]]
set rval {}
set nblkmax [expr {( [rlc get bsizemax] >> 2 ) << 2}]; # ensure multiple of 4
set nrest $nent
while {$nrest > 0} {
set nblk [expr {$nrest << 2}]
if {$nblk > $nblkmax} {set nblk $nblkmax}
set iaddr [$cpu imap im.data]
$cpu cp -rbibr $iaddr $nblk rawdat
foreach {d0 d1 d2 d3} $rawdat {
set d3burst [regget ibd_ibmon::DAT3(burst) $d3]
set d3tout [regget ibd_ibmon::DAT3(tout) $d3]
set d3nak [regget ibd_ibmon::DAT3(nak) $d3]
set d3ack [regget ibd_ibmon::DAT3(ack) $d3]
set d3busy [regget ibd_ibmon::DAT3(busy) $d3]
set d3we [regget ibd_ibmon::DAT3(we) $d3]
set d3rmw [regget ibd_ibmon::DAT3(rmw) $d3]
set d0be1 [regget ibd_ibmon::DAT0(be1) $d0]
set d0be0 [regget ibd_ibmon::DAT0(be0) $d0]
set d0racc [regget ibd_ibmon::DAT0(racc) $d0]
set d0addr [regget ibd_ibmon::DAT0(addr) $d0]
set d0cacc [regget ibd_ibmon::DAT0(cacc) $d0]
set eflag [regbld ibd_ibmon::FLAGS \
[list burst $d3burst] \
[list tout $d3tout] \
[list nak $d3nak] \
[list ack $d3ack] \
[list busy $d3busy] \
[list cacc $d0cacc] \
[list racc $d0racc] \
[list rmw $d3rmw] \
[list be1 $d0be1] \
[list be0 $d0be0] \
[list we $d3we] \
]
set edelay [expr {( [regget ibd_ibmon::DAT3(ndlymsb) $d3] << 6 ) |
[regget ibd_ibmon::DAT2(ndlylsb) $d2] }]
set enbusy [regget ibd_ibmon::DAT2(nbusy) $d2]
set edata $d1
set eaddr [expr {0160000 | ($d0addr<<1)}]
lappend rval [list $eflag $eaddr $edata $edelay $enbusy]
}
set nrest [expr {$nrest - ( $nblk >> 2 ) }]
}
# restore address and resume
# resume only if not already suspended before
set rfu [expr {[regget ibd_ibmon::STAT(susp) $rstatpre] ? "NOOP" : "RES"}]
$cpu cp -wibr im.addr $raddr \
-wibr im.cntl [regbldkv ibd_ibmon::CNTL func $rfu]
return $rval
}
#
# print: print ibmon data (optionally also read them) ----------------------
#
proc print {{cpu "cpu0"} {mondat -1}} {
if {[llength $mondat] == 1} {
set ele [lindex $mondat 0]
if {[llength $ele] == 1} {
set nent [lindex $ele 0]
set mondat [read $cpu $nent]
}
}
set rval {}
set edlymax 16383
set eind [expr {1 - [llength $mondat] }]
append rval \
" ind addr data delay nbsy btnab-crm10w acc-mod"
set mtout [regbld ibd_ibmon::FLAGS tout ]
set mnak [regbld ibd_ibmon::FLAGS nak ]
set mack [regbld ibd_ibmon::FLAGS ack ]
set mbusy [regbld ibd_ibmon::FLAGS busy ]
set mcacc [regbld ibd_ibmon::FLAGS cacc ]
set mracc [regbld ibd_ibmon::FLAGS racc ]
set mrmw [regbld ibd_ibmon::FLAGS rmw ]
set mbe1 [regbld ibd_ibmon::FLAGS be1 ]
set mbe0 [regbld ibd_ibmon::FLAGS be0 ]
set mwe [regbld ibd_ibmon::FLAGS we ]
foreach {ele} $mondat {
foreach {eflag eaddr edata edly enbusy} $ele { break }
set ftout [expr {$eflag & $mtout} ]
set fnak [expr {$eflag & $mnak} ]
set fack [expr {$eflag & $mack} ]
set fbusy [expr {$eflag & $mbusy} ]
set fcacc [expr {$eflag & $mcacc} ]
set fracc [expr {$eflag & $mracc} ]
set frmw [expr {$eflag & $mrmw} ]
set fbe1 [expr {$eflag & $mbe1} ]
set fbe0 [expr {$eflag & $mbe0} ]
set fwe [expr {$eflag & $mwe} ]
set prw "r"
set pmod " "
set pwe1 " "
set pwe0 " "
if {$fwe } {
set prw "w"
set pwe1 "0"
set pwe0 "0"
if {$fbe1} { set pwe1 "1"}
if {$fbe0} { set pwe0 "1"}
}
if {$frmw} { set pmod "m"}
set prmw "$pmod$prw$pwe1$pwe0"
set pacc "loc"
if {$fcacc} { set pacc "con"}
if {$fracc} { set pacc "rem"}
set pedly [expr {$edly!=$edlymax ? [format "%5d" $edly] : " --"}]
set ename [format "%6.6o" $eaddr]
set etext ""
if {[$cpu imap -testaddr $eaddr]} {
set ename [$cpu imap -name $eaddr]
set eam "l${prw}"
if {$fracc} { set eam "r${prw}"}
# mask out high/low byte for byte writes for regmap_txt
set edatamsk $edata
if {$pwe1 eq "0"} {set edatamsk [expr { $edatamsk & 0x00ff } ]}
if {$pwe0 eq "0"} {set edatamsk [expr { $edatamsk & 0xff00 } ]}
set etext [rw11util::regmap_txt $ename $eam $edatamsk]
}
set comment ""
if {$fnak} {append comment " NAK=1!"}
if {$ftout} {append comment " TOUT=1!"}
append rval [format \
"\n%5d %-10s %6.6o %5s %4d %s %s %s" \
$eind $ename $edata $pedly $enbusy [pbvi b12 $eflag] \
$prmw $pacc]
if {$etext ne ""} {append rval " $etext"}
if {$comment ne ""} {append rval " $comment"}
incr eind
}
return $rval
}
#
# raw_edata: prepare edata lists for raw data reads in tests ---------------
# args is list of {eflag eaddr edata enbusy} sublists
proc raw_edata {edat emsk args} {
upvar $edat uedat
upvar $emsk uemsk
set uedat {}
set uemsk {}
set m3 [rutil::com16 [regbld ibd_ibmon::DAT3 {ndlymsb -1}]]; # all but ndly
set m2 [rutil::com16 [regbld ibd_ibmon::DAT2 {ndlylsb -1}]]; # all but ndly
set m1 0xffff
set m0 0xffff
foreach line $args {
foreach {eflags eaddr edata enbusy} $line { break }
set d3 [regbld ibd_ibmon::DAT3 [list flags $eflags]]
set d2 [regbld ibd_ibmon::DAT2 [list nbusy $enbusy]]
if {$edata ne ""} {
set m1 0xffff
set d1 $edata
} else {
set m1 0x0000
set d1 0x0000
}
set d0 $eaddr
lappend uedat $d0 $d1 $d2 $d3
lappend uemsk $m0 $m1 $m2 $m3
}
return
}
#
# raw_check: check raw data against expect values prepared by raw_edata ----
#
proc raw_check {{cpu "cpu0"} edat emsk} {
$cpu cp \
-ribr im.addr -edata [llength $edat] \
-wibr im.addr 0 \
-rbibr im.data [llength $edat] -edata $edat $emsk \
-ribr im.addr -edata [llength $edat]
return
}
#
# === high level procs: compact usage (also by rw11:shell) =================
#
# ime: ibmon enable --------------------------------------------------------
#
proc ime {{cpu "cpu0"} {mode "lrc"}} {
if {![regexp {^[lrcnRW]*$} $mode]} {
error "ime-E: bad mode '$mode', use \[lrc\]* and \[nRW\]*"
}
set locena [string match *l* $mode]
set remena [string match *r* $mode]
set conena [string match *c* $mode]
if {$locena == 0 && $remena == 0 && $conena == 0} {
set locena 1
set remena 1
set conena 1
}
set wstop [string match *n* $mode]
set rcolr [string match *R* $mode]
set rcolw [string match *W* $mode]
ibd_ibmon::start $cpu \
locena $locena remena $remena conena $conena \
wstop $wstop rcolr $rcolr rcolw $rcolw
return
}
#
# imf: ibmon filter --------------------------------------------------------
#
proc imf {{cpu "cpu0"} {lo ""} {hi ""}} {
set lolim 0160000
set hilim 0177776
if {$lo ne ""} {
set aran [rw11::imap_range2addr $cpu $lo $hi]
set lolim [lindex $aran 0]
set hilim [lindex $aran 1]
}
ibd_ibmon::filter $cpu $lolim $hilim
}
}