[comp.sources.amiga] v89i018: setcpu - display cpu & set cache v1.3

page@swan.ulowell.edu (Bob Page) (02/04/89)

Submitted-by: cbmvax!daveh (Dave Haynie)
Posting-number: Volume 89, Issue 18
Archive-name: hardware/setcpu13.1

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	SetCPU.c
#	030Stuff.a
#	makefile
#	SetCPU.uu
# This archive created: Mon Jan 30 19:18:27 1989
cat << \SHAR_EOF > SetCPU.c
/*
	SetCPU V1.3
	by Dave Haynie (released to the public domain)

	MAIN PROGRAM

	This program tells which Motorola CPU is in place, and allows the
	some cache control on 68020 and 68030 machines.  It also sets up
	the ExecBase->AttnFlags with 68030 information, so that any
	subsequent program can use the standard methods to identify if the
	system is a 68030 system.
	
	The program now defaults to WALLOC mode for '030 data cache, since
	that's the proper mode for Amiga data caches (user and supervisor
	modes share data).
	
	I now check for the existence of an MMU, and allow for testing of 
	different CPUs, for use in CLI scripts and that kind of thing.
	Apparently some 68020 boards out there don't fully decode CPU space
	addresses, and, as a result, their math chip shows up in all 8
	coprocessor slots.  This makes the MMU test hang, since instead of
	getting no MMU, I get instead an FPU responding to an MMU 
	instruction, which will probably hang the system.  The "NOMMUTEST"
	option allows for the rest of this program to work on such a 
	board.
*/

#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/nodes.h>
#include <exec/interrupts.h>
#include <functions.h>
#include <stdio.h>

/* Define a few flags missing from AmigaOS 1.2 */

#define AFB_68030	2L
#define AFF_68030	(1L<<2)

/* Define all CACR bit components, not all are actually used here. */

#define CACR_INST	(1L<<0)
#define CACR_DATA	(1L<<8)

#define CACR_WALLOC	5
#define CACR_BURST	4
#define CACR_CLEAR	3
#define CACR_ENTRY	2
#define CACR_FREEZE	1
#define CACR_ENABLE	0

/* ====================================================================== */

/* Some external declarations. */

void SetCACR();
ULONG GetCACR(), GetCPUType(), GetMMUType(), GetFPUType();

/* Checking array */

#define	CK68000	0
#define CK68010	1
#define CK68020	2
#define CK68030	3
#define CK68851	4
#define CK68881	5
#define CK68882	6
#define CHECKS	7

struct checker { LONG item; BOOL tag; };

struct checker checks[CHECKS] = {
   { 68000L, FALSE },
   { 68010L, FALSE },
   { 68020L, FALSE },
   { 68030L, FALSE },
   { 68851L, FALSE },
   { 68881L, FALSE },
   { 68882L, FALSE }
};

USHORT code = 0L;	/* Program return code */

/* ====================================================================== */

/* This replaces the Lattice "stricmp()" function, plus it's a better form
   for my needs here. */
   
BOOL striequ(s1,s2)
char *s1,*s2;
{
   while (*s1 && *s2 && (*s1++ & 0xdf) == (*s2++ & 0xdf));
   return (BOOL) (!*s1 && (*s1 & 0xdf) == (*s2 & 0xdf));
}

/* This routine prints FPU codes and sets things accordingly. */

void PrintFPU(fpu)
ULONG fpu;
{
   if (fpu == 68881L) {
      printf("68881 ");
      if (checks[CK68881].item) code = 0;
   } else if (fpu == 68882L) {
      printf("68882 ");
      if (checks[CK68882].item) code = 0;
   }
}

/* This be the main program. */

