router.tcl 9.26 KB
#
# Copyright (C) 1996-1998 by the Board of Trustees
#    of Leland Stanford Junior University.
# 
# This file is part of the SimOS distribution. 
# See LICENSE file for terms of the license. 
#
###
### router.tcl -- provides support for examining interconnect traffic
###
### Dan Teodosiu, Sep. 1996
###

#==================================================================
# Symbolic displaying of message types

# Initialize message name table
for {set i 0} {$i < 128} {incr i} { set message_name($i) "-" }
set message_name(0) "WB"
set message_name(2) "NAK_CLEAR_GET"
set message_name(3) "UPGRADE_DELAYED"
set message_name(4) "INVAL_DELAYED"
set message_name(5) "FORWARD_ACK"
set message_name(6) "GET"
set message_name(7) "GETX"
set message_name(8) "UPGRADE_ACK_DELAYED"
set message_name(9) "GET_FROM_IO"
set message_name(10) "NAK"
set message_name(11) "GETX_FROM_IO"
set message_name(12) "PUTX_FROM_IO"
set message_name(13) "PUT"
set message_name(14) "PUT_FROM_IO"
set message_name(15) "PUTX_ACKS_DONE"
set message_name(16) "SWS_READ"
set message_name(17) "ACKS_DONE"
set message_name(18) "REPLACE"
set message_name(19) "NOP"
set message_name(20) "SWB"
set message_name(21) "IO_FORWARD_ACK<0>"
set message_name(22) "PREF"
set message_name(23) "IO_GETX<0>"
set message_name(24) "UNC_READ"
set message_name(25) "UNC_WRITE"
set message_name(26) "IO_NAK<0>"
set message_name(27) "IO_GETX_FROM_IO<0>"
set message_name(28) "IO_PUTX_FROM_IO<0>"
set message_name(29) "UNC_WRITE_NAK"
set message_name(30) "UNC_PUT"
set message_name(31) "IO_PUTX<0>"
set message_name(32) "UNC_ACKS_DONE"
set message_name(33) "UNC_WB"
set message_name(34) "NAK_CLEAR_OTHER"
set message_name(37) "MC_DATA_NAK"
set message_name(38) "MC_ACK"
set message_name(40) "MC_SEND_GETX_NAK"
set message_name(41) "MC_RECV_GETX"
set message_name(42) "MC_RECV_GETX_NAK"
set message_name(43) "MC_SEND_PUTX"
set message_name(44) "MC_RECV_PUTX"
set message_name(45) "MC_RH_REQ"
set message_name(46) "MC_RH_ACK"
set message_name(47) "PUTX"
set message_name(48) "MC_RH_NAK"
set message_name(50) "MC_INVAL_ACK"
set message_name(51) "UNC_READ_FROM_IO"
set message_name(52) "MC_DATA_FAST"
set message_name(53) "MC_GO_FAST"
set message_name(54) "BUSERR"
set message_name(55) "FWALL_WRITE_TO_SWQ"
set message_name(56) "PIO_WRITE"
set message_name(57) "PIO_READ"
set message_name(59) "MC_SEND_GETX"
set message_name(60) "MC_INVAL"
set message_name(61) "BZ_RH_NAK"
set message_name(62) "MC_RECV_IO_GETX"
set message_name(64) "SWS_WRITE"
set message_name(67) "UPGRADE_EAGER"
set message_name(68) "INVAL_EAGER"
set message_name(70) "RETRACT"
set message_name(71) "GETX_EAGER"
set message_name(72) "UPGRADE_ACK_EAGER"
set message_name(75) "MC_SEND_IO_GETX"
set message_name(76) "MC_REQ"
set message_name(77) "BZ_RH_REQ"
set message_name(78) "BZ_RH_ACK"
set message_name(81) "SIPS_REQUEST"
set message_name(82) "SIPS_REQUEST_ACK"
set message_name(83) "SIPS_REQUEST_NAK"
set message_name(84) "SIPS_REPLY_ACK"
set message_name(85) "IO_FORWARD_ACK<1>"
set message_name(86) "RETRACT_NAK"
set message_name(87) "IO_GETX<1>"
set message_name(88) "PUT_SEQ"
set message_name(89) "PUT_IDENT"
set message_name(90) "IO_NAK<1>"
set message_name(91) "IO_GETX_FROM_IO<1>"
set message_name(92) "IO_PUTX_FROM_IO<1>"
set message_name(93) "SIPS_REPLY"
set message_name(95) "IO_PUTX<1>"
set message_name(103) "FWALL_WRITE_ACK"
set message_name(105) "FWALL_WRITE_RETRY"
set message_name(106) "LOCK_TOKEN_REQUEST"
set message_name(107) "LOCK_TOKEN_GRANT"
set message_name(108) "SIPS_REPLY_NAK"
set message_name(138) "UNC_NAK"
set message_name(149) "IO_FORWARD_ACK<2>"
set message_name(151) "IO_GETX<2>"
set message_name(154) "IO_NAK<2>"
set message_name(155) "IO_GETX_FROM_IO<2>"
set message_name(156) "IO_PUTX_FROM_IO<2>"
set message_name(159) "IO_PUTX<2>"
set message_name(182) "UNC_BUSERR"
set message_name(192) "MC_COLLECT_GET"
set message_name(193) "MC_COLLECT_IO_GET"
set message_name(194) "MC_COLLECT_PUT"
set message_name(195) "MC_COLLECT_NAK"
set message_name(213) "IO_FORWARD_ACK<3>"
set message_name(215) "IO_GETX<3>"
set message_name(218) "IO_NAK<3>"
set message_name(219) "IO_GETX_FROM_IO<3>"
set message_name(220) "IO_PUTX_FROM_IO<3>"
set message_name(223) "IO_PUTX<3>"

