[fa.info-vax] DEUNA details

info-vax@ucbvax.ARPA (10/24/84)

From: engvax!KVC@cit-vax

Well folks, it's done.  The long-awaited DEUNA document is ready to
be sent.  I mailed a preliminary article out to INFO-VAX a few weeks
ago.  The new one contains a lot more detail.  I am not sure how to
go about distributing it...

First of all, the article has already been sent to Larry Kilgallen
(the Pageswapper editor).  If you can wait, the best thing to do is
read it when it comes out there.  If you think you need to see it
sooner (I do not know what the publication delay is on Pageswapper
articles) I can send the article via mail.  It is 104 blocks long,
though, and I don't think I should send that much to the whole of
INFO-VAX.  On the other hand, it may be useful if it appeared in the
INFO-VAX archives (this stuff does get archived, doesn't it????).

Anyone have any ideas?  What does the INFO-VAX maintainer think?
Should I just see who is interested and send to them?  I got a lot of
responses to my preliminary article, though, and I expect at least
as many to this one.  Since my mailer isn't very smart (is anybody's?)
I'd have to mail a separate copy to each person anyway, which would
put a burden on the friendly people at CIT-VAX who gateway for us...

How about this idea:

I'll mail the article to someone on the ARPAnet who can put it where
other ARPAnauts can FTP it (you cannot get to my system with FTP, only
MAIL).  If you really think you need the info and cannot FTP, then
drop me a line and I'll mail you a special copy.  Anyone think that's
a problem?  Am I making a lot of fuss for 104 blocks?  Any volunteers
who can put make it available to other FTP's?

Oh well, I'll just sit back and see what people think I should do.
Maybe Larry'll publish it before I have to decide... :-)

By the way, is there anyway he can be reached by e-mail?  It'd sure
be nice to be able to submit articles electronically.  What ever
happened to the DECUS VAX?  Weren't they gonna put the SIG newsletters
on it?

	/Kevin Carosso               engvax!kvc @ CIT-VAX.ARPA
	 Hughes Aircraft Co.

info-vax@ucbvax.ARPA (10/24/84)

From: Richard Garland <OC.GARLAND%CU20B@COLUMBIA.ARPA>

Mail-From: OC.GARLAND created at 24-Oct-84 09:26:03
Date: Wed 24 Oct 84 09:26:03-EDT
From: Richard Garland <OC.GARLAND@CU20B.ARPA>
Subject: Re: DEUNA details...
To: engvax!KVC%cit-vax@COLUMBIA.ARPA
cc: M_INFOVAX%cit-vax@COLUMBIA.ARPA, OC.GARLAND@CU20B.ARPA
In-Reply-To: Message from "engvax!KVC%cit-vax@columbia.arpa" of Tue 23 Oct 84 23:40:52-EDT

in re electronic input to DECUS:

There is a VAX is Massachusetts on which DECUS folks have accounts
for MAIL meeting announcements etc.

Anybody from DEC listening?  How about DEC creating a gateway from
DEC-Marlboro through DEC enet to that machine?  At least maybe a
mailbox for suggestions.  Anyone from DEC listening who knows how
to ask about this please do.

					Rg
-------
-------

info-vax@ucbvax.ARPA (10/28/84)