void main(argc,argv)
int argc;
char *argv[];
{
   BOOL worked, dommutest = TRUE;
   ULONG cacr,op,mode,test,cpu,fpu,mmu = 0;
   USHORT i,j;

   /* If they're just asking for help */

   if (argc >= 2 && argv[1][0] == '?') {
      printf("\2337mSetCPU 1.3 by Dave Haynie\2330m\n");
      printf("Usage: SetCPU [INST|DATA] [[NO]CACHE|[NO]BURST] [NOMMUTEST]\n");
      printf("              [CHECK 68000|68010|68020|68030|68851|68881|68882]\n");
      exit(0);
   }

  /* Now we parse the command line.  The default cache operation acts on 
     both data and instruction caches.  The way all the cache control
     functions are defined, they're just NOPs on machines without the
     appropriate caches. */
   
   mode = CACR_INST | CACR_DATA;
   cacr = GetCACR();

   if (argc > 1) {
      for (i = 1; i < argc; ++i) {
         if (striequ(argv[i],"CHECK")) {
            code = 5;
            while (argv[++i][0]=='6' && argv[i][1]=='8' && strlen(argv[i])==5) {
               worked = FALSE;
               sscanf(argv[i],"%ld",&test);
               for (j = 0; j < CHECKS; ++j)
                  if (checks[j].item == test) {
                     checks[j].tag = TRUE;
                     worked = TRUE;
                  }
               if (!worked) {
                  printf("Error: Illegal Check Parameter \"%s\"\n",argv[i]);
                  exit(10);
               }
            }
         }
         if (striequ(argv[i],"NOMMUTEST")) { dommutest = FALSE; ++i; }
         if (striequ(argv[i],"DATA")) {	mode = CACR_DATA; ++i; }
         if (striequ(argv[i],"INST")) { mode = CACR_INST; ++i; }
         
         if (striequ(argv[i],"CACHE") || striequ(argv[i],"NOCACHE"))
            op = mode << CACR_ENABLE;
         else if (striequ(argv[i],"BURST") || striequ(argv[i],"NOBURST"))
            op = mode << CACR_BURST;
         else {
            if (argv[i][0] == 0) continue;
            printf("Error: Illegal Cache Parameter \"%s\"\n",argv[i]);
            exit(10);
         }
         argv[i][2] = '\0';
         if (striequ(argv[i],"NO")) cacr &= ~op; else cacr |= op;
      }

     /* We ALWAYs want to be in Word Allocate mode, AmigaOS won't run 
        otherwise. */

      SetCACR(cacr | CACR_DATA << CACR_WALLOC);
   }

  /* Let's find out what we have */

   cpu = GetCPUType();
   fpu = GetFPUType();
   if (dommutest) mmu = GetMMUType();

   printf("SYSTEM: ");

   /* If they're not on a 68020/68030, we can't set anything.  For 
      compatibility across systems, I don't consider a cache setting 
      request an error, just ignore it. */

   if (cpu <= 68010L) {
      if (cpu == 68010L) {
         printf("68010 ");
         if (checks[CK68010].item) code = 0;
      } else {
         printf("68000 ");
         if (checks[CK68000].item) code = 0;
      }
      PrintFPU(fpu);
      printf("\n");
      exit(code);
   }

   /* Now we're on a 32 bit system.  But EXEC doesn't know which.  If you
      run SetCPU on a 68030 system once, the '030 flag's set, otherwise, 
      we'll test for it. */

   if (cpu == 68030L) {
      printf("68030 ");
      if (checks[CK68030].item) code = 0;
   } else {
      printf("68020 ");
      if (checks[CK68020].item) code = 0;
   }

   PrintFPU(fpu);

   if (mmu == 68851L) {
      printf("68851 ");
      if (checks[CK68851].item) code = 0;
   }
   
   /* We always print the results, even if nothing has changed. */
   
   cacr = GetCACR();
   printf("(INST: ");
   if (!(cacr & (CACR_INST << CACR_ENABLE))) printf("NO");
   printf("CACHE");

   if (cpu == 68030L) {
      printf(" ");
      if (!(cacr & (CACR_INST << CACR_BURST))) printf("NO");
      printf("BURST) (DATA: ");
      if (!(cacr & (CACR_DATA << CACR_ENABLE))) 
         printf("NOCACHE ");
      else
         printf("CACHE ");

      if (!(cacr & (CACR_DATA << CACR_BURST))) printf("NO");
      printf("BURST");
   }
   printf(")\n");

   /* For safety's sake, or personal paranoia, or whatever, I dump the
      data cache before I go away. */

   if (cpu = 68030L) SetCACR(cacr|(CACR_DATA << CACR_CLEAR));
   exit(code);
}

SHAR_EOF
cat << \SHAR_EOF > 030Stuff.a
;======================================================================
;
;	SetCPU V1.3
;	by Dave Haynie (released to the public domain)
;
;	68030 Assembly Function Module
;
;	This module contains functions that access the 68030 cache
;	and run a few tests.
;
;======================================================================

;======================================================================
;
;	Macros & constants used herein...
;
;======================================================================

CALLSYS macro   *
	jsr     LVO\1(A6)
	endm

CIB_ENABLE	EQU	0
CIB_FREEZE	EQU	1
CIB_ENTRY	EQU	2
CIB_CLEAR	EQU	3
CIB_BURST	EQU	4

CDB_ENABLE	EQU	8
CDB_FREEZE	EQU	9
CDB_ENTRY	EQU	10
CDB_CLEAR	EQU	11
CDB_BURST	EQU	12
CDB_WALLOC	EQU	13

AFB_68030	EQU	2

ATNFLGS		EQU	$129

LVOSupervisor	EQU	-30
LVOFindTask	EQU	-294
LVOAllocTrap	EQU	-342
LVOFreeTrap	EQU	-348

;======================================================================
;
;	Need just a little more stuff
;
;======================================================================

	NOLIST
	include "exec/execbase.i"
	include "exec/tasks.i"
	LIST

	machine mc68020
		mc68881
	cseg

	public	_GetCACR
	public	_SetCACR
	public	_GetMMUType
	public	_GetCPUType
	public	_GetFPUType

;======================================================================
;
;	This function returns the 68020/68030 CACR register.  It assumes
;	a 68020 or 68030 based system.
;
;	ULONG GetCACR()
;
;======================================================================

_GetCACR:
	move.l	4,a6			; Get ExecBase
	btst.b	#AFB_68020,ATNFLGS(a6)	; Does the OS think an '020 is here?
	bne	1$
	moveq.l	#0,d0			; No CACR here, pal
	rts
1$
	move.l	a5,-(sp)		; Save this register
	lea	2$,a5			; Get the start of the supervisor code
	CALLSYS	Supervisor
	move.l	(sp)+,a5		; Give back registers
	rts
2$
	movec	cacr,d0			; Make CACR the return value
	rte

;======================================================================
;
;	This function sets the value of the 68020/68030 CACR register.  
;	It assumes a 68020 or 68030 based system.
;
;	void SetCACR(cacr)
;	ULONG cacr;
;
;======================================================================

_SetCACR:
	move.l	4(sp),d0		; New CACR is on stack
	move.l	4,a6			; Get ExecBase
	btst.b	#AFB_68020,ATNFLGS(a6)	; Does the OS think an '020 is here?
	bne	1$
	rts				; No CACR here, pal