proc messageType {type} {
    global message_name
    set n $message_name([expr $type])
    if {$n == "-"} { return [hex $type] } else { return $n }
}


# Initialize vector name table
for {set i 0} {$i < 256} {incr i} { set vector_name([hex $i]) "-" }
set vector_name(0xf0) "MAGIC_RECOVER"
set vector_name(0xf1) "MAGIC_REQUEST"
set vector_name(0xf2) "MAGIC_REPLY"
set vector_name(0x61) "ROUTER_READ_REQ"
set vector_name(0x62) "ROUTER_WRITE_REQ"
set vector_name(0xe9) "ROUTER_READ_REP"
set vector_name(0xea) "ROUTER_WRITE_REP"
# ... and many more I didn't care to init here...

proc vectorType {type} {
    global vector_name
    set n $vector_name([hex $type])
    if {$n == "-"} {
	return [hex $type]
    } else {
	return "$n"
    }
}


#==================================================================
# Message beautification.
# printMessage returns a better-looking string containing the message
# representation.
# Works for both regular messages and vector packets.
#

proc printMessage {msg} {
    set src  [expr ([lindex $msg 1] >> 21) & 0x7ff]
    set dest [expr ([lindex $msg 2] >> 14) & 0x1ff]
    set dir  [expr ([lindex $msg 2] >> 10) & 0xf]
    set cmd  [expr ([lindex $msg 3] >> 22) & 0xff]
    set a    [format "0x%06x%08x" [expr [lindex $msg 3] & 0x3fffff] [lindex $msg 4]]

    if {[lindex $msg 0] == "VP"} {
	### Vector packet
	set t [vectorType $cmd]
	set d [format "0x%08x%08x" [lindex $msg 6] [lindex $msg 7]]
	set r [format "0x%08x%08x" [lindex $msg 8] [lindex $msg 9]]
	return "VP $t s:$src d:$dest p:$dir a:$a r:$r $d"
    } elseif {[lindex $msg 0] == "PKT"} {
	### Regular packet
	set t [messageType $cmd]
	set d ""
	set dlen [llength $msg]
	for {set i 6} {$i < $dlen} {incr i 2} {
	    set dw [format "0x%08x%08x" [lindex $msg $i] [lindex $msg [expr $i + 1]]]
	    set d "$d$dw "
	}
	return "PKT $t s:$src d:$dest p:$dir a:$a $d"
    } else {
	### Whooops
	return "BAD PACKET\n"
    }
}