From: William "Chops" Westfield <BILLW@SRI-KL.ARPA>




              Using the DEUNA/DEQNA Ethernet Interface Under VMS

                   Ned Freed, Kevin Carosso and Dan Newman
                               MATHLIB Project
                             Harvey Mudd College
                             Claremont, CA 91711

  We recently completed adapting  an  implementation  of  TCP/IP  originally
  written  for  an  Interlan NI1010 ethernet interface to a DEC DEUNA.  This
  provided us a lot of insight into the way the DEUNA works.  (Most  of  the
  insight  came as a result of studying the VMS XEDRIVER source code and not
  by reading the I/O User's Guide.)
                 ___ ______ _____

  This article attempts to summarize what we learned so  others  will  start
  with  something  more  than  what  the I/O User's Guide provides.  We also
                                         ___ ______ _____
  present  a  program  which  captures  and   displays   DEUNA   performance
  statistics.

  We assume the reader is somewhat familiar with,  but  not  necessarily  an
  expert on, the principles of Ethernet operation.

  DISCLAIMER:  Although the information contained herein is believed  to  be
  correct,  the DEUNA and XEDRIVER are very complex and it is quite possible
  that  our  description  is  incorrect  in  some  areas.   We   assume   no
  responsibility for the content of this article.



1.0  The DEQNA versus the DEUNA

The DEQNA is the equivalent of the DEUNA for a Q-bus system.  It appears  that
the  device  driver  interface for the DEQNA is nearly identical to the DEUNA.
Differences appear to be minor --  we  mention  the  ones  we  know  of  where
appropriate.   When  we refer to the DEUNA or to XEDRIVER, we are also talking
about the DEQNA and XQDRIVER unless  a  specific  statement  is  made  to  the
contrary.



2.0  The basics of XEDRIVER

The VMS device driver for the DEUNA is called XEDRIVER.  This  driver  is  the
one used by DECnet if it is running over the Ethernet, but DECnet's use of the
device does not  preclude  additional  utilization  of  the  device  by  other
programs.

XEDRIVER is a very complex and sophisticated piece of software with an amazing
range of capabilities.  A large portion of its complexity is devoted to making
it possible for multiple users to utilize the Ethernet simultaneously  without
disturbing  each  other.   We  wish  to  take  this opportunity to express our
appreciation to Rod Gamache, who wrote the beast.
                                                                        Page 2


3.0  Using the DEUNA

In order to use the DEUNA via XEDRIVER, 6 basic steps must be performed:

    (1)  Assign a channel or channels.
    (2)  Establish device characteristics.
    (3)  Start up the device.
    (4)  Perform any desired I/O operations.
    (5)  Shut down the device.
    (6)  Deassign the channel(s).


XEDRIVER provides a conventional $QIO interface for user use.  (DECnet and the
LAT-11  use  their own special direct path into XEDRIVER at the IRP level, but
other users should not use this facility.  We  will  describe  only  the  $QIO
interface.)  Regular  high  level  languages  whose  I/O facilities employ RMS
cannot use the DEUNA directly.  First of all, certain set mode $QIO  functions
must  be performed to establish required operational parameters.  Second, $QIO
write functions must be accompanied by a special P5 parameter  specifying  the
destination  address.  These additional required parameters cannot be supplied
by RMS.

However, programs to control the DEUNA are not too difficult to write.  In the
following   sections,  we  will  describe  the  various  details  involved  in
performing each of the steps listed above.  The  excessive  amount  of  detail
provided  is an attempt to accomodate any conceivable use for the DEUNA and is
not an indication of how complex a simple program to use the device must be.



3.1  Assigning a channel

When a channel is $ASSIGN'ed to the DEUNA (usually the  device  named  "XEA0")
the  driver  creates  a new Unit Control Block (UCB), assigns a channel to it,
and returns this channel to the caller.  This new unit is a device in its  own
right  and  has a name of the form XEAn, where n is an ever-increasing integer
greater than 0.  If a user needs to $ASSIGN more than one channel to a  single
unit,  the  name of the unit associated with one channel can be determined via
$GETDVI and another channel can be  $ASSIGN'ed  to  the  device  name  $GETDVI
returns.

The unit will remain in existence as long as someone has a channel assigned to
it.   When  the  last  channel  to  a  unit  is $DASSGN'ed the unit is deleted
automatically.



3.2  Establishing device characteristics

The hardest part of using  the  DEUNA  is  setting  its  operating  parameters
properly.   This  is  especially  difficult  if  DECnet is running on the same
device, because certain device characteristics will then be immutable.

A IO$_SETMODE function $QIO with the IO$M_CTRL modifier bit set is used to set
all  operational parameters of the DEUNA.  The parameter list used by the $QIO
always has the same form -- a sequential list of  ordered  pairs:   (parameter
code,  parameter  value).   Each  parameter  code  is a 16 bit value and has a
                                                                        Page 3


symbolic name beginning with the  prefix  "NMA$C_".   The  parameters  can  be
specified  in  any  order in the list.  Note that not all symbols of this form
defined by the $NMADEF macro are valid DEUNA parameter codes;   these  symbols
are  used  to establish characteristics for many different devices besides the
DEUNA.

A descriptor must be created that describes the parameter list and the address
of this descriptor is passed as the P2 parameter in the IO$_SETMODE + IO$_CTRL
$QIO call.  P2 is the only parameter that this call uses.

The following sections describe the various DEUNA parameters that  can  appear
in the list.



3.2.1  The Ethernet physical address (NMA$C_PCLI_PHA)

Every DEUNA on the Ethernet must be assigned a 48 bit physical address.   This
address   serves   to  uniquely  identify  the  device.   Such  addresses  are
customarily written as a series of six 8 bit hexadecimal values  separated  by
dashes, e.g.  AA-00-FA-23-3A-20.

Each network packet sent by the DEUNA has a header that specifies the sender's
and  receiver's physical addresses.  The DEUNA only bothers to receive packets
that are addressed to  it;   normally  all  other  packets  are  ignored  (see
promiscious mode and multicasting below).

It would not make sense for one user to change the  physical  address  of  the
device while someone else is using it.  Consequently, when a request to change
the physical address is made XEDRIVER checks to see if there is only one  unit
attached to the DEUNA.  If so, the physical address can be changed.  If not, a
SS$_BADPARM error will be returned.  In other words, the physical address  can
only be changed by an exclusive user of the device.

If no one specifies a physical address the DEUNA will use its default hardware
address.   All  DEUNA  default  addresses  fall in the range AA-00-00-00-00-00
through AA-00-04-FF-FF-FF.  Specific default addresses are  uniquely  assigned
to each DEUNA during manufacture.

The physical address parameter value  appears  in  the  parameter  list  as  a
counted  string  of  bytes.   The  count  word precedes the string.  The first
element in the string must be  a  modifier  word,  either  NMA$C_LINMC_SET  or
NMA$C_LINMC_CLR,  which specifies whether the physical address is to be set or
cleared.  (The symbols that begin with NMA$C_LINPR described in the I/O User's
                                                                    ___ ______
Guide  do  not seem to exist.) If NMA$C_LINMC_SET is used the physical address
_____
must appear as the next 6 bytes in the string.  When NMA$C_LINMC_CLR  is  used
the rest of the string is ignored.

A physical address remains in effect until it is  explicitly  cleared  or  the
DEUNA  goes  idle  (no  one  has  channels assigned to it), at which point the
physical address will reset unconditionally to the default hardware address.

DECnet insists on setting the  physical  address  to  something  of  the  form
AA-00-04-00-xx-04,  where  xx  is  the DECnet node number.  If some user beats
DECnet to the DEUNA and sets up  a  different  address  (or  even  leaves  the
default  address  active) DECnet will report a circuit error and refuse to use
the device.  We recommend that DECnet be allowed to establish contact with the
                                                                        Page 4


DEUNA  prior to attempting any other use so it can establish all the parameter
settings it needs.

If another user has to use the DEUNA prior to DECnet the physical address must
be  set  to  the  value  DECnet  expects.   In  order  to  facilitate this, an
additional modifier word for the NMA$C_PCLI_PHA parameter value has been added
in version 4.0 of VMS.  This modifier word, NMA$C_LINMC_SDF, sets the physical
address  of  the  DEUNA  to  the  DECnet  default  address.   The  address  is
constructed  by  merging  the value of the SYSGEN parameter SCSSYSTEMID to the
constant portions of the DECnet address.



3.2.2  Protocol type (NMA$C_PCLI_PTY)

Additional information is required to select who actually gets  each  received
packet  since  everyone sharing the same DEUNA uses the same physical address.
This information is provided by a 16 bit value called the protocol type.  Each
unit must select its own protocol type, so this must be specified by each unit
prior to starting the DEUNA.

Some protocol types already in use are:

    60-00  Loopback functions
    60-01  Dump/load functions
    60-02  Remote console functions
    60-03  DECnet
    60-04  LAT (Ethernet terminal server)
    60-06  Reserved for customer use by Digital
    00-08  TCP/IP (as implemented by 4.2BSD UNIX)
    90-00  Cross-company loopback messages

The first three protocol types in the table above are handled specially by the
DEUNA  hardware.   We  only  describe  the  functionality  available  via this
mechanism briefly;  for more information  refer  to  the  DEUNA  User's  Guide
                                                          _____  ______  _____
(pages 4-76 to 4-99 and Appendix B).

Packets with loopback function protocol types are received by  the  DEUNA  and
immediately  retransmitted  somewhere  without  informing  the  VAX  of  their
presence.  The first word of the data portion of the  packet  is  used  as  an
offset  (skip count) into the packet indicating where to find a function code.
The  function  code  specifies  exactly  what  loopback  operation  should  be
performed.  The possible function codes are:

    1 - reply, return packet to sender
    2 - forward, send packet on to specified forwarding address

In the returned packet the skip count is incremented by 8 while  the  protocol
type  is still 60-00, so whoever receives the packet sees a possibly different
function code and forwarding address.  Packets can be  sent  through  multiple
relay  points by choosing an appropriate list of function codes and forwarding
addresses.

The remote console protocol type is used to determine what  other  DEUNAs,  if
any, are present on the network and their characteristics.  The second word of
the data portion of the packet is a function code:
                                                                        Page 5


    5 - return this DEUNA's system ID table
    6 - boot system request
    9 - return this DEUNA's usage counters to sender

The read internal usage counters operation is actually implemented in XEDRIVER
-- it is not a hardware function like the first two.

The dump/load protocol type is used for the loading  and  starting  of  remote
hardware over the network for systems such as VAXELN and the LAT-11.

There are no special checks in XEDRIVER to prevent any user from  transmitting
messages  with  these  protocol  types,  so  these capabilities can be used by
nonprivileged user programs.



3.2.3  Access to different protocol types (NMA$C_PCLI_ACC)

The first unit to use a given protocol type gets to  pick  how  that  protocol
type may be used via this parameter.  The possible parameter values are:

Exclusive use = NMA$C_ACC_EXE

    This protocol type is reserved for the  current  user.   Anyone  else  who
    tries  to  use  it will get a SS$_BADPARM error.  This access mode will be
    the default unless this parameter is specified.

Default user = NMA$C_ACC_SHR

    Anyone may use this protocol  type  to  transmit  packets,  but  only  the
    default  user  (the first one to use this protocol type) gets any received
    packets that have this protocol type associated with them.

Shared use = NMA$C_ACC_LIM

    Each unit using this  protocol  type  is  required  to  declare  a  single
    physical  address  they are going to be communicating with (NMA$C_PCLI_DES
    parameter).  Then they  are  locked  into  sending  each  to  that  single
    destination.   When  a  packet of this protocol type is received, XEDRIVER
    figures out who its from and hands it to  whoever  is  communicating  with
    that  particular  place.   If  no  one  is  sending  there  the  packet is
    discarded.

    The NMA$C_PCLI_DES parameter (see below) is required if  NMA$C_ACC_LIM  is
    used.

Whenever a protocol is shared among units all the parameter settings for  each
unit are cross-checked by XEDRIVER to insure the settings are compatible.

Protocol sharing should be  used  whenever  the  special  protocol  types  for
loopback,  system  loading,  or  remote  console functions are used.  In these
cases protocol sharing will prevent a single user from locking others out  who
need  these  capabilities  as  well.  DECnet uses its protocol type (60-03) in
exclusive use mode,  so  nonprivileged  users  cannot  interfere  with  DECnet
operations via XEDRIVER.
                                                                        Page 6


3.2.4  Shared protocol destination address (NMA$C_PCLI_DES)

This parameter is used when NMA$C_PCLI_ACC is set to NMA$C_ACC_LIM to  specify
the  address  this  unit is going to communicate with.  See the NMA$C_PCLI_ACC
parameter above.



3.2.5  Promiscious mode (NMA$C_PCLI_PRM)

Promiscious mode is used to defeat the normal  blocking  of  incoming  packets
whose  destination  addresses  do not match the DEUNA's physical address.  All
packets regardless of physical address will be received if this mode is active
(NMA$_STATE_ON).  The default is promiscious mode off (NMA$_STATE_OFF).

A promiscious mode user receives absolutely every packet that arrives  on  the
network,  including  any  packets  received  by other users of the same DEUNA.
XEDRIVER contains special packet duplication code so  who  needs  each  packet
gets their own copy.

Promiscious mode also makes it possible to  send  packets  with  an  arbitrary
protocol  type  code.   The  protocol type for each packet transmitted must be
specified in the P5 buffer of each write $QIO.

Only one unit can have promiscious mode activated,  so  whoever  turns  it  on
first  is  the  only one who can use it.  Activating promiscious mode requires
PHY_IO privilege.  DECnet does not use promiscious mode.



3.2.6  Echo mode (NMA$C_PCLI_EKO)

The DEUNA has the option of  either  receiving  or  ignoring  the  packets  it
transmits  itself.   If  echo (or "half duplex") mode is off the DEUNA ignores
its own transmissions (NMA$C_STATE_OFF).  If echo mode is on  (NMA$C_STATE_ON)
any  packet that is sent will also be eligible for reception.  Echo mode is on
by default.

Echo mode is not available on the DEQNA and this parameter  cannot  be  turned
on.

Packets received via echoing  are  treated  in  the  same  manner  as  packets
obtained  from  the  network  --  the  destination  address  and protocol type
determine who, if anyone, gets the echoed packet.

Echoed packet's checksums are not checked by  the  DEUNA  hardware.   However,
XEDRIVER  recognizes  this  fact  and  computes  checksums  for echoed packets
automatically.

Echo reception is a hardware feature of the DEUNA and thus everyone using  the
device  must  agree  on  the  setting  of  this parameter.  You have to be the
exclusive user of the DEUNA to  change  the  setting  of  echo  mode.   DECnet
insists that echo mode be off.

If echo mode is turned on you can do wierd things like activating default user
mode  and  sending a packet to another user of the device.  It is particularly
useful for debugging, when you have no idea of what you  are  sending  to  the
                                                                        Page 7


network  and  want to receive and check it.  DECnet must be shut down in order
to perform such debugging operations.



3.2.7  Internal loopback or controller mode (NMA$C_PCLI_CON)

If internal loopback mode is active the DEUNA's transmitter is looped back  to
the receiver and the entire device is isolated from the network.  This is very
similar to echo mode except for the enforced isolation from the network.

Loopback mode is a hardware feature of the DEUNA and setting it  will  prevent
the  device from receiving any incoming packets.  Consequently, you have to be
the exclusive user of the DEUNA to turn on loopback mode.   Loopback  mode  is
off by default, and DECnet requires that it remain off, of course.

The DEUNA will not respond to any  special  protocol  type  function  requests
while  in  internal loopback mode.  (Don't confuse internal loopback mode with
the loopback protocol type -- they are NOT the same thing.  The  former  is  a
loopback to the local host CPU, while the latter is a loopback to someone else
on the network.)

The  I/O  User's  Guide  claims   that   the   symbols   NMA$C_LINCN_NOR   and
     ___  ______  _____
NMA$C_LINCN_LOO  are  used  to  control  loopback  mode.  These symbols do not
exist.   Use  NMA$C_STATE_ON  for  NMA$C_LINCN_NOR  and  NMA$C_STATE_OFF   for
NMA$C_LINCN_LOO.  These are the symbols used in XEDRIVER, at least.

Loopback mode should be used when debugging a DEUNA  connected  to  an  active
network  to  prevent  any  possible  interference with that network from buggy
programs.



3.2.8  Multicasting (NMA$C_PCLI_MLT and NMA$C_PCLI_MCA)

Multicasting is a feature whereby the  DEUNA  can  be  instructed  to  receive
messages  with addresses other than the current physical address.  Any packets
sent to these "multicast" addresses will be  received  and  processed  by  the
DEUNA.

Multicasting should not be confused with broadcast messages.  The  DEUNA,  and
in  fact every other standard Ethernet interface, will always receive messages
addressed to FF-FF-FF-FF-FF-FF (the standard broadcast address) regardless  of
the setting of the current physical address.

Note:  Physical addresses must have a 0 in the least significant bit of  their
first byte, while multicast addresses must have a 1 in this position.

Each unit can enable or disable multicasting independently and set up its  own
list  of  multicast  addresses.   The  lists  from  all  the various units are
combined by XEDRIVER  and  sent  to  the  DEUNA  hardware.   Due  to  hardware
limitations,  a  total of 10 different addresses can be nominated as multicast
addresses by all the units combined.

There  are   two   parameters   that   control   multicasting.    The   first,
NMA$C_PCLI_MLT,  is  used  to  turn on and off the entire multicasting system.
Multicasting  is  activated  by  setting  NMA$C_PCLI_MLT  to   NMA$C_STATE_ON.
                                                                        Page 8


NMA$C_STATE_OFF is the default.

The NMA$C_PCLI_MCA parameter is used to specify the current list of  multicast
addresses.   This parameter's value is a counted string of bytes formed in the
same fashion as the NMA$C_PCLI_PHA parameter's value is.   The  modifier  word
must be one of:

    NMA$C_LINMC_SET - Add these addresses to the list
    NMA$C_LINMC_CLR - Remove these addresses from the list
    NMA$C_LINMC_CAL - Clear the entire list unconditionally

The multicasting address list is initially empty.

DECnet enables only a single multicasting address, so 9  slots  are  left  for
users if DECnet is running (as of VMS version 3.5, at least).



3.2.9  Number of receive buffers (NMA$C_PCLI_BFN)

This parameter specifies the number of receive buffers to maintain  in  system
memory for this unit.  Each unit must specify a (possibly different) value for
this parameter.



3.2.10  Size of receive buffers (NMA$C_PCLI_BUS)

The maximum size of user packet buffers on this  unit  is  specified  by  this
parameter.   Each unit may choose its own receive buffer size.  The default if
this parameter is left  unspecified  is  512.   The  minimum  value  for  this
parameter is 46, the maximum 1500.

Transmit buffers are allocated automatically by XEDRIVER as  they  are  needed
and  can  be  of  any  size  up  1500 bytes.  (See the sections on padding and
checksumming below for the true limits on the size of a transmitted packet.)



3.2.11  Data chaining (NMA$C_PCLI_DCH)

Messages may be received by the DEUNA that will not fit into a single  receive
buffer.   If  data chaining is on (NMA$C_STATE_ON) the DEUNA has the option of
splitting a received packet and placing it in two or more receive buffers.  If
data  chaining  is  off (NMA$C_STATE_OFF) all packets will be truncated to fit
into a single receive buffer.  Data chaining is on by default.

Data chaining is useful  in  avoiding  having  excessive  buffers  when  large
numbers  of  irregularly  sized packets are expected.  On the other hand, data
chaining could have a tendency to fill too many of the available buffers  when
anomalously  large packets are received.  Since normal buffer sizes are fairly
small (around  512  bytes),  data  chaining  is  recommended  for  almost  all
applications.

Each unit can choose whether or not the packets it receives will  be  eligible
for data chaining.
                                                                        Page 9


3.2.12  Checksum computation (NMA$C_PCLI_CRC)

Ethernet packets normally have a 32 bit check sequence  appended  to  them  to
insure  detection  of  network  errors.   The  check  is  a CRC code with this
generating polynomial:

G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 +
       x^8 + x^7 + x^5 + x^4 + x^2 + x + 1

The entire Ethernet packet, including the destination address, source address,
protocol  type  field  and  data  is  checksummed.  The packet is treated as a
binary polynomial M(x) which is divided by G(x) to produce a  remainder  R(x).
The  check  sequence  is the complement of R(x), with the most significant bit
corresponding to the highest term in R(x).

The receiver runs the entire packet including the checksum, through  the  same
algorithm,  at  which time if the packet is valid the checksum register should
contain the value C704DD7D.  Receiver checksumming cannot be disabled.

Checksums are also returned at the end of the packet by the IO$_READVBLK  $QIO
if  there  is room for it in the supplied buffer, although the reported length
of the packet does not include the checksum.  The checksum is returned so  the
user  can  check to make sure that packets are being properly transferred from
the DEUNA to the VAX.  A  VAX  CRC  instruction  can  be  used  to  check  the
checksum.   The  XEDRIVER  source contains a list of the required coefficients
(see CRCTABLE and the routine ASSEM_PKTS).

Computation  of  checksums  on  transmitted  packets  will  be   disabled   if
NMA$C_PCLI_CRC  is  set to NMA$C_STATE_OFF.  In addition, the operation of all
special protocol types like loopback or remote console will be inhibited.  The
default for checksumming is initially NMA$C_STATE_ON, or alternately the value
the first user of the DEUNA set it to.

The NMAC_PCLI_CRC parameter is permanently set to NMA$C_STATE_ON on the  DEQNA
and cannot be turned off.

The CRC takes up space in outgoing packets so its presence or absence  affects
the  maximum allowable packet size -- see the description of padding below for
more information.

The CRC is computed in hardware, so the setting of this parameter affects  all
users of the DEUNA.  Exclusive usage rights are required to change the setting
of this parameter.  DECnet requires that CRC checking be active.



3.2.13  Message padding (NMA$C_PCLI_PAD)

The Ethernet specification imposes a minimum length limit on all packets.  The
DEUNA  can  optionally  extend  all  packets  to  meet this requirement.  This
hardware facility is always enabled by XEDRIVER.  However,  XEDRIVER  contains
its  own  message padding facility that allows the lengths of short packets to
be preserved.   It  is  this  facility  of  XEDRIVER,  and  not  the  hardware
capability that is controlled by this parameter.

If NMA$C_PCLI_PAD is disabled (NMA$C_STATE_OFF) all transmitted  packets  must
be  at  least  46  bytes  long  including  checksum.   Shorter packets will be
                                                                       Page 10


extended and transmitted, but their lengths will be  arbitrarily  extended  to
the 46 byte minimum by the DEUNA.

Enabling NMA$C_PCLI_PAD (NMA$C_STATE_ON) causes XEDRIVER to take some  special
actions.   A  length  word  is  placed between the header and the data in each
outgoing packet.  The packet is then extended, if need  be,  and  transmitted.
Upon  reception,  the  length  word  is  removed and is used in lieu of length
returned by the DEUNA.  XEDRIVER padding is on by default.

IMPORTANT:  The presence of the length word in a padded  packet  makes  padded
and  unpadded  packets INCOMPATIBLE.  Transmitters and receivers MUST agree on
whether or not to pad their packets or errors will occur.  For example, 4.2BSD
TCP/IP  does  not  pad  its  packets  so the default of packet padding must be
changed by VMS TCP/IP.

Since padding adds some  overhead  to  each  packet  it  changes  the  maximum
allowable  size  of  a  packet.  The following table shows the maximum size of
packets for the each possible padding and checksumming setting:

padding on, checksumming on   = 1494   bytes maximum size
padding off, checksumming on  = 1496
padding on, checksumming off  = 1498
padding off, checksumming off = 1500



3.2.14  Device buffer size (NMA$C_PCLI_BSZ)

This parameter controls the size of the hardware packet  buffer  used  by  the
DEUNA.   It  affects  all  users of the device and exclusive access rights are
required to change its value.  Under normal  conditions  it  should  never  be
changed from its default value of 1500.  Obviously, DECnet will not approve of
changes to this parameter's value.



3.2.15  Protocol selection mode (NMA$C_PCLI_PRO)

This  undocumented  parameter  is  used  to  select  between  normal   network
operations  and  point-to-point  communications.   Specifics  on  its  use are
unavailable at this time.



3.2.16  Hardware buffer quota (NMA$C_PCLI_HBQ)

This  undocumented  parameter's  function  is  unknown.   It  is,  however,  a
write-only parameter and cannot be read back with a IO$_SENSEMODE operation.



3.2.17  Parameter summary

Summing up, there are four basic categories of parameters:

                                                                       Page 11


    (1)  Mandatory parameters every unit must specify:

         NMA$C_PCLI_PTY, NMA$C_PCLI_BFN

    (2)  Optional parameters any user can specify:

         NMA$C_PCLI_ACC,   NMA$C_PCLI_DES,   NMA$C_PCLI_BUS,   NMA$C_PCLI_PAD,
         NMA$C_PCLI_MLT, NMA$C_PCLI_MCA, NMA$C_PCLI_DCH

    (3)  Optional paramaters at most one user can use:

         NMA$C_PCLI_PRM

    (4)  Optional parameters requiring exclusive usage rights:

         NMA$C_PCLI_PHA,   NMA$C_PCLI_EKO,   NMA$C_PCLI_CON,   NMA$C_PCLI_CRC,
         NMA$C_PCLI_BSZ




3.3  Starting the DEUNA

A $QIO IO$_SETMODE function with a IO$M_STARTUP modifier is used to  start  up
the  DEUNA.   This  runs  the onboard diagnostics, which take about 6 seconds.
After the diagnostics complete the device is ready for I/O  operations.   Only
the first user of the device has to wait for the diagnostics to run.

The operations of setting DEUNA parameters and actually  starting  the  device
may  be  combined  in  the  same  $QIO  if both the IO$M_CTRL and IO$M_STARTUP
modifiers are used together.  Thus, the steps  configuring  and  starting  the
device can be combined.



3.4  I/O operations

Normal $QIO read and write operations are used to transfer packets to and from
the DEUNA.  The usual IO$_READVBLK and IO$_WRITEVBLK functions should be used.



3.4.1  Write $QIO parameters

The P5 parameter of the IO$_WRITEVBLK $QIO specifies to  whom  the  packet  is
being  sent;   the  actual packet data (pointer in P1) contains only data.  P2
specifies the length of the data block, all the other parameters are unused.

P5 must point to an 8 byte buffer.  The first 6 bytes specify the  destination
address for the packet, while the last 2 bytes specify the protocol type.  The
protocol type is ignored unless in promiscious mode.  If promiscious  mode  is
active  this  protocol  specification  overrides  the  one  specified  by  the
NMA$C_PCLI_ACC IO$_SETMODE parameter.

The P5 parameter is ignored if a non-exclusive shared protocol type  is  being
used -- XEDRIVER already knows who to send the message to.
                                                                       Page 12


3.4.2  Read $QIO parameters

Read $QIO requests require the address of a buffer for the packet  in  P1  and
the  length of that buffer as P2.  P5 can optionally point to a 14 byte buffer
that will receive the destination address, the source address and the protocol
type  (in  that  order).   The  destination  address may be either physical or
multicast, the source address is always physical.  The protocol type may  vary
from that set by NMA$C_PCLI_ACC if promiscious mode is enabled.  The P5 buffer
is not needed when communicating with a single other DEUNA on the Ethernet  --
you should already know all the information the buffer can provide.

The length of the packet received can only  be  determined  by  examining  the
transfer  size field (the second word) in the I/O status block, so the IOSB is
usually specified in read $QIO requests to the DEUNA.

 by  examining  the
transfer  size field (the second word) in the I/O status block, so the IOSB is
usually specified in read $QIO requests to the DEUNA.



3.5  Shutting down the DEUNA

After all I/O operations on the DEUNA are complete the device should  be  shut
down  in  order  to  flush  all  active buffers and return buffer space to the
system nonpaged memory pool.  A IO$_SETMODE $QIO is used  with  the  IO$M_CTRL
and IO$M_SHUTDOWN modifiers to perform this function.  Once this is applied to
a unit, the unit cannot be used for additional I/O until another  IO$M_STARTUP
function is executed.



3.6  Deassigning the DEUNA

Units attached to the DEUNA will not be dismantled until all channels to  them
are  released.   When  this  is  done  (normally  via the usual $DASSGN system
service) the  unit  will  be  deleted  and  all  the  parameter  settings  and
information associated with it will be destroyed.



4.0  Debugging hints

Debugging code for the DEUNA is usually pretty simple.  If error returns  from
$QIO  requests are encountered the key is to pay close attention to all values
returned in the I/O status block.  In particular, when performing  IO$_SETMODE
operations  (the  most  error-prone  of  them  all)  the code of any offending
parameter will be returned in  the  second  longword  of  the  IOSB.   If  the
erroneous  parameter was in fact specified, the value it was given is illegal.
If the parameter is one that was left unspecified, it is required and must  be
specified in order for the $QIO to work.

Any outstanding read requests will abort immediately if the DEUNA is unplugged
from  its  H4000 transceiver.  Most software can avoid problems caused by this
by waiting a bit and then requeueing its read requests.
                                                                       Page 13


5.0  Sense mode $QIO's

The IO$_SENSEMODE $QIO function can be  used  to  retrieve  various  sorts  of
information  about  the  DEUNA.   A  function  modifier  must be included with
IO$_SENSEMODE to specify what information to return.



5.1  Characteristics retrieval

If IO$_SENSEMODE is paired with the IO$M_CTRL modifier the  $QIO  will  return
device  characteristics  in  a 2 longword buffer pointed to by P1 and extended
device characteristics in a block of memory whose descriptor is pointed to  by
P2.   Both  parameters  are optional.  The returned block will be truncated to
fit within the available space in the P2 buffer.  The  actual  length  of  the
returned information will be placed in the second word of the I/O status block
if one is specified in the $QIO.

The structure of the P1 buffer is shown in figure 6-4 in the I/O User's Guide.
                                                             ___ ______ _____

The P2 buffer contains parameters that have the same format as those passed to
a  IO$_SETMODE  function.   However,  IO$_SENSEMODE tries to return the ENTIRE
list of all possible parameters in a user-supplied buffer;  you don't  get  to
pick  what  you  want.  The parameters are always returned in a specific order
and all that must be done is to make the P2 buffer long enough to get what you
want.   (Of  course, the order of the parameters may change in future versions
of the driver, so it is best to search the returned list to find  the  desired
information.  See the DEUNA monitor program below for one way of doing this in
Pascal.)

Currently, the order in which the parameters are returned is:

    (1)  NMA$C_PCLI_ACC - access mode for protocol (a)
    (2)  NMA$C_PCLI_PRO - protocol selection mode
    (3)  NMA$C_PCLI_BUS - receive buffer size
    (4)  NMA$C_PCLI_BFN - number of receive buffers
    (5)  NMA$C_PCLI_PHA - physical device address (b)
    (6)  NMA$C_PCLI_PRM - promiscious mode
    (7)  NMA$C_PCLI_MLT - multicast mode
    (8)  NMA$C_PCLI_PAD - transmit data padding
    (9)  NMA$C_PCLI_DCH - data chaining
   (10)  NMA$C_PCLI_CRC - CRC generated on transmitted packets
   (11)  NMA$C_PCLI_CON - loopback or controller mode
   (12)  NMA$C_PCLI_PTY - protocol type
   (13)  NMA$C_PCLI_MCA - multicast address list (c)
   (14)  NMA$C_PCLI_EKO - echo mode
   (15)  NMA$C_PCLI_BSZ - device buffer size
   (16)  NMA$C_PCLI_HWA - default hardware address (d)
   (17)  NMA$C_PCLI_DES - shared destination address (e)


Notes:

    (a)  Unless otherwise noted below, all parameter values  are  returned  as
         longwords.
                                                                       Page 14


    (b)  The physical device address is returned as a counted string  starting
         with a length word (always 6) and followed by the 6 byte address.  If
         no one has explicitly set an address the  address  returned  will  be
         FF-FF-FF-FF-FF-FF,   NOT   the   default   hardware   address.    The
         NMA$C_PCLI_HWA parameter always returns the default hardware address.

    (c)  The multicast address list is returned as a counted string containing
         all the addresses.  There is no modifier word in the list.

    (d)  NMA$C_PLCI_HWA always returns the default hardware address regardless
         of  what the physical address is set to.  It is returned as a counted
         string with no modifier word.

    (e)  NMA$C_PLCI_DES is only returned to the shared-protocol users to  whom
         it  applies  (i.e.   NMA$C_PCLI_ACC  is set to NMA$C_ACC_LIM).  It is
         returned as a counted string with no modifier word.


See the XEDRIVER  source  (in  particular,  the  table  LINE_PARAM)  for  more
information on these parameters.



5.2  Usage counters

The IO$_SENSEMODE function also has an undocumented  function  modifier.   The
DEUNA  maintains  a slew of statistics about what activities it has performed.
These counters may be read using the  function  modifier  IO$M_RD_COUNT  along
with  IO$M_CTRL.   If IO$M_CLR_COUNT is used as well the counters are read and
then zeroed.  The counters returned are in the order defined by  the  hardware
starting  with  the  seconds  since  the  counters were last zeroed.  Refer to
figure 4-16 (page 4-31) of the DEUNA User's Guide (NOT the I/O  User's  Guide)
                               _____ ______ _____          ___  ______  _____