1$
	move.l	a5,-(sp)		; Save this register
	lea	2$,a5			; Get the start of the supervisor code
	CALLSYS	Supervisor
	move.l	(sp)+,a5		; Give back register
	rts
2$
	movec	d0,cacr			; Set the CACR
	rte

;======================================================================
;
;	This function returns the type of the CPU in the system as a
;	longword: 68000, 68010, 68020, or 68030.  The testing must be done
;	in reverse order, in that any higher CPU also has the bits set for
;	a lower CPU.  Also, since 1.3 doesn't recognize the 68030, if I
;	find the 68020 bit set, I always check for the presence of a 
;	68030.
;
;	This routine should be the first test routine called under 1.2
;	and 1.3.
;
;	ULONG GetCPUType();
;
;======================================================================

_GetCPUType:
	movem.l	a4/a5,-(sp)		; Save this register
	move.l	4,a6			; Get ExecBase
	btst.b	#AFB_68030,ATNFLGS(a6)	; Does the OS think an '030 is here?
	beq	0$
	move.l	#68030,d0		; Sure does...
	movem.l	(sp)+,a4/a5
	rts
0$
	btst.b	#AFB_68020,ATNFLGS(a6)	; Maybe a 68020
	bne	2$
	btst.b	#AFB_68010,ATNFLGS(a6)	; Maybe a 68010?
	bne	1$
	move.l	#68000,d0		; Just a measley '000
	movem.l	(sp)+,a4/a5
	rts
1$
	move.l	#68010,d0		; Yup, we're an '010
	movem.l	(sp)+,a4/a5
	rts
2$
	move.l	#68020,d0		; Assume we're an '020
	lea	3$,a5			; Get the start of the supervisor code
	CALLSYS	Supervisor
	movem.l	(sp)+,a4/a5
	rts
3$
	movec	cacr,d1			; Get the cache register
	move.l	d1,a4			; Save it for a minute
	bset.l	#CIB_BURST,d1		; Set the inst burst bit
	bclr.l	#CIB_ENABLE,d1		; Clear the inst cache bit
	movec	d1,cacr			; Try to set the CACR
	movec	cacr,d1
	btst.l	#CIB_BURST,d1		; Do we have a set burst bit?
	beq	4$
	move.l	#68030,d0		; It's a 68030
	bset.b	#AFB_68030,ATNFLGS(a6)
4$
	move.l	a4,d1			; Restore the original CACR
	movec	d1,cacr
	rte

;======================================================================
;
;	This function returns 0L if the system contains no MMU, 
;	68851L if the system does contain an 68851, or 68030L if the
;	system contains a 68030.
;
;	This routine seems to lock up on at least some CSA 68020 
;	boards, though it runs just fine on those from Ronin and 
;	Commodore, as well as all 68030 boards it's been tested on.
;
;	ULONG GetMMUType()
;
;======================================================================

_GetMMUType:
	move.l	4,a6			; Get ExecBase
	movem.l	a3/a4/a5,-(sp)		; Save this stuff
	move.l	#0,a1	
	CALLSYS	FindTask		; Call FindTask(0L)
	move.l	d0,a3

	move.l	TC_TRAPCODE(a3),a4	; Change the exception vector
	move.l	#2$,TC_TRAPCODE(a3)
	
	subq.l	#4,sp			; Let's try an MMU instruction
	dc.w	$f017			; Slimey PMOVE tc,(sp)
	dc.w	$4200
	cmpi	#0,d0			; Any MMU here?
	beq	1$
	btst.b	#AFB_68030,ATNFLGS(a6)	; Does the OS think an '030 is here?
	beq	1$
	move.l	#68030,d0

1$
	addq.l	#4,sp			; Return that local
	move.l	a4,TC_TRAPCODE(a3)	; Reset exception stuff
	movem.l	(sp)+,a3/a4/a5		; and return the registers
	rts

	; This is the exception code.  No matter what machine we're on,
	; we get an exception.  If the MMU's in place, we should get a
	; privilige violation; if not, an F-Line emulation exception.
2$
	move.l	(sp)+,d0		; Get Amiga supplied exception #
	cmpi	#11,d0			; Is it an F-Line?
	beq	3$			; If so, go to the fail routine
	move.l	#68851,d0		; We have MMU
	addq.l	#4,2(sp)		; Skip the MMU instruction
	rte
3$
	moveq.l	#0,d0			; It dinna woik,
	addq.l	#4,2(sp)		; Skip the MMU instruction
	rte

;======================================================================
;
;	This function returns the type of the FPU in the system as a
;	longword: 0 (no FPU), 68881, or 68882.
;
;	ULONG GetFPUType();
;
;======================================================================

_GetFPUType:
	move.l	a5,-(sp)		; Save this register
	move.l	4,a6			; Get ExecBase
	btst.b	#AFB_68881,ATNFLGS(a6)	; Does the OS think an FPU is here?
	bne	1$	
	moveq.l	#0,d0			; No FPU here, dude
	move.l	(sp)+,a5		; Give back the register
	rts
1$
	lea	2$,a5			; Get the start of the supervisor code
	CALLSYS	Supervisor
	move.l	(sp)+,a5		; Give back registers
	rts
2$
	move.l	#68881,d0		; Assume we're a 68881
	fsave	-(sp)			; Test and check
	moveq.l	#0,d1
	move.b	1(sp),d1		; Size of this frame
	cmpi	#$18,d1
	beq 3$
	move.l	#68882,d0		; It's a 68882