#==================================================================
# Router annotations
# These annotations fire whenever a new pkt arrives at a router

annotation type router num

for {set i 0} {$i < $PARAM(CPU.Count)} {incr i} {
    annotation set router $i {
	newPacket
    }
}

# Note: this contortion necessary because we cannot change router watch
# status before SimOS is entered.

set simosEntaered 0
for {set i 0} {$i < $PARAM(CPU.Count)} {incr i} { set watchRouter($i) 0 }

annotation set simos enter {
    set simosEntaered 1
    if {$CPU == 0} {
	# only do once
	for {set i 0} {$i < $PARAM(CPU.Count)} {incr i} {
	    if {$watchRouter($i) != 0} {
		router watch $i on
	    }
	}
    }
}
     

#==================================================================
# New packet has arrived -- what now?

# illegible? yeah, but man, sooo efficient...
proc newPacket {} {
    global router_ann_routerNum router_ann_portNum router_ann_lane
    set pn [expr [router queuelen $router_ann_routerNum $router_ann_portNum $router_ann_lane] - 1]
    set p [router packet $router_ann_routerNum $router_ann_portNum $router_ann_lane $pn]
    if [catch {packetAction $router_ann_routerNum $router_ann_portNum $router_ann_lane $pn "$p"} status] {
	if {[lindex $status 0] != "invalid"} {
	    log "ROUTER: $status\n"
	}
	defaultPacketAction $router_ann_routerNum $router_ann_portNum $router_ann_lane $pn "$p"
    }
}

proc defaultPacketAction {routerNum portNum lane n pkt} {
    set prettyPkt [printMessage $pkt]

    log "+++ new packet r:$routerNum p:$portNum l:$lane pn:$n\n"
    log "    $prettyPkt\n"
}


#==================================================================
# Various utilities for determining interconnect config

proc numPorts {rn} {
    return [llength [router connections $rn]]
}

proc magicPort {rn} {
    set cx [router connections $rn]
    return [lsearch $cx M]
}

proc connectedRouter {rn pn} {
    set rp [lindex [router connections $rn] $pn]
    if {$rp == "M"} {
	return "M"
    } else {
	return [lindex $rp 0]
    }
}

proc connectedPort {rn pn} {
    return [lindex [lindex [router connections $rn] $pn] 1]
}


#==================================================================
# Utilities for setting / clearing router watch

proc routerWatch {r on} {
    global watchRouter simosEntaered

    set oldwatch $watchRouter($r)
    if {$on == "on" && $oldwatch == 0} {
	if {$simosEntaered != 0} { router watch $r on }
	set watchRouter($r) 1
    } elseif {$on == "off" && $oldwatch != 0} {
	if {$simosEntaered != 0} { router watch $r off }
	set watchRouter($r) 0
    } else {
	console "bad parameter to routerWatch: $on\n"
	exit
    }
}

proc routerWatchAll {on} {
    global PARAM

    for {set i 0} {$i < $PARAM(CPU.Count)} {incr i} {
	routerWatch $i $on
    }
}


#==================================================================
console "  ROUTER package loaded\n"

annotation set simos enter {
    if {$CPU == 0} {
	console "\n  INTERCONNECT TOPOLOGY:\n"
	for {set i 0} {$i < $PARAM(CPU.Count)} {incr i} {
	    console "    $i  "
	    for {set j 0} {$j < [numPorts $i]} {incr j} {
		set cr [connectedRouter $i $j]
		set cp [connectedPort $i $j]
		if {$cr == "M"} {
		    console "$j:M "
		} elseif {$cr == ""} {
		    console "$j:- "
		} else {
		    console "$j:($cr.$cp) "
		}
	    }
	    console "\n"
	}
	console "\n"
    }
}