for  a  complete list of all the counters.  See the program at the end of this
article for a demonstration of how to read the returned parameter block.   The
actual  structure  of  the parameter block is similar in form to all the other
DEUNA parameter blocks.

The counters apply to the whole DEUNA and reflect the activities  of  everyone
using  the  device,  but  it  seems  that any user can read or clear them with
impunity.



6.0  SYSGEN parameter considerations

Due to the potentially large size of Ethernet packets you should watch  system
nonpaged  pool  carefully when using a DEUNA (especially when TWO programs are
using it at the same time).  The pool may be exhausted and cause the system to
hang.

A possible cause of SS$_EXQUOTA errors is that the  SYSTEM  parameter  MAXBUF,
which controls the maximum size of an I/O buffer, is set to too small a value.
(The routine EXE$ALLOCBUF allocates such buffers for XEDRIVER and checks  this
limit.)  The  default value for MAXBUF is around 1300 bytes, while the maximum
Ethernet packet size is 1500 bytes.
                                                                       Page 15


7.0  A DEUNA monitoring program

The following program monitors DEUNA performance by periodically sampling  the
internal  hardware  counters  via  a  $QIO.   Both  transmission and reception
information  is  presented   in   the   form   of   "current"   (e.g.    bytes
received/second),  "average"  (e.g.  average bytes received/second), "minimum"
and "maximum" (e.g.  minimum and maximum bytes received/second) and  "counter"
(e.g.   present value of the DEUNA's bytes received counter).  The result is a
MONITOR-like display of DEUNA activity.

XEA0 is monitored by default.  If you want to monitor a different device, just
define  a  symbol to run the program.  The device name to monitor will then be
read off the command line with a LIB$GET_FOREIGN call.

The program begins operations by clearing the terminal screen and drawing  its
display.   To exit type either control-c or control-z.  To repaint the screen,
type contrl-w.  The counters will be reset if the "seconds since  last  reset"
counter  exceeds  65530.   The  counters  can  be  reset  manually  by  typing
control-r.

The program uses the protocol type  61-02,  which  is  not  reserved  for  any
specific  purpose.   This  protocol  type  can be changed if it conflicts with
anything.  The program is written in VAX Pascal V2  and  requires  no  special
privileges.

(* Monitor DEUNA performance statistics.
   Written by Dan Newman and Ned Freed, 21-July-84,
   MATHLIB Project, Harvey Mudd College *)

[inherit ('SYS$LIBRARY:STARLET.PEN')] Program DEUNA;
Const
  NMA$C_PCLI_BFN  = %x451; NMA$C_PCLI_PTY  = %xB0E; NMA$C_CTLIN_ZER = %x000;
  NMA$C_CTLIN_DBR = %x3F2; NMA$C_CTLIN_MBL = %x3F4; NMA$C_CTLIN_RFL = %x426;
  NMA$C_CTLIN_BRC = %x3E8; NMA$C_CTLIN_MBY = %x3EA; NMA$C_CTLIN_OVR = %x428;
  NMA$C_CTLIN_LBE = %x411; NMA$C_CTLIN_DBS = %x3F3; NMA$C_CTLIN_MBS = %xA8D;
  NMA$C_CTLIN_BSM = %x3F7; NMA$C_CTLIN_BS1 = %x3F6; NMA$C_CTLIN_BID = %x3F5;
  NMA$C_CTLIN_BSN = %x3E9; NMA$C_CTLIN_MSN = %xA8E; NMA$C_CTLIN_SFL = %x424;
  NMA$C_CTLIN_CDC = %x425; NMA$C_CTLIN_UFD = %x427;
Type
  UnsignedWord = [Word] 0..65535; $Word = [Word] -32768..32767;
  CounterType = array [1..256] of unsigned;
  Counters = (BRC, DBR, MBY, MBL, RFL, OVR, LBE, BSN, DBS, MSN, MBS,
              BID, SFL, BSM, BS1, CDC, UFD);
  StartupType = Record
    PCLI_BFN       : UnsignedWord; PCLI_BFN_VALUE : unsigned;
    PCLI_PTY       : UnsignedWord; PCLI_PTY_VALUE : unsigned;
  end; (* StartupType *)
  StatType = Record
    Current, Previous           : array [Counters] of unsigned;
    Rate, Accumulated, Min, Max : array [Counters] of real;
  end; (* StatType *)
Var
  DEUNAChannel, TTYChannel : $Word; Count, Flag, Status : integer := 0;
  CounterBuffer : CounterType; StartupBuffer : StartupType; Stats : StatType;
  CounterDescriptor, IOStatus, StartupDescriptor : array [1..2] of integer;
  CurrentTime, LastTime : unsigned; Exit : boolean := false;
  DeviceName : varying [20] of char; DeviceNameLength : integer;
                                                                       Page 16


  First : boolean := true; Index : Counters;
  Lines : array [Counters] of integer;
  LongPointer : ^unsigned; WordPointer : ^UnsignedWord;

[Unbound, External (LIB$GET_FOREIGN)] Function $GetForeign (
  var GetStr : varying [l1] of char;
  Prompt : [Class_S] packed array [l2..u2 : integer] of char := %Immed 0;
  %Ref OutLen, Force : integer := %Immed 0) : integer; extern;

[Unbound, External (LIB$STOP)] Function $STOP (
  %Immed Error : integer) : integer; extern;

[Unbound, External (LIB$SET_BUFFER)] Function $SetBuffer (
  Buffer : [Class_S] packed array [l1..u1 : integer] of char := %Immed 0;
  %Ref OldBuffer : packed array [l2..u2 : integer] of char := %Immed 0)
  : integer; extern;

[Unbound, External (LIB$PUT_BUFFER)] Function $PutBuffer (
  %Ref OldBuffer : packed array [l1..u1 : integer] of char := %Immed 0)
  : integer; extern;

[Unbound, External (LIB$PUT_SCREEN)] Function $PutScreen (
  Text : [Class_S] packed array [l1..u1 : integer] of char;
  %Ref LineNo, ColNo, Flags : integer) : integer; extern;

[Unbound, External (LIB$ERASE_PAGE)] Function $ErasePage (
  %Ref LineNo, ColNo : integer := %Immed 0) : integer; extern;

Function Min (Real1, Real2 : real) : real;
  Begin Min := Real1; if Real2 < Real1 then Min := Real2; End;

Function Max (Real1, Real2 : real) : real;
  Begin Max := Real1; if Real2 > Real1 then Max := Real2; End; (* Max *)

Procedure IncrementPointers (Inc : integer);
  Begin (* IncrementPointers *)
    LongPointer::unsigned := LongPointer::unsigned + Inc;
    WordPointer::unsigned := WordPointer::unsigned + Inc;
  End; (* IncrementPointers *)

Procedure ReadCounterBuffer;
  var CurrentCounter : UnsignedWord; i : integer;
  Begin (* ReadCounterBuffer *)
    WordPointer := nil; LongPointer := nil;
    IncrementPointers (Iaddress (Counterbuffer));
    while LongPointer::unsigned < Iaddress (Counterbuffer) + 
                                      size (Counterbuffer) do begin
      CurrentCounter := WordPointer^;
      IncrementPointers (2);
      i := int (uand (%xFFF, CurrentCounter));
      if CurrentCounter = 0 then IncrementPointers (256)
        else if i = NMA$C_CTLIN_ZER then CurrentTime := WordPointer^
        else if i = NMA$C_CTLIN_DBR then Stats.Current[DBR] := LongPointer^
        else if i = NMA$C_CTLIN_MBL then Stats.Current[MBL] := LongPointer^
        else if i = NMA$C_CTLIN_RFL then Stats.Current[RFL] := WordPointer^
        else if i = NMA$C_CTLIN_BRC then Stats.Current[BRC] := LongPointer^
        else if i = NMA$C_CTLIN_MBY then Stats.Current[MBY] := LongPointer^
                                                                       Page 17


        else if i = NMA$C_CTLIN_OVR then Stats.Current[OVR] := WordPointer^
        else if i = NMA$C_CTLIN_LBE then Stats.Current[LBE] := WordPointer^
        else if i = NMA$C_CTLIN_DBS then Stats.Current[DBS] := LongPointer^
        else if i = NMA$C_CTLIN_MBS then Stats.Current[MBS] := LongPointer^
        else if i = NMA$C_CTLIN_BSM then Stats.Current[BSM] := LongPointer^
        else if i = NMA$C_CTLIN_BS1 then Stats.Current[BS1] := LongPointer^
        else if i = NMA$C_CTLIN_BID then Stats.Current[BID] := LongPointer^
        else if i = NMA$C_CTLIN_BSN then Stats.Current[BSN] := LongPointer^
        else if i = NMA$C_CTLIN_MSN then Stats.Current[MSN] := LongPointer^
        else if i = NMA$C_CTLIN_SFL then Stats.Current[SFL] := WordPointer^
        else if i = NMA$C_CTLIN_CDC then Stats.Current[CDC] := WordPointer^
        else if i = NMA$C_CTLIN_UFD then Stats.Current[UFD] := WordPointer^;
      if CurrentCounter > %xCFFF then IncrementPointers (4)
                                 else IncrementPointers (2);
    end; (* while *)
  End; (* ReadCounterBuffer *)

Procedure PutScreen (Text : packed array [l1..u1 : integer] of char;
  LineNo, ColNo, Flags : integer);
  var Status : integer;
  Begin (* PutScreen *)
    Status := $PutScreen (Text, LineNo, ColNo, Flags);
    if not odd (Status) then $STOP (Status);
  End; (* PutScreen *)

Procedure UpdateLine (Rate, Average, Min, Max : real; Current : unsigned;
  LineNo : integer);
  var String : varying [9] of char;
  Begin (* UpdateLine *)
    writev (String, Rate:7:1); PutScreen (String, LineNo, 37, 0);
    writev (String, Average:7:1); PutScreen (String, LineNo, 46, 0);
    writev (String, Min:7:1); PutScreen (String, LineNo, 55, 0);
    writev (String, Max:7:1); PutScreen (String, LineNo, 64, 0);
    writev (String, Current:9); PutScreen (String, LineNo, 72, 0);
  End; (* UpdateLine *)

Procedure Update;
  var
    Buffer : packed array [1..1000] of char; String : varying [7] of char;
    Date : packed array [1..23] of char; Index : Counters; Status : integer;
  Begin (* Update *)
    (* Set up the screen buffer *)
    Status := $SetBuffer (Buffer); if not odd (Status) then $STOP (Status);
    (* Get the date *)
    $ASCTIM (,Date); 
    for Status := 23 downto 13 do Date[Status] := Date[Status-1];
    (* Build the Buffer *)
    PutScreen (Date, 2, 29, 0);
    for Index := BRC to UFD do
      UpdateLine (Stats.Rate[Index], Stats.Accumulated[Index]/Count,
                  Stats.Min[Index], Stats.Max[Index],
                  Stats.Current[Index], Lines[Index]);
    writev (String, CurrentTime:6);
    Status := 1; While String[Status] = ' ' do Status := succ (Status);
    PutScreen (substr (String, Status, 1+length(String)-Status), 24, 35, 0);
    (* Post the buffer to the screen via one $QIO *)
    Status := $PutBuffer; if not odd (Status) then $STOP (Status);
                                                                       Page 18


    (* Stop blocking the AST's *)
    Status := $SETAST (1); if not odd (Status) then $STOP (Status);
    (* See if the "Resetting the Counters" flag needs to be removed *)
    if Flag = 2 then begin
      Flag := 0; PutScreen ('                      ', 1, 59, 0);
      PutScreen ('            ', 24, 35, 0);
    end; (* if Flag *)
    if Flag = 1 then Flag := succ (Flag);
  End; (* Update *)

Procedure Paint;
  var Buffer : packed array [1..900] of char; Status : integer;
  Begin (* Paint *)
    (* Set up the Screen buffer *)
    Status := $SetBuffer (Buffer); if not odd (Status) then $STOP (Status);
    (* Erase the page *)
    $ErasePage (1,1);
    (* Put up the headers *)
    PutScreen ('DEUNA Performance Statistics', 1, 26, 1);
    PutScreen ('Device', 4, 1, 0); PutScreen (DeviceName, 4, 8, 0);
    PutScreen ('Current', 4, 37, 8); PutScreen ('Average', 4, 46, 8);
    PutScreen ('Minimum', 4, 55, 8); PutScreen ('Maximum', 4, 64, 8);
    PutScreen ('Counter', 4, 74, 8); PutScreen ('Received:', 5, 1, 0);
    PutScreen ('Bytes', 6, 3, 0); PutScreen ('Packets', 7, 3, 0);
    PutScreen ('Multicast Bytes', 8, 3, 0);
    PutScreen ('Multicast Packets', 9, 3, 0);
    PutScreen ('Packets in Error', 10, 3, 0);
    PutScreen ('Lost - Internal Buffer Errors', 11, 3, 0);
    PutScreen ('Lost - Local Buffer Errors', 12, 3, 0);
    PutScreen ('Transmitted:', 13, 1, 0); PutScreen ('Bytes', 14, 3, 0);
    PutScreen ('Packets', 15, 3, 0); PutScreen ('Multicast Bytes', 16, 3, 0);
    PutScreen ('Multicast Packets', 17, 3, 0);
    PutScreen ('Packets Deferred', 18, 3, 0); 
    PutScreen ('Packets Aborted', 19, 3, 0);
    PutScreen ('Packets with Several Errors', 20, 3, 0);
    PutScreen ('Packets with 1 Error', 21, 3, 0);
    PutScreen ('Collision Check Failures', 22, 3, 0);
    PutScreen ('Unrecognized Frame Destinations', 23, 1, 0);
    PutScreen ('Seconds Since Last Counter Reset:', 24, 1, 0);
    (* Now put the info to the screen in one $QIO *)
    Status := $PutBuffer; if not odd (Status) then $STOP (Status);
  End; (* Paint *)

Procedure ResetDEUNA;
  var Status : integer;
  Begin (* ResetDEUNA *)
    Flag := 1; PutScreen ('Resetting the Counters' + chr (7), 1, 59, 3);
    Status := $QIOW (Chan := DEUNAChannel, Iosb := IOStatus,
                     Func := IO$_SENSEMODE + IO$M_CTRL + IO$M_CLR_COUNT +
                     IO$M_RD_COUNT, P2 := IAddress (CounterDescriptor));
    if not odd (Status) then $STOP (Status);
    if not odd (IOStatus[1]) then $STOP (IOStatus[1]);
    ReadCounterBuffer;
    for Index := BRC to UFD do Stats.Previous[Index] := Stats.Current[Index];
    LastTime := CurrentTime; PutScreen ('        ', 24, 34, 0);
  End; (* ResetDEUNA *)

                                                                       Page 19


Procedure EnableAST; forward;

Procedure AST (var Character : char);
  var Status : integer;
  Begin (* AST *)
    (* Kill any other I/O requests on this channel *)
    Status := $CANCEL (TTYChannel); if not odd (Status) then $STOP (Status);
    case IAddress (Character) of
      (* ^C and ^Z -- Exit gracefully *)
      03, 26 : begin
        (* Shut the DEUNA down *)
        RetStatus := $CANCEL (DEUNAChannel);
        if not odd (RetStatus) then $STOP (RetStatus);
        RetStatus := $QIOW (Chan := DEUNAChannel, Iosb := IOStatus,
                            Func := IO$_SETMODE + IO$M_CTRL + IO$M_SHUTDOWN);
        if not odd (RetStatus) then $STOP (RetStatus);
        RetStatus := $DASSGN (DEUNAChannel);
        if not odd (RetStatus) then $STOP (RetStatus);
        Exit := true; end;
      (* ^R -- Reset the DEUNA *)
      18 : ResetDEUNA;
      (* ^W -- Repaint the screen *)
      23 : begin Paint; Update; end;
    end; (* case *)
    (* Reset the AST *)
    EnableAST;
  End; (* AST *)

Procedure EnableAST;
  var Mask : array [1..2] of integer; Status : integer;
  Begin (* EnableAST *)
    (* Out-of-band AST Mask -- Trap ^C, ^R, ^W and ^Z*)
    Mask[1] := 0; Mask[2] := (2**3) + (2**18) + (2**23) + (2**26);
    (* Queue the out-of-band AST *)
    Status := $QIOW (Chan := TTYChannel, Func := IO$_SETMODE + IO$M_OUTBAND,
                     P1 := %Immed AST, P2 := IAddress (Mask));
    if not odd (Status) then $STOP (Status);
  End; (* EnableAST *)

Begin (* DEUNA *)
  (* These numbers represent which lines on the screen to place the data on *)
  Lines[BRC] :=  6; Lines[DBR] :=  7; Lines[MBY] :=  8; Lines[MBL] :=  9;
  Lines[RFL] := 10; Lines[OVR] := 11; Lines[LBE] := 12; Lines[BSN] := 14;
  Lines[DBS] := 15; Lines[MSN] := 16; Lines[MBS] := 17; Lines[BID] := 18;
  Lines[SFL] := 19; Lines[BSM] := 20; Lines[BS1] := 21; Lines[CDC] := 22;
  Lines[UFD] := 23;
  (* Setup the information to initialize the DEUNA *)
  with StartupBuffer do begin
    PCLI_BFN := NMA$C_PCLI_BFN; PCLI_BFN_VALUE := 1;
    PCLI_PTY := NMA$C_PCLI_PTY;
    PCLI_PTY_VALUE := %x0261; (* some unused protocol here *)
  end; (* with *)
  (* Build the descriptors for the $QIO calls *)
  CounterDescriptor[1] := size (CounterBuffer);
  CounterDescriptor[2] := IAddress (CounterBuffer);
  StartupDescriptor[1] := size (StartupBuffer);
  StartupDescriptor[2] := IAddress (StartupBuffer);
                                                                       Page 20


  (* Get a Channel to the terminal *)
  Status := $ASSIGN ('TT:', TTYChannel); 
  if not odd (Status) then $STOP (Status);
  (* Get a Channel to the DEUNA *)
  Status := $GetForeign (DeviceName, , DeviceNameLength);
  if not odd (Status) then $STOP (Status);
  if DeviceNameLength = 0 then DeviceName := 'XEA0';
  Status := $ASSIGN (DeviceName, DEUNAChannel);
  if not odd (Status) then $STOP (Status);
  (* Set up the ^C, ^R, ^W and ^Z traps *)
  EnableAST;
  (* Initialize the DEUNA *)
  Status := $QIOW (Chan := DEUNAChannel, Iosb := IOStatus,
                   Func := IO$_SETMODE + IO$M_STARTUP + IO$M_CTRL,
                   P2 := IAddress (StartupDescriptor));
  if not odd (Status) then $STOP (Status);
  if not odd (IOStatus[1]) then $STOP (IOStatus[1]);
  (* Start our loop *)
  Repeat
    (* Read the DEUNA counters *)
    Status := $QIOW (Chan := DEUNAChannel, Iosb := IOStatus,
                     Func := IO$_SENSEMODE + IO$M_RD_COUNT + IO$M_CTRL,
                     P2 := IAddress (CounterDescriptor));
    if not odd (Status) then $STOP (Status);
    if not odd (IOStatus[1]) then $STOP (IOStatus[1]);
    (* Dissect the returned information *)
    ReadCounterBuffer;
    (* Now generate the statisitics *)
    if CurrentTime > 65530 then ResetDEUNA else begin
      if LastTime <> CurrentTime then begin
        if First then begin
          for Index := BRC to UFD do begin
            Stats.Previous[Index] := Stats.Current[Index];
            Stats.Accumulated[Index] := 0;
            Stats.Min[Index] := maxint; Stats.Max[Index] := -1;
          end; (* for *)
        end else begin
          Count := succ (Count);
          for Index := BRC to UFD do begin
            Stats.Rate[Index] := (Stats.Current[Index] -
                       Stats.Previous[Index]) / (CurrentTime - LastTime);
            Stats.Accumulated[Index] := Stats.Accumulated[Index] +
                                        Stats.Rate[Index];
            Stats.Min[Index] := Min (Stats.Min[Index], Stats.Rate[Index]);
            Stats.Max[Index] := Max (Stats.Max[Index], Stats.Rate[Index]);
            Stats.Previous[Index] := Stats.Current[Index];
          end; (* for *)
        end; (* if First *)
        (* Display the information on the terminal *)
        if First then begin
           First := false; Paint;
        end else Update;
        if Exit then begin
           $ErasePage (1,1); $EXIT (1);
        end; (* if Exit *)
      end; (* if LastTime <> CurrentTime *)
      LastTime := CurrentTime;
                                                                       Page 21


    end; (* if CurrentTime > 65530 *)
  until 1 = 2;
End. (* DEUNA *)
-------