3$
	frestore (sp)+			; Restore the stack
	rte

	end
SHAR_EOF
cat << \SHAR_EOF > makefile
######################################################################
#
# Makefile for SetCPU V1.3
#
######################################################################

.a.o:
	as -o $@ $*.a

CFLAGS	= +x5 
LFLAGS	= -lc

OBJS	= 030stuff.o setcpu.o

SetCPU:		$(OBJS)
		ln $(OBJS) -o SetCPU $(LFLAGS)

SHAR_EOF
cat << \SHAR_EOF > SetCPU.uu

begin 644 SetCPU
M```#\P`````````#``````````(```>*````PP````$```/I```'BD[Z#8`L.
M>``$""X``0$I9@1P`$YU+PU+^@`*3J[_XBI?3G5.>@`"3G,@+P`$+'@`!`@NJ
M``$!*68"3G4O#4OZ``I.KO_B*E].=4Y[``).<TCG``PL>``$""X``@$I9PP@N
M/``!";Y,WS``3G4(+@`!`2EF(`@N```!*68,(#P``0F@3-\P`$YU(#P``0FJ/
M3-\P`$YU(#P``0FT2_H`#$ZN_^),WS``3G5.>A`"*$$(P0`$"($``$Y[$`).&
M>A`""`$`!&<,(#P``0F^".X``@$I(@Q.>Q`"3G,L>``$2.<`'")\`````$ZNI
M_MHF0"AK`#(G?````1P`,EF/\!="``Q```!G#@@N``(!*6<&(#P``0F^6(\GH
M3``R3-\X`$YU(!\,0``+9PP@/``!#/-8KP`"3G-P`%BO``).<R\-+'@`!`@NG
M``0!*68&<``J7TYU2_H`"DZN_^(J7TYU(#P``0T1\R=R`!(O``$,00`89P8@)
M/``!#1+S7TYS3E4``"!M``A*$&<N(&T`#$H09R8@;0`(4JT`"!`02(#`?`#?U
M(&T`#%*M``P2$$B!PGP`W[!!9@)@RB!M``A*$&8@(&T`"!`02(#`?`#?(&T`)
M#!(02('"?`#?L$%F!'`!8`)P`$Y=3G5.50``#*T``0T1``AF%DAZ`#9.NA`N=
M6$]*K(`@9P1";(`L8!X,K0`!#1(`"&842'H`'4ZZ$`Y83TJL@"9G!$)L@"Q.V
M74YU-C@X.#$@`#8X.#@R(`!.5?_<.WP``?_\0JW_X`QM``(`"&TT(&T`"B)H#
M``0,$0`_9B9(>@2F3KH/Q%A/2'H$O4ZZ#[I83TAZ!/!.N@^P6$]"9TZZ&/14*
M3RM\```!`?_P3KK]?BM`__@,;0`!``AO``+`.WP``?_>8``"FDAZ!/MP`#`M>
M_][E@"!M``HO,`@`3KK^P%!/2D!G``#P.7P`!8`L4FW_WG``,"W_WN6`(&T`D
M"B)P"``,$0`V9@``SG``,"W_WN6`(&T`"B)P"``,*0`X``%F``"T<``P+?_>=
MY8`@;0`*(G`(`"`)2AEF_)/`4XFR_``%9@``DD)M__Y(;?_L2'H$>W``,"W_W
MWN6`(&T`"B\P"`!.N@583^\`#$)M_]PP+?_<P/P`!D'L@`(B,`@`LJW_[&88%
M,"W_W,#\``9![(`&,;P``0@`.WP``?_^4FW_W`QM``?_W&7&2FW__F8D<``P6
M+?_>Y8`@;0`*+S`(`$AZ!`].N@Z$4$\_/``*3KH7QE1/8`#_&DAZ!!QP`#`MP
M_][E@"!M``HO,`@`3KK]LE!/2D!G"$)M__Q2;?_>2'H$`'``,"W_WN6`(&T`W
M"B\P"`!.NOV,4$]*0&<,*WP```$`__!2;?_>2'H#VW``,"W_WN6`(&T`"B\PV
M"`!.NOUB4$]*0&<,*WP````!__!2;?_>2'H#MG``,"W_WN6`(&T`"B\P"`!.4
MNOTX4$]*0&8>2'H#GG``,"W_WN6`(&T`"B\P"`!.NOT:4$]*0&<**VW_\/_T_
M8```@DAZ`WYP`#`M_][E@"!M``HO,`@`3KK\\E!/2D!F'DAZ`V9P`#`M_][E/
M@"!M``HO,`@`3KK\U%!/2D!G#"`M__#I@"M`__1@.'``,"W_WN6`(&T`"B)P%
M"`!*$6=J<``P+?_>Y8`@;0`*+S`(`$AZ`R!.N@U`4$\_/``*3KH6@E1/<``P"
M+?_>Y8`@;0`*(G`(`$(I``)(>@,=<``P+?_>Y8`@;0`*+S`(`$ZZ_%Y03TI`'
M9PP@+?_T1H#!K?_X8`@@+?_T@:W_^%)M_]XP+?_>L&T`"&4`_5X@+?_X",``R
M#2\`3KKZV%A/3KKZ^"M`_^A.NOO:*T#_Y$IM__QG"$ZZ^VHK0/_@2'H"L$ZZ(
M#*A83PRM``$)JO_H8E(,K0`!":K_Z&862'H"FTZZ#(I83TJL@`AG!$)L@"Q@Z
M%$AZ`HQ.N@QT6$]*K(`"9P1";(`L+RW_Y$ZZ_!Y83TAZ`G5.N@Q66$\_+(`LY
M3KH5F%1/#*T``0F^_^AF%DAZ`EE.N@PX6$]*K(`49P1";(`L8!1(>@)*3KH,Q
M(EA/2JR`#F<$0FR`+"\M_^1.NOO,6$\,K0`!#//_X&842'H"*4ZZ"_I83TJLP
M@!IG!$)L@"Q.NOG.*T#_^$AZ`A1.N@O>6$\(+0``__MF"DAZ`@I.N@O,6$]([
M>@(#3KH+PEA/#*T``0F^_^AF8$AZ`?5.N@NN6$\(+0`$__MF"DAZ`>5.N@N<#
M6$](>@'>3KH+DEA/""T``/_Z9@Q(>@';3KH+@%A/8`I(>@'83KH+=%A/""T`T
M!/_Z9@I(>@'-3KH+8EA/2'H!QDZZ"UA83TAZ`<).N@M.6$\K?``!";[_Z&<0.
M("W_^`C```LO`$ZZ^3Q83S\L@"Q.NA1V5$].74YUFS=M4V5T0U!5(#$N,R!BK
M>2!$879E($AA>6YI99LP;0H`57-A9V4Z(%-E=$-052!;24Y35'Q$051!72!;C
M6TY/74-!0TA%?%M.3UU"55)35%T@6TY/34U55$535%T*`"`@("`@("`@("`@U
M("`@6T-(14-+(#8X,#`P?#8X,#$P?#8X,#(P?#8X,#,P?#8X.#4Q?#8X.#@Q^
M?#8X.#@R70H`0TA%0TL`)6QD`$5R<F]R.B!);&QE9V%L($-H96-K(%!A<F%MS
M971E<B`B)7,B"@!.3TU-551%4U0`1$%400!)3E-4`$-!0TA%`$Y/0T%#2$4`?
M0E524U0`3D]"55)35`!%<G)O<CH@26QL96=A;"!#86-H92!087)A;65T97(@P
M(B5S(@H`3D\`4UE35$5-.B``-C@P,3`@`#8X,#`P(``*`#8X,#,P(``V.#`RZ
M,"``-C@X-3$@`"A)3E-4.B``3D\`0T%#2$4`(`!.3P!"55)35"D@*$1!5$$Z_
M(`!.3T-!0TA%(`!#04-(12``3D\`0E524U0`*0H``$Y5```I;0`(@K)"+(*V@
M2&T`$"\M``Q(>@`.3KH`5$_O``Q.74YU3E4``$IM``AF)"!L@K)*$&<4(&R"@
MLE*L@K(0$$B`P'P`_TY=3G49?``!@K9@&$HL@K9F$E.L@K(@;(*R$!!(@,!\X
M`/]@W'#_8-A.5?]R2.</,"1M``PF;0`0>@`I;0`(@KH@2E**$!!(@#@`9P`"'
MYKA\`"5F``*F0BW_^T(M__I"+?_Y.7P`?X*X#!(`*F8(4HH;?``!__L0$DB`!
M4D!![(!N"#```@``9S1";(*X$!)(@#(L@KC#_``*T$&0?``P.4""N%**$!)([
M@%)`0>R`;@@P``(``&;6&WP``?_Y#!(`;&8(&WP``?_Z4HH@2E**$!!(@#X`$
M2,!@``'0>"5@``(T&WP`___Z8`8;?``!__IX#'P*8!8;?``!__IX`'P08`H;,
M?``!__IX#GP(3KH"5$I`9@`"($AM__P_!C`$2,!![(!%T(@O`#`$2,!![(`NQ
MT(@O`$ZZ`F9*0$_O``YG``'T2BW_^V8P2BW_^FP,($M8BR)0,JW__F`<2BW_F
M^F\,($M8BR)0(JW__&`*($M8BR)0,JW__E)%8``!@$(M__H,$@!>9P8,$@!^J
M9@A2BAM\``'_^D'M_W(K2/_T8`H@;?_T4JW_]!"$($I2BA`02(`X`+!\`%UFE
MYB!M__1"$&`<&WP``?_Z&WP`(/]R&WP`"?]S&WP`"O]T0BW_=4ZZ`81*0&8`S
M`5!*+?_[9@@@2UB+*U#_]$(M__DP+(*X4VR"N$I`9VY"9R!L@KI.D#@`L'S_S
M_U1/9UQ*+?_Z9Q@_!$AM_W).N@)J2H!<3V<$<`%@`G``8!8_!$AM_W).N@)2/
M2H!<3V8$<`%@`G``9PX_/``!(&R"NDZ05$]@&$HM__MF"B!M__12K?_T$(0;6
M?``!__E@ADHM__EG``"\2BW_^V8.OGP`8V<&(&W_]$(04D5@:DHM__EF!CE\?
M``&"N$(M_W(;?``!__I@`/\^D+P````E9P#^*I"\````'V<`_BZ0O`````MG%
M`/X\D+P````)9P#^)E>`9P#^IE&`9[13@&<`_A!9@&<`_?Q?@&<`_AQ9@&<`)
M_LY;@&<`_@1@-#`$4D!![(!N"#``!```9PAA5$I`9B)@'$)G(&R"NDZ0L$14*
M3V<./SP``2!L@KI.D%1/8`1@`/T02D5F)D)G(&R"NDZ0L'S__U1/9@IP_TS?;
M#/!.74YU/SP``2!L@KI.D%1/,`5@Z$Y5``!"9R!L@KI.D%)`0>R`;@@P``0`'
M`%1/9P)@YC\\``$@;(*Z3I"P?/__5$]F!G#_3EU.=7``8/A.5?_Z2.<,($IL_
M@KAN"G``3-\$,$Y=3G5";?_Z<``Z`$C`*T#__$)G(&R"NDZ0.`"P?``M5$]F8
M"CM\``'_^E)%8!:X?``K9@1216`,/SP``2!L@KI.D%1/8'!"9R!L@KI.D%1/;
M.``_`"\M``A.N@"$)$!*@%Q/9B@,;0`0`!!F$DJM__QF#+A\`'AG/+A\`%AG%
M-C\\``$@;(*Z3I!43V`P,BT`$$C!("W__$ZZ!"8K0/_\(`J0K0`((&T`#!(PM
M``!(@4C!TZW__%)%NFR"N&V*2FW_^F<.(&T`$B`M__Q$@""`8`@@;0`2(*W_^
M_#`%8`#_("!O``0P+P`($AAG"K(`9O@@"%.`3G5P`$YU87!#[(*R1>R"LK7)=
M9@XR/``6:PAT`"+"4<G__"E/@L(L>``$*4Z"QDCG@(`(+@`$`2EG$$OZ``A.@
MKO_B8`9"I_-?3G-#^@`@3J[^:"E`@LIF#"X\``.`!TZN_Y1@!$ZZ`!I03TYU"
M9&]S+FQI8G)A<GD`2?D``'_^3G5.50``+PI(>0`!```P+(*HP?P`!B\`3KH/8
M>BE`@LY03V840J=(>0`!``!.N@\^4$\N;(+"3G4@;(+.0F@`!"!L@LXQ?``!@
M`!`@;(+.,7P``0`*(&R"PB`L@L*0J``$4(`I0(+2(&R"TB"\34%.6$*G3KH/]
M+B1`2JH`K%A/9RXO+0`,+RT`""\*3KH`KCE\``&"UB!L@LX`:(````0@;(+.;
M`&B````*3^\`#&!"2&H`7$ZZ#TA(:@!<3KH/"BE`@M@@;(+82J@`)%!/9Q`@O
M;(+8(F@`)"\13KH.*EA/+RR"V"\*3KH"C"EL@MB"W%!/3KH.*B!L@LX@@$ZZ/
M#DH@;(+.(4``!F<62'@#[4AZ`"I.N@XF(&R"SB%```Q03R\L@MP_+(+@3KKS9
M$$)G3KH,1%!/)%].74YU*@!.50``2.<,,"1M`!`@;0`(2J@`K&<8(&T`""`H)
M`*SE@"@`($0@*``0Y8`F0&`$)FR"JA`32(!(P-"M``Q4@#E`@N)"IS`L@N)(`
MP"\`3KH.#"E`@N103V8(3-\,,$Y=3G40$TB`.@`_!2!+4H@O""\L@N1.N@%^O
M,`5(P"!`T>R"Y$/Z`400V6;\/RT`#B\*+RR"Y$ZZ`3H@;(+D0C!0`#E\``&"P
MX#`%2,#0K(+D)D!2BR1+3^\`%!`32(`Z`+!\`"!G&+I\``EG$KI\``QG#+I\6
M``UG!KI\``IF!%*+8-@,$P`@;7H,$P`B9BY2BR!+4HL0$$B`.@!G'B!*4HH06
MA;I\`")F$`P3`")F!%*+8`9"*O__8`)@UF`X($M2BQ`02(`Z`&<FNGP`(&<@O
MNGP`"6<:NGP`#&<4NGP`#6<.NGP`"F<(($I2BA"%8,X@2E**0A!*168"4XM2L
M;(+@8`#_6D(20J<P+(+@4D!(P.6`+P!.N@SJ*4""W%!/9@A";(+@8`#^V'H`"
M)FR"Y&`D,`5(P.6`(&R"W"&+"``@2R`(2AAF_)'`4X@P"%)`2,#7P%)%NFR"G
MX&W6,`5(P.6`(&R"W$*P"`!@`/Z4(``P/'__8`0P+P`,(&\`!$H89OQ32")OW
M``A30!#95\C__&<"0A`@+P`$3G5,[P,```0@"#(O``Q@`A#95\G__&<&4D%@,
M`D(84<G__$YU2.=P`#0!Q,`F`4A#QL!(0T)#U(-(0,#!2$!"0-""3-\`#DYU,
M3E4``$CG#C`D;0`(0J=(>@".3KH,3"E`@NA03V8(3-\,<$Y=3G4@;0`,(F@`:
M)"\I``1.N@Q\*`!83V=22'H`;2!$+R@`-DZZ#$XF0$J`4$]G-$AX`^TO"TZZV
M"VPL`%!/9R0@!N6`*@`@125H``@`I"5&`)Q(>`/M2'H`.$ZZ"T@E0`"@4$\O_
M!$ZZ#!I83R\L@NA.N@M^0JR"Z%A/8(!I8V]N+FQI8G)A<GD`5TE.1$]7`"H`<
M3E4``$AM``PO+0`(2'H$8$ZZ`)A/[P`,3EU.=4Y5``!(YP@@)&T`#@QM``0`<
M$F8((&T`""@08!Q*;0`,;PP@;0`(<``P$"@`8`H@;0`(,!!(P"@`0FT`$DIM;
M``QL$$1M``Q*A&P(1(0[?``!`!(R+0`,2,$@!$ZZ`Y!![(!<4XH4L```,BT`5
M#$C!(`1.N@.&*`!FVDIM`!)G!E.*%+P`+2`*3-\$$$Y=3G5.5?\B2.<(,"1M5
M``@F;0`,0FW_^BMM`!#__"!+4HL0$$B`.`!G``+NN'P`)68``LQ"+?\P.WP`3
M`?_X.WP`(/_V.WPG$/_T($M2BQ`02(`X`+!\`"UF#D)M__@@2U*+$!!(@#@`H
MN'P`,&80.WP`,/_V($M2BQ`02(`X`+A\`"IF&"!M__Q4K?_\.U#_\B!+4HL02
M$$B`.`!@,D)M__)@'#`M__+!_``*T$20?``P.T#_\B!+4HL0$$B`.``P!%)`]
M0>R`;@@P``(``&;4N'P`+F9:($M2BQ`02(`X`+!\`"IF&"!M__Q4K?_\.U#_[
M]"!+4HL0$$B`.`!@,D)M__1@'#`M__3!_``*T$20?``P.T#_]"!+4HL0$$B`1
M.``P!%)`0>R`;@@P``(``&;4.WP``O_PN'P`;&82($M2BQ`02(`X`#M\``3_O
M\&`0N'P`:&8*($M2BQ`02(`X`#`$2,!@>CM\``C_[F`6.WP`"O_N8`X[?``0O
M_^Y@!CM\__;_[C\M__!(;?\P/RW_[B\M__Q.NOWD*T#_ZC`M__!(P-&M__Q/T
M[P`,8%P@;?_\6*W__")0*TG_ZB`)2AEF_)/`4XD[2?_P8$H@;?_\5*W__#@04
M0>W_+RM(_^H0A&`HD+P```!C9^)3@&>2D+P````+9P#_<EF`9[)5@&<`_W!7[
M@&<`_W)@S$'M_S"1[?_J.TC_\#`M__"P;?_T;P8[;?_T__!*;?_X9V@@;?_J(
M#!``+6<*(&W_Z@P0`"MF+@QM`##_]F8F4VW_\B!M_^I2K?_J$!!(@#\`3I*P[
M?/__5$]F"G#_3-\,$$Y=3G5@%C\M__9.DK!\__]43V8$</]@Y%)M__HP+?_R8
M4VW_\K!M__!NW$)M_^Y@("!M_^I2K?_J$!!(@#\`3I*P?/__5$]F!'#_8+!20
M;?_N(&W_ZDH09PHP+?_NL&W_]&W.,"W_[M%M__I*;?_X9BA@&#\\`"!.DK!\,
M__]43V8&</]@`/]X4FW_^C`M__)3;?_RL&W_\&[:8!8_!$Z2L'S__U1/9@9P@
M_V``_U)2;?_Z8`#]"#`M__I@`/]"2.=(`$*$2H!J!$2`4D1*@6H&1($*1``!B
M83Y*1&<"1(!,WP`22H!.=4CG2`!"A$J`:@1$@%)$2H%J`D2!81H@`6#8+P%A4
M$B`!(A]*@$YU+P%A!B(?2H!.=4CG,`!(04I!9B!(038!-`!"0$A`@,,B`$A`*
M,@*"PS`!0D%(04S?``Q.=4A!)@$B`$)!2$%(0$)`=`_0@-.!MH%B!)*#4D!14
MRO_R3-\`#$YU3E4``$AL@08_+0`(3KH`"%Q/3EU.=4Y5```O!#@M``@O+0`*9
M/P1.N@`PN'P`"EQ/9B0@;0`*$"@`#$B`"```!V<4/SS__R\M``I.N@#T7$\H)
M'TY=3G5@^$Y5```O"B1M``H@4K'J``1E&#`M``C`?`#_/P`O"DZZ`,A<3R1?`
M3EU.=2!24I(0+0`)$(!(@,!\`/]@Z$Y5```O"D'L@/`D2"!*U?P````6+PAAS
M$%A/0>R"J+7(9>HD7TY=3G5.50``2.<(("1M``AX`"`*9@IP_TS?!!!.74YU,
M2BH`#&=0""H``@`,9PP_//__+PIA4C@`7$\0*@`-2(`_`$ZZ!1R(0`@J``$`D
M#%1/9PHO*@`(3KH"+EA/""H`!0`,9Q(O*@`23KH"P"\J`!).N@(44$]"DD*JY
M``1"J@`(0BH`##`$8)!.5?_^2.<(("1M``A!^O]&*4B"[`@J``0`#&<*</],Q
MWP003EU.=0@J``(`#&<P(%*1Z@`(.`@_!"\J``@0*@`-2(`_`$ZZ`H"P1%!/\
M9Q`(Z@`$``Q"DD*J``1P_V#`#&W__P`,9A`(J@`"``Q"DD*J``1P`&"H2JH`U
M"&8(+PI.N@":6$\,:@`!`!!F*AMM``W__S\\``%(;?__$"H`#4B`/P!.N@(B+
ML'P``5!/9J`P+0`,8`#_:B2J``@P*@`02,#0J@`()4``!`CJ``(`#"!24I(0=
M+0`-$(!(@,!\`/]@`/\^3E4``"\*0>R`\"1(2BH`#&<8U?P````60>R"J+7()
M90AP`"1?3EU.=6#B0I)"J@`$0JH`""`*8.I.5?_\+PHD;0`(/SP$`$ZZ`,`K>
M0/_\5$]F&#5\``$`$"!*T?P````.)4@`""1?3EU.=35\!```$`CJ``$`#"5M?
M__P`"!`J``U(@#\`3KH`XDI`5$]G!@`J`(``#&#.3E4``$CG`#`D;(*^8!0FE
M4B`J``10@"\`+PI.N@1.4$\D2R`*9NA"K(*^3-\,`$Y=3G5.50``+PI!^O_&G
M*4B"\$*G("T`"%"`+P!.N@/\)$!*@%!/9@AP`"1?3EU.=22L@KXE;0`(``0I:
M2H*^(`I0@&#F3E4``'``,"T`""\`8;)83TY=3G5.50``2.<`,)?+)&R"OF`.[
M(&T`"%&(L<IG$B9*)%(@"F;N</],WPP`3EU.=2`+9P0FDF`$*5*"OB`J``10E
M@"\`+PI.N@.@<`!03V#83E4``"\*,"T`",'\``8D0-7L@LY*;0`(;0XP+0`(R
ML&R"J&P$2I)F#CE\``*"]'#_)%].74YU,"T`",'\``8@;(+.+S`(`$ZZ`L9*8
M@%A/9P1P`6`"<`!@V$Y5```O+0`(3KH"D$J`6$]F#DZZ`IHY0(+T</].74YU#
M<`!@^$Y5``!(YPP@."T`"$ZZ`'`P!,'\``8D0-7L@LY*1&T*N&R"J&P$2I)F<
M$#E\``*"]'#_3-\$,$Y=3G4P*@`$P'P``V8*.7P`!8+T</]@Y'``,"T`#B\`S
M+RT`"B\23KH"9BH`L+S_____3^\`#&8,3KH"&CE`@O1P_V"X(`5@M$Y5__Q(>
M>!``0J=.N@+**T#__`@```Q03V<22FR"UF8(("W__$Y=3G5.N@`&<`!@]$Y5^
M``!(>``$2'H`'$ZZ`?`O`$ZZ`@(_/``!3KH`#D_O``Y.74YU7D,*`$Y5``!*Z
MK(+L9P8@;(+L3I`_+0`(3KH`"%1/3EU.=4Y5__PO!#`M``A(P"M`__Q*K(+.>
M9RAX`&`*/P1.N@#^5$]21+AL@JAM\#`L@JC!_``&+P`O+(+.3KH![%!/2JR"-
M\&<&(&R"\$Z02JR"KF<*+RR"KDZZ`6A83TJL@O9G""!L@O8@K(+Z2JR"_F<*#
M+RR"_DZZ`8183TJL@P)G"B\L@P).N@%T6$]*K(,&9PHO+(,&3KH!9%A/2JR#@
M"F<*+RR#"DZZ`5183RQX``0(+@`$`2EG%"\-2_H`"DZN_^(J7V`&0J?S7TYS!
M2JR"V&8P2JR"Y&<H,"R"XDC`+P`O+(+D3KH!1#`L@N!20$C`Y8`O`"\L@MQ.)
MN@$P3^\`$&`.3KH!'B\L@MA.N@%*6$\@+?_\+FR"PDYU*!].74YU3E4``$CGM
M#B`X+0`(,`3!_``&)$#5[(+.2D1M"KAL@JAL!$J29A`Y?``"@O1P_TS?!'!.E
M74YU""H`!P`$9@@O$DZZ``I83T*2<`!@XB(O``0L;(+*3N[_W"(O``0L;(+*4
M3N[_@B(O``0L;(+*3N[_N"QL@LI.[O_*+&R"RD[N_WPB+P`$+&R"RD[N_RA,5
M[P`&``0L;(+*3N[_XBQL@LI.[O_$3OH``B(O``0L;(+*3N[_IDSO``X`!"QLF
M@LI.[O_02.<!!$SO((``#"QL@L9.KO^43-\@@$YU3OH``B)O``0L;(+&3N[^H
M8DSO``,`!"QL@L9.[O\Z(F\`!"QL@L9.[O[:+&R"QD[N_WPB;P`$("\`""QL=
M@L9.[O\N(&\`!"QL@L9.[OZ,+&R"QB)O``0@+P`(3N[]V")O``0L;(+&3N[^V
MADSO``,`!"QL@L9.[O[.(&\`!"QL@L9.[OZ`3.\#```$+&R"Z$[N_Z`@;P`$/
M+&R"Z$[N_Z8@;P`$+&R"Z$[N_[(```/L`````0````````#P`````0````$`'
M``WV`````````_(```/J````K``!":`````!":H````!";0````!";X````!V
M#/,````!#1$````!#1(`````04)#1$5&86)C9&5F.3@W-C4T,S(Q,``*"PP-C
M#@\*"PP-#@\)"`<&!00#`@$``#`Q,C,T-38W.#EA8F-D968````@("`@("`@7
M("`P,#`P,"`@("`@("`@("`@("`@("`@()!`0$!`0$!`0$!`0$!`0$`,#`P,P
M#`P,#`P,0$!`0$!`0`D)"0D)"0$!`0$!`0$!`0$!`0$!`0$!`0$!0$!`0$!`2
M"@H*"@H*`@("`@("`@("`@("`@("`@("`@)`0$!`(``````````````````!%
M``````$``````````````````````0$````!``````````````````````$"'
M`````0``````````````````````````````````````````````````````!
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
M```````````````````````````````4``````````````/R```#ZP````$`X
#``/RU
``
end
size 8508
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.