/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION  1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:loutil.s 12.0$ */
/* $ACIS:loutil.s 12.0$ */
/* $Source: /ibm/acis/usr/sys/ca/RCS/loutil.s,v $ */

	.data
rcsidloutil:	.asciz	"$Header:loutil.s 12.0$"
	.text


 #  Note that these are NOT the 'spln' routines called by C, these
 #  are the routines that the 'spln' macros invoke (e.g. they have
 #  the UNIX spl numbers mapped into the ibm032 CPU numbers.
 #	  e.g. 'spl0()' --> _spl7()		(WEW)
 #
 #  set interrupt level 0 (highest priority) through level 7 (lowest)
 #    also set interrupt level according to argument
 #    always return previous level
 #
 # when the debugger is present INT_PRI0 is actually 1 (instead of 0)
 # so that the debugger can use level zero interrupt requests to
 # single step the kernel.
 #

 	 .globl __spl0
	 .globl __spl1
	 .globl __spl2
	 .globl __spl3
	 .globl __spl4
	 .globl __spl5
	 .globl __spl6
	 .globl __spl7
	 .globl _splx
         .globl _splimp
         .globl _splnet
 # the 'brx + mts' is quite useful when profiling as it causes a
 # held-off clock tick to be attributed to the caller of the spl
 # routine rather than the spl routine itself.
#define SPL_N(newprio)		\
          mfs   scr_ics,RETREG;       /* get the current status */ \
          ni    r3,RETREG,-8;         /* get all but priority in r3 */ \
          oi     r3,r3,newprio;      /* overlay priority bits */ \
          ni    RETREG,RETREG,7;     /* get only old priority bits */ \
          brx   r15;              /* return and... */ \
          mts   scr_ics,r3        /* set new status*/  
 # note that several of the following could be combined but it is 
 # useful for profiling to keep them separate
eye_profil(_spl0):    SPL_N(INT_PRI0)
eye_profil(_spl1):    SPL_N(1)
eye_profil(_spl2):    SPL_N(2)
eye_profil(splimp):  SPL_N(2)
eye_profil(_spl3):    SPL_N(3)
eye_profil(_spl4):    SPL_N(4)
eye_profil(_spl5):    SPL_N(5)
eye_profil(_spl6):    SPL_N(6)
eye_profil(splnet):  SPL_N(6)
eye_profil(_spl7):    SPL_N(7)
 #
eye_profil(splx):         nilz  r2,r2,7 # get only low 3 bits
          mfs   scr_ics,r3       # get the current status
          ni    r3,r3,-8         # get all but priority in r3
          o     r2,r3            # overlay priority bits 
          brx   r15              # return and... 
          mts   scr_ics,r2       # set new status 
 #
 #   Getspl: (dob) Returns the current ics priority bits
 #           without modifiction of current spl
	.globl _getspl
eye_profil(getspl):
	mfs   scr_ics,RETREG       # get the current status
	brx   r15
	ni    RETREG,RETREG,7             # Return only priority bits

 #
 #  I/O routines:  ior(port);  iow(port,value);
 #
         .globl _ior
	 .globl _iow
eye_profil(ior):
         brx   r15
         ior   RETREG,0(r2)          # read data from port

eye_profil(iow):
         brx   r15
         iow   r3,0(r2)          # write data to port
 #
 #  system reqister access routines
 #
         .globl _mtsr
eye_profil(mtsr):
         sli   r2,2              # r2 = parm 1 * 4
         mfs   scr_iar,r5        # set r5 to address of next inst
1:       ais   r5,mts_vector - 1b# set r5 to address of mts_vector
         a     r5,r2             # set r5 to address of mts_vector entry
         balr  RETREG,r5             # case statement (set RETREG for debug)
mts_vector:                      # each entry must be 4 bytes
         brx   r15;   mts r0,r3  # set scr 00 to 2nd parm |***
         brx   r15;   mts r1,r3  # set scr 01 to 2nd parm |***
         brx   r15;   mts r2,r3  # set scr 02 to 2nd parm |***
         brx   r15;   mts r3,r3  # set scr 03 to 2nd parm |***
         brx   r15;   mts r4,r3  # set scr 04 to 2nd parm |***
         brx   r15;   mts r5,r3  # set scr 05 to 2nd parm |***
         brx   r15;   mts r6,r3  # set scr 06 to 2nd parm |***
         brx   r15;   mts r7,r3  # set scr 07 to 2nd parm |***
         brx   r15;   mts r8,r3  # set scr 08 to 2nd parm |***
         brx   r15;   mts r9,r3  # set scr 09 to 2nd parm |***
         brx   r15;   mts r10,r3  # set scr 10 to 2nd parm |***
         brx   r15;   mts r11,r3  # set scr 11 to 2nd parm |***
         brx   r15;   mts r12,r3  # set scr 12 to 2nd parm |***
         brx   r15;   mts r13,r3  # set scr 13 to 2nd parm |***
         brx   r15;   mts r14,r3  # set scr 14 to 2nd parm |***
         brx   r15;   mts r15,r3  # set scr 15 to 2nd parm |***
         .globl _mfsr
eye_profil(mfsr):
         sli   r2,2              # r2 = parm 1 * 4
         mfs   scr_iar,r5        # set r5 to address of next inst
1:       ais   r5,mfs_vector - 1b# set r5 to address of mfs_vector
         a     r5,r2             # set r5 to address of mfs_vector entry
         balr  RETREG,r5             # case statement (set RETREG for debug)
mfs_vector:                      # each entry must be 4 bytes
         brx   r15;   mfs r0,RETREG  # return scr 00 |***
         brx   r15;   mfs r1,RETREG  # return scr 01 |***
         brx   r15;   mfs r2,RETREG  # return scr 02 |***
         brx   r15;   mfs r3,RETREG  # return scr 03 |***
         brx   r15;   mfs r4,RETREG  # return scr 04 |***
         brx   r15;   mfs r5,RETREG  # return scr 05 |***
         brx   r15;   mfs r6,RETREG  # return scr 06 |***
         brx   r15;   mfs r7,RETREG  # return scr 07 |***
         brx   r15;   mfs r8,RETREG  # return scr 08 |***
         brx   r15;   mfs r9,RETREG  # return scr 09 |***
         brx   r15;   mfs r10,RETREG  # return scr 10 |***
         brx   r15;   mfs r11,RETREG  # return scr 11 |***
         brx   r15;   mfs r12,RETREG  # return scr 12 |***
         brx   r15;   mfs r13,RETREG  # return scr 13 |***
         brx   r15;   mfs r14,RETREG  # return scr 14 |***
         brx   r15;   mfs r15,RETREG  # return scr 15 |***

 #  prepare for a core dump by saving the registers (including stack
 #  pointer) and also the important MM registers
 #  as a favour to the user we will cause the TRAR to point to the
 #  real address of the u area

.globl _dumpsave
eye_profil(dumpsave):
	 get	r5,$USTRUCT	# point to _u (and also pcb)
	 stm	r0,PCB_R0(r5)	# save registers
	 st	r15,PCB_IAR(r5)	# save return address as IAR
	 st	sp,PCB_USP(r5)	# save stack pointer
         mfs   scr_iar,r5       # use r5 as base register
1: 	 .using 1b,r5           # tell assembler
	stm	r0,_dumpregs	# save the registers
 #
 # save control registers
 #
	get	r4,$_dumpsysregs	# point to save location
#define DUMP_SYS(reg) mfs r/**/reg,r2; sts r2,reg<<2(r4)
	DUMP_SYS(0)
	DUMP_SYS(1)
	DUMP_SYS(2)
	DUMP_SYS(3)
	DUMP_SYS(4)
	DUMP_SYS(5)
	DUMP_SYS(6)
	DUMP_SYS(7)
	DUMP_SYS(8)
	DUMP_SYS(9)
	DUMP_SYS(10)
	DUMP_SYS(11)
	DUMP_SYS(12)
	DUMP_SYS(13)
	DUMP_SYS(14)
	DUMP_SYS(15)
 #
	cal	r2,0x19(r0)	# count of MM segment registers SEG0...RAS MODE
	get	r3,$MMU_SEGREG0	# point to seg reg 0
 #	cau	r3,(MMU_SEGREG0)>>16(r0) # point to seg reg 0
 #	oil	r3,r3,(MMU_SEGREG0)&0xffff
	get	r4,$USTRUCT	# get address of U area
	iow	r4,MMU_CRA(r3) # do the translate
	cal	r4,_dumpmmregs
 # loop thru storing the important MMU registers into lowcore
1:
	ior	r0,0(r3)	# get the registers
	put	r0,0(r4)	# store it
	ais	r4,4		# step pointer
	sis	r2,1
	ais	r3,1
	cis	r2,0
	jne	1b
	br	r15		# just return 
 #
 #  fill the specified real page with binary zeros.  Vax does this with 4 insts:
 #    create a pte, invalidate the tlb, block fill, return.
 #
         .globl _clearseg
eye_profil(clearseg):
         mfs   scr_ics,r5        # save caller's ics in r5
         ai    sp,sp,-44             # push stack
         stm   r5,0(sp)          # save caller's registers
         mfs   scr_iar,r15       # use r15 as base register
1: 	 .using 1b,r15           # tell assembler
         lps   0,csegreal_ps     # switch to untranslated mode at level 0

csegreal_ps:
         .long  csegreal-real0   # new iar
         .short NOTRANS_ICS      # new ics: xlate off
         .short 0                # new cs

csegreal:
         .using real0,r0         # tell assembler r0 is base reg
         mfs    scr_ics,r0       # get the current status
         ni     r0,r0,-8            # set processor level bits to zero
         ni     r5,r5,7             # isolate old processor level bits
         o      r0,r5            # set processor level bits to old level
         mts    scr_ics,r0       # set old processor level

	 cau    r0,(PAGESIZE-52)>>16(r0) # # bytes to clear less 52
	 oil    r0,r0,(PAGESIZE-52)&0xffff
         sli    r2,LOG2PAGESIZE  # real address of page to clear
         lis    r3,0             # fill constant
         lis    r4,0             # fill constant
         lis    r5,0             # fill constant
         lis    r6,0             # fill constant
         lis    r7,0             # fill constant
         lis    r8,0             # fill constant
         lis    r9,0             # fill constant
         lis    r10,0            # fill constant
         lis    r11,0            # fill constant
         lis    r12,0            # fill constant
         lis    r13,0            # fill constant
         lis    r14,0            # fill constant
         lis    r15,0            # fill constant
cseg10:
         stm    r3,0(r2)         # zero 52 bytes in page
         ai     r0,r0,-52            # decrement residual byte count
         bpx    cseg10           # loop if more to clear
         ai     r2,r2,52            # increment page address

         ai     r0,r0,52            # set residual byte count
         je     cseg30           # jump if all done
cseg20:
         sts    r3,0(r2)         # zero 4 bytes in page
         sis    r0,4             # decrement residual byte count
         bpx    cseg20           # loop if more to clear
         ais    r2,4             # increment page address
cseg30:
         lps    0,csegxlat_ps    # switch back to translated mode at level 0
csegxlat:
1:       .using 1b               # tell assembler no base register
         lm     r5,0(sp)         # restore caller's registers
         mts    scr_ics,r5       # restore caller's ics (processor level)
         brx    r15              # return to caller
         ai     sp,sp,44            # pop stack
1:       .using 1b
 #
 #  copypage(from,to) -- copy one real page to another real page.
 # "from" and "to" are the real addresses concerned (not page numbers)
 #
	.globl _copypage
eye_profil(copypage):
         mfs   scr_ics,r5        # save caller's ics in r5
         ai    sp,sp,-44             # push stack
         stm   r5,0(sp)          # save caller's registers
	mfs   scr_iar,r15       | use r15 as base register
1:	.using 1b,r15            | tell assembler
	lps   0,cpagreal_ps     | switch to untranslated mode
	
	.align 2
cpagreal_ps:
	.long  cpagreal-real0   | new iar
	.short NOTRANS_ICS,0    | new ics: xlate off

cpagxlat_ps:
	.long  cpagxlat		| new iar
	.short TRANS_ICS,0      | new ics: xlate off
	
	.using	real0,r0
cpagreal:
         mfs    scr_ics,r0       # get the current status
         ni     r0,r0,-8            # set processor level bits to zero
         ni     r5,r5,7             # isolate old processor level bits
         o      r0,r5            # set processor level bits to old level
         mts    scr_ics,r0       # set old processor level

	.using real0,r0         | tell assembler r0 is base reg
 #	sli    r2,MMU_LOG2PAGESIZE  | real address of page to copy from
 #	sli    r3,MMU_LOG2PAGESIZE  | real address of page to copy to
cpag10:
 # copy 48 bytes via a lm, stm combination block gives the offset (in
 # terms of 48-byte blocks)
#define LM_STM(r4,block)	lm     r4,block*48(r2); /* get next 48 bytes in "from" page */	\
	stm    r4,block*48(r3) /* set next 48 bytes in "to" page */

	LM_STM(r4,0)		/* copy 48 bytes */
	LM_STM(r4,1)		/* copy 48 bytes */
	LM_STM(r4,2)		/* copy 48 bytes */
	LM_STM(r4,3)		/* copy 48 bytes */
	LM_STM(r4,4)		/* copy 48 bytes */
	LM_STM(r4,5)		/* copy 48 bytes */
	LM_STM(r4,6)		/* copy 48 bytes */
	LM_STM(r4,7)		/* copy 48 bytes */
	LM_STM(r4,8)		/* copy 48 bytes */
	LM_STM(r4,9)		/* copy 48 bytes */
	LM_STM(r4,10)		/* copy 48 bytes */
	LM_STM(r4,11)		/* copy 48 bytes */
	LM_STM(r4,12)		/* copy 48 bytes */
	LM_STM(r4,13)		/* copy 48 bytes */
	LM_STM(r4,14)		/* copy 48 bytes */
	LM_STM(r4,15)		/* copy 48 bytes */
	LM_STM(r4,16)		/* copy 48 bytes */
	LM_STM(r4,17)		/* copy 48 bytes */
	LM_STM(r4,18)		/* copy 48 bytes */
	LM_STM(r4,19)		/* copy 48 bytes */
	LM_STM(r4,20)		/* copy 48 bytes */
	LM_STM(r4,21)		/* copy 48 bytes */
	LM_STM(r4,22)		/* copy 48 bytes */
	LM_STM(r4,23)		/* copy 48 bytes */
	LM_STM(r4,24)		/* copy 48 bytes */
	LM_STM(r4,25)		/* copy 48 bytes */
	LM_STM(r4,26)		/* copy 48 bytes */
	LM_STM(r4,27)		/* copy 48 bytes */
	LM_STM(r4,28)		/* copy 48 bytes */
	LM_STM(r4,29)		/* copy 48 bytes */
	LM_STM(r4,30)		/* copy 48 bytes */
	LM_STM(r4,31)		/* copy 48 bytes */
	LM_STM(r4,32)		/* copy 48 bytes */
	LM_STM(r4,33)		/* copy 48 bytes */
	LM_STM(r4,34)		/* copy 48 bytes */
	LM_STM(r4,35)		/* copy 48 bytes */
	LM_STM(r4,36)		/* copy 48 bytes */
	LM_STM(r4,37)		/* copy 48 bytes */
	LM_STM(r4,38)		/* copy 48 bytes */
	LM_STM(r4,39)		/* copy 48 bytes */
	LM_STM(r4,40)		/* copy 48 bytes */
	LM_STM(r4,41)		/* copy 48 bytes */
	LM_STM(r8,42)		/* copy last 32 bytes */
	.using	real0,r0
	lps    0,cpagxlat_ps    | switch back to translated mode
cpagxlat:
1:	.using 1b                | tell assembler no base register
	lm     r5,0(sp)         | restore caller's registers
	mts    scr_ics,r5       # restore caller's ics (processor level)
	brx    r15              | return to caller
	ai   sp,sp,44            | pop stack

 #  setrq - add to runable queue for this priority
 #
 #  setrq(p) struct proc *p;
 #
 #     _qs[pri]             Q                 R
 #      +---------------------------------------+
 #      |                   +-----------------+ |
 #      |                   V                 | V
 #    +-+-+---+           +---+---+         +-+-+---+
 # +->| | | --+---------->| | | --+-------->| | | | |       BEFORE
 # |  +---+---+           +-+-+---+         +---+-+-+
 # |    A                   |                     |
 # |    +-------------------+                     |
 # +----------------------------------------------+
 #
 #                    P
 #                  +---+---+
 #           RLINK  |   |   |  LINK
 #                  +---+---+
 #
 #
 #     _qs[pri]             Q                 R
 #                          +-----------------+
 #                          V                 |
 #    +---+---+           +---+---+         +-+-+---+
 # +->| | | --+---------->| | | --+-------->| | | | |       AFTER
 # |  +-+-+---+           +-+-+---+         +---+-+-+
 # |    |   A               |                 A   |
 # |    |   +---------------+                 |   |
 # |    |             +-----------------------+   |
 # |    |             |   +-----------------------+
 # |    |           P |   |
 # |    |             |   V
 # |    |           +-+-+---+
 # |    +---------->| | | | |
 # |                +---+-+-+
 # +----------------------+

         .globl _setrq
eye_profil(setrq):
         stm   r13,-3*4(r1)         # save registers we use
         sis   r1,3*4               # make room on stack
         mfs   scr_iar,r13          # get addressability
1:	 .using 1b,r13              # tell the assembler
         ls    r0,P_RLINK(r2)       # make sure not already on a queue
         cis   r0,0                 # ?.rlink zero (not on q)
         bz    set1                 # Y.ok, skip ahead
         cal   r2,set_panic         # N.panic
	CCALL(panic,1)		# call panic with 1 argument

set1:
         setsb scr_ics,INTMASK-16   # no interrupts, please
         lc    r15,P_PRI(r2)        # priority - 0..127
         sri   r15,3                # now 0..15
         nilz  r15, r15,0xf              # make sure
         slpi  r15,3                # times 8 bytes per q hdr (in r14)
         cal   r4,_qs               # queue headers
         a     r4,r14               # add offset for this priority
         ls    r3,P_RLINK(r4)       # r4 -> r (tail of queue)
         sts   r3,P_RLINK(r2)       # set back ptr of p -> r
         sts   r4,P_LINK(r2)        # set forw. ptr of p -> que hdr
         sts   r2,P_LINK(r3)        # set forw ptr of r -> p
         sts   r2,P_RLINK(r4)       # set back ptr of que hdr -> p
 #  mark queue as non-empty
         l     r4,_whichqs          # word with one bit per queue
	 cal16 r14,(0x8000^0x8000-0x8000)(r0) # get a one
         sr    r14,r15              # move the 1 to the bit for this prio
         o     r4,r14               # set the bit
         st    r4,_whichqs          # back in _whichqs
 #  restore regs & return
         clrsb scr_ics,INTMASK-16   # interrupts safe now
         lm    r13,0(r1)            # restore registers
         brx   r15                  # return after
         ais   r1,3*4               # restore stack pointer

set_panic: .asciz "setrq"

 #  remrq - delete from runable queue for this priority
 #
 #  remrq(p) struct proc *p;
 #
 #      Q                   P                 R
 #                          +-----------------+
 #                          V                 |
 #    +---+---+           +---+---+         +-+-+---+
 #    |   | --+---------->| | | --+-------->| | |   |       BEFORE
 #    +---+---+           +-+-+---+         +---+---+
 #      A                   |
 #      +-------------------+
 #
 #
 #      Q                   P                 R
 #          +---------------------------------+
 #          |                                 V
 #    +---+-+-+           +---+---+         +---+---+
 #    |   | | |           |   |   |         | | |   |       AFTER
 #    +---+---+           +---+---+         +-+-+---+
 #      A                                     |
 #      +-------------------------------------+
 #
         .globl _remrq
eye_profil(remrq):
         stm   r13,-3*4(r1)         # save registers we use
         sis   r1,3*4               # make room on stack
         mfs   scr_iar,r13          # get addressability
1:	 .using 1b,r13              # tell the assembler
 #  make sure that there is really someone on that queue
         lc    r15,P_PRI(r2)        # get the priority
         sri   r15,3                # now 0..15
         nilz  r15,r15,0xf              # make sure
	 cal16 r14,(0x8000^0x8000-0x8000)(r0) # priority 0 mask
         sr    r14,r15              # shift to position for this priority
         l     r4,_whichqs          # which queues have waiting procs
         n     r14,r4               #?.anything there?
         bnz   rem1                 # Y.ok, skip ahead
         cal   r2,rem_panic         # N.panic
	CCALL(panic,1)		# call panic with 1 arg

rem1:
         setsb scr_ics,INTMASK-16   # no interrupts, please
         x     r14,r4               # turn off bit for that priority
         ls    r15,P_RLINK(r2)      # r15 -> Q
         ls    r4,P_LINK(r2)        # r4 -> R
         sts   r4,P_LINK(r15)       # link(q) := r
         sts   r15,P_RLINK(r4)      # rlink(r) := q
         c     r4,r15               # equal?  (queue empty?)
         bne   rem2                 # n.skip
         st    r14,_whichqs         # y.update which queues waiting

rem2:
         lis   r15,0                # zero for firewall
         sts   r15,P_RLINK(r2)      # see check in setrq
 #  restore regs & return
         clrsb scr_ics,INTMASK-16   # interrupts safe now
         lm    r13,0(r1)            # restore registers
         brx   r15                  # return after
         ais   r1,3*4               # restore stack pointer

rem_panic: .asciz "remrq"

 #  swtch - resume hightest priority task in the queue
 #
 #     _qs[pri]             P                 Q
 #                          +-----------------+
 #                          V                 |
 #    +---+---+           +---+---+         +-+-+---+
 # +->| | | --+---------->| | | --+-------->| | | | |       BEFORE
 # |  +-+-+---+           +-+-+---+         +---+-+-+
 # |    |   A               |                 A   |
 # |    |   +---------------+                 |   |
 # |    |             +-----------------------+   |
 # |    |             |   +-----------------------+
 # |    |           R |   |
 # |    |             |   V
 # |    |           +-+-+---+
 # |    +---------->| | | | |
 # |                +---+-+-+
 # +----------------------+
 #
 #  note:  MUST NOT modify the return address in r15, which is passed to
 #         _resume below
 #
swtch_panic: .asciz "swtch"
         .globl _swtch
eye_profil(swtch):
         stm   r13,-3*4(sp)
         sis   sp,3*4
         mfs   scr_iar,r13
1:	.using 1b,r13
         lis   r0,1
         st    r0,_noproc
         lis   r0,0
         st    r0,_runrun
sw1:
         mfs   scr_ics,r0            # get current ics
         oil   r0,r0,7                  # set level 7
         j     sw1b                  # stay at current level 1st pass
 #  loop looking for process to run
sw1a:
         mts   scr_ics,r0            # get down to level 7
sw1b:
         l     r2,_whichqs           # get list of non-empty queues
         clz   r3,r2                 # how many
         cis   r3,15                 # all 0's
         jh    sw1a                  # y.loop

 #  _whichqs not zero

         nilo  r0,r0,0xFFF8             # back to level zero
         mts   scr_ics,r0            # into ics
	 cal16 r4,(0x8000^0x8000-0x8000)(r0) # get a 1 bit
         sr    r4,r3                 # move the bit into pos'n for pri
         l     r0,_whichqs           # get bits again
         n     r4,r0                 # make sure bit still on
         bz    sw1                   # not still on...loop back
 #
         x     r0,r4                 # was on, turn just that one off
         sli   r3,3                  # 8 bytes per _qs element
         cal   r4,_qs                # point to que headers
         a     r4,r3                # offset into this queue header
 #  remove the head process
         ls    r2,P_LINK(r4)        # r2 -> P
         ls    r3,P_RLINK(r4)       # r3 -> R
         c     r2,r4                # ?==?  (ie. queue empty)
         bne   sw2                  # n.skip ahead (ok)
 #  come here to panic
sw1c:
         cal   r2,swtch_panic       # "swtch"
	CCALL(panic,1)		# call panic with 1 arg
 #
 #  come here to dequeue first element
sw2:
         ls    r3,P_LINK(r2)        # r3 -> Q
         sts   r3,P_LINK(r4)        # link(_qs[pri]) := Q
         sts   r4,P_RLINK(r3)       # rlink(Q) := _qs[pri]
         c     r3,r4                # ?.== now?
         bne   sw3                  # n.not empty, skip ahead
 #  queue is now empty, record new _whichqs
         st    r0,_whichqs          # record new queue status
 #
 #
sw3:
         lis   r0,0                 # zero
         st    r0,_noproc           # ???
         lc    r3,P_STAT(r2)        # check P_STAT
         cis   r3,SRUN              # ?. running?
         bne   sw1c                 # n.panic!
         sts   r0,P_RLINK(r2)       # y.zero rlink for sanity check later
	st	r2,_masterpaddr		# point to current proc running
 #  resume the new process (addr in r2), return addr in r15
 # increment cnt.v_swtch
	l	r0,V_SWTCH+_cnt		# get value of cnt
	ais	r0,1			# bump 
	st	r0,V_SWTCH+_cnt		# store it
#
         lm    r13,0(sp)            # restore regs
	   ais	  sp,3*4		  # give back stack space
	   bx	  _.resume		  # resume new process
	    get	  r0,$_resume

1:	.using 1b                # tell assembler no base register

 #  resume - save current state and switch to new process
 #
 #  resume(p) - saves current state and switched to process p
 #    struct proc *p;     points to the process to be resumed
 #
 #    operation:
 #      r2 -> proc struct of the new proc to run
 #      remember the address of the current (soon to be previous) proc
 #      save the registers (r1,r6-r15) of the current proc in the u struct
 #      load seg regs 0 and 1 from the new proc struct (changes to new
 #         process
 #      reload the sp from the (new) u struct
 #      restore the other registers from the (new) u struct
 #      if PCB_SSWAP is zero then
 #         return
 #      else
 #         PCB_SSWAP points to a SETJMP saved context - go to LONGJMP
 #
         .globl _resume
eye_profil(resume):
#if defined(FPA) || defined(MC881)
         mfs   scr_iar,r4		# set up addressability
1:	.using 1b,r4
#endif
#ifdef FPA
/*
 * Note: FPA processing is done before any important status is saved
 * in PCB in case we cause an FPA interrupt here.
 */
         setsb scr_ics,INTMASK-16	# no interrupts, please
	l	r3,_fpa_curreg		# get current register set
	ni	r0,r3,FPA_LOCK		# was locked?
	jne	2f			# yes, don't store status to RAM
#ifdef ROMPC
 # save the IOIM length register if using AFPA with DMA
	load	r5,_float_hardware	# get float_hardware
	ni	r0,r5,FLOAT_AFPA_DMA	# is it an AFPA with DMA? 
	jeq	3f			# 	nope
	cau	r5,0xfe1e7c03/UPPER(r0)	# get top 16 bits of address
	l	r0,0x7c03(r5)		# read the length register
	store	r0,_u+PCB_AFPALEN,r5	# and save it
	j	2f			# skip over read status for AFPA
3:
	ni	r0,r5,FLOAT_FPA		# is it an FPA? 
	jeq	2f			# not an FPA either
#endif ROMPC
	get	r5,$FPA_RDSTR		# otherwise read status 
	.globl	_resume_rdstr
 #	mfs	scr_ics,r0		# get old ics
 #	clrsb	scr_ics,29-16		# get high priority bit
_resume_rdstr:				# location of read status command */
	ls	r5,0(r5)		# into r5
#ifdef ROMPC
	c	r5,r5			# force sync here
#endif ROMPC
 #	mts	scr_ics,r0		# restore priority
2:
#endif FPA
 #  save current state in the current pcb
	 get	r5,$USTRUCT		# point to the user structure
         sts   sp,PCB_USP(r5)          # save sp
         stm   r6,PCB_R6(r5)           # save registers
 #  save the old segment register 8
 	get	r13,$MMU_SEGREG0 # point to seg reg 0
	 ior   r14,(MMU_SEGREGSTEP)<<3(r13) # get sr08 from MMU
	 sts   r14,PCB_SR08(r5)	       # save old sr08
 #  remember where the (soon to be) old proc struct is
         l     r6,U_PROCP(r5)          # r6 -> proc struct
 #  load seg reg 0 value from new proc struct
         lh    r14,P_SID0(r2)          # load seg reg 0 value
         sli   r14,2                   # (Special,Key) = (0,0)
         oiu   r14,r14,1                   # (Present) = (1)
 #  send new value to the seg reg 0
         iow   r14,0(r13)              # set new value for seg reg 0
 #  load seg reg 1 value from new proc struct
         lh    r14,P_SID1(r2)          # load seg reg 1 value
         sli   r14,2                   # (Special,Key) = (0,0)
         oiu   r14,r14,1                   # (Present) = (1)
 #  send new value to the seg reg 1
         iow   r14,MMU_SEGREGSTEP(r13) # set new value for seg reg 1
 #  restore segment 8
	 ls    r14,PCB_SR08(r5)        # get new sr08
	 iow   r14,MMU_SEGREGSTEP<<3(r13) # store in sr08
#ifdef ATR
 #  restore the TID (which controls access to the I/O segment 
	 ls    r14,PCB_IO(r5)        # get new sr08
	 iow   r14,MMU_TIDR-MMU_SEGR(r13) # store in sr08
#endif ATR
 #  now running as new process - restore registers
         ls    sp,PCB_USP(r5)          # restore sp

#if	defined(MC881)
 #
 #   If the current PID is the PID of the 68881 owner, then
 #   allow accesses to the hardware; otherwise, disable
 #   accesses to the hardware.
 #
 #   We use
 #	r0, r13, r14
 #
 #   We assume
 #	r2 - points at the current proc structure
 #
 #   We preserve the value of
 #	r2, r3
 #
	l	r0,_mc881_proc		# get proc address of 68881 owner
#if	defined(SGP)
	/* On an SGP board, 68881 doesn't exist */
	ci	r0,-1			# does it exist?
	be	1f			# no, skip code
#endif	/* defined(SGP) */
#ifndef ATR
	get	r14,$(IOIM2)	# get IOIM2 base address
#else
	l	r14,_ioim2		# test if IOIM 2 present 	XXX
	cis	r14,0			# zero if not			XXX
	jeq	1f			#				XXX
#endif ATR
	get	r13,$(IOIM2_PROB_DISABLE)	# assume "lock"
	c	r0,r2			# is this the owner?
	jne	0f			# yes, go open it up
	get	r13,$(IOIM2_PROB_ENABLE)	# enable problem state access
0:
	iow	r13,IOIM_SUB_PROB(r14)	# do the lock or unlock
	# done with 68881 processing
1:
#endif	/* defined(MC881) */

#ifdef FPA
 # either switch to fpa register set or lock the fpa
 # r2 points to our proc structure on entry
 # r3 contains the value of fpa_curreg on entry
 # r4 is a base register 
	load	r5,_float_hardware	# get float_hardware
	nilz	r0,r5,FLOAT_AFPA+FLOAT_FPA # test if any FPA present
	jeq	0f			# no float hardware
	getc	r14,P_FPAREG(r2)	# get register set
	c	r14,r3			# same ? (also no fpa present)
	jeq	0f			# yes
	st	r14,_fpa_curreg		# remember new current register set
	ni	r0,r14,FPA_LOCK		# should lock it?
	jne	1f			# yes, lock fpa
	get	r2,$FPA_TSKSWU		# otherwise get task switch command
	sts	r14,0(r2)		# do fpa task switch
#ifdef ROMPC
 # restore the IOIM length register if using AFPA with DMA
	ni	r0,r5,FLOAT_AFPA_DMA	# is it an AFPA with DMA? 
	jeq	0f			# 	nope
	load	r2,_u+PCB_AFPALEN	# get saved length register
	store	r2,0xfe1e7c03,r14	# and set it
3:
#endif ROMPC
	j	0f
 # issue fpa lock command
1:
	get	r2,$FPA_LOCKFP
	sts	r2,0(r2)		# and lock it
0:
#endif FPA

#ifdef DEBUG
 #  BEGIN DEBUGGING CODE
         mfs   scr_iar,r11
1:	.using 1b,r11
         load     r2,_sydebug
	 nilz	r2,r2,SHOW_SWTCH
         jeq    normsg

         cal   r2,$.ascii ":%d:\0"
	 load	r3,USTRUCT+U_PROCP
         lh    r3,P_PID(r3)
	CCALL(printf,2)
1:      .using 1b
normsg:
#endif
 #  END DEBUGGING CODE

 #  restore other registers
	 get	r5,$USTRUCT		# point to the user structure
#ifdef IBMRTPC
 # set CCR from pcb
	 getc	r7,PCB_CCR(r5)		# pick up ccr value
	 get	r6,$CCR			# point to CCR
	 stcs	r7,0(r6)		# put into CCR
 # set CCR end
#endif IBMRTPC
#ifdef ATR
 # set the 128 K window for the user
	getc	r7,PCB_WIN(r5)		# pick up current window value
	get	r6,$_pcif_reg		# get the offset to pcif ctrl regs
	ls	r6,0(r6)
	sts	r7,PC_WIND128(r6)	# change the window
	get	r6,$_current_128_w	# set current_128_w to the cur window
	sts	r7,0(r6)		# value
#endif ATR
         lm    r6,PCB_R6(r5)           # restore registers
 #  check for PCB_SSWAP - if nonzero points to longjmp vector
         l     r2,PCB_SSWAP(r5)        # get SSWAP field of pcb
         lis   r0,0                    # new value for SSWAP field
         st    r0,PCB_SSWAP(r5)        # use SSWAP only once
         clrsb scr_ics,INTMASK-16      # now interrupts are safe ???
         cis   r2,0                    # check for zero
         bzr   r15                     # return if zero
#ifdef GPROF
	   get	  r0,$_longjmp
#endif
         j     _.longjmp			# non-zero - pass r2 to longjmp
 #
 #  longjmp(buf) - restore saved context and return (to caller of setjmp)
 #      label_t buf;
 #
         .globl _longjmp
eye_profil(longjmp):
         lm    r5,0(r2)                # restore registers
	 cas	r1,r5,r0		# restore stack pointer (from r5)
         brx   r15                     # return, after...
         lis   RETREG,1                    # return value 1
 #
 #  setjmp(buf) - save context for later
 #
         .globl _setjmp
eye_profil(setjmp):
	 cas	r5,r1,r0		# save stack pointer in r5
         stm   r5,0(r2)			# save registers r5 (sp) ... r15
         brx   r15			# return, after...
         lis   RETREG,0			# return value == 0

 #
 #  savectx(buf) - save context for later
 #
         .globl _savectx
eye_profil(savectx):
	 cas	r5,r1,r0		# save stack pointer in r5
         stm   r5,0(r2)			# save registers r5 (sp) ... r15
         brx   r15			# return, after...
         lis   RETREG,0			# return value == 0

 #
 # bcmp coded in assembler for efficiency
 # the original C was:
 #
 # bcmp(s1, s2, len)
 # 	register char *s1, *s2;
 # 	register int len;
 # {
 # 
 # 	while (len--)
 # 		if (*s1++ != *s2++)
 # 			return (1);
 # 	return (0);
 # }
 # r2=s1, r3=s2, r4=len
 #

	.globl _bcmp
eye_profil(bcmp):
	cis	r4,0
	ble	0f		# return 0 if length is 0
 #
	cas	r4,r2,r4	# calculate end = s1 + len
 # change with care, 2: should be aligned on a 4-byte boundary 
2:
	getc	r0,0(r2)	# first character (*s1)
	getc	r5,0(r3)	# second character (*s2)
	inc	r2,1		# s1++
	inc	r3,1
	c	r0,r5		# compare (*s1) == (*s2)
	jne	1f		# not the same
	c	r2,r4		# if (s1 < end)
	jl	2b		# 	{ goto 2b; ++s2 }
0:
	brx	r15
	 lis	RETREG,0		# return 0 (same)
1:
	brx	r15
	 lis	RETREG,1		# return 1 (different)

#ifdef ATR
 #
 # Initialize the 8514 so we don't have to allow write access
 # to some critical areas of memory.
 #
eye_profil(lo_init_8514):
	cal	r3,0x02e8(r0)
	oiu	r3,r3,(0x000e+(MMU_IO_SEG << 12))
	mfs	scr_iar,r4
0:	.using	0b,r4
	cal	r2,2f-0b(r4)
	lis	r4,8
1:
	lhs	r5,0(r2)
	st	r5,0(r3)
	ai	r3,r3,0x400
	ais	r2,2
	sis	r4,1
	jnz	1b
	br	r15
2:
	.short	0x9d00,0x7f00,0x8100,0x1600
	.short  0x6006,0xfa05,0x0006,0x0800
#endif ATR

 #
 #	display(nn) displays two hex digits in the front panel display
 #

#ifdef IBMRTPC
display_ps:
	.int 	display_go-real0
	.short	NOTRANS_ICS+INT_PRI0
	.short	0
display_ps2:
	.int 	display_go2
	.short	TRANS_ICS		# previous ics stored here
	.short	0
#endif IBMRTPC

	.globl	_display
eye_profil(display):
#ifdef IBMRTPC
	mfs	scr_ics,r0
	mfs	scr_iar,r3
1: 	.using	1b,r3
	lps	0,display_ps
 # now running non-translated
	.using	real0,r0		# locore addressing
display_go:
	sth	r0,display_ps2+old_ics_cs
	bali	r5,display		# call routine
	lps	0,display_ps2
display_go2:
#endif IBMRTPC
	br	r15			# and return to caller
 # display routine available to kernel in non-translate mode
 # r2 contains the value to display
 # clobbers r0 and r3
 # return is via r5.
display:
#ifdef IBMRTPC
	get	r3,$(MMUBASE)		# get base address of MMU
	ior	r0,MMU_ROS(r3)		# get the value of ROS register
	cis	r0,0			# is it specified? 
	jeq	0f			# no, go map in ROS
	cau	r3,ROS_ADDR/UPPER(r0)
	ls	r3,4(r3)		# get the ROS EP table
 # we could call ROS but since we've referenced it that is enough
1:	get     r3,$(LED_ADDR)		# get the address base for LED's
	mc33	r3,r2			# get the complete address
	ior	r0,0(r3)		# read from it
	iow	r0,0(r3)		# write it (lock it)
#endif IBMRTPC
	br	r5			# and return to caller
 # ROS is not in address space:
 # Since we must map ROS out again anyway, we map ROS not at
 # 8 Meg, but just below us were we're safe from dma (We're in
 # big trouble if someone is trying to dma to kernel text!!).
 # NOTE: This method is making some very sweepping assumptions
 # about the nature of the kernel:
 #	1) we're in locore, so at least 128K of kernel text
 # follow us (we are almost certainly in the first 64K of memory,
 # but it's easy to find the first 64K chunk after us, so we do).
 #	2) we cannot be interrupted! (we don't want to find
 # ourselves in random ROS as oppose to trap or loslih, especially
 # since half the ROS is 286 code!).
 #	3) we will not program check/machine check here!! (see above).
 #
0:
#define ROS_PAGE	(((1f-real0)/UPPER)+1)
#define ROS_SPEC_2	(((ROS_PAGE) << 4) + 0x0001)
#define ROS_ADDR_2	(ROS_PAGE)
	get	r0,$(ROS_SPEC_2) # get first 64K junk after us an validate it.
	iow	r0,MMU_ROS(r3)		# and store it
	cau	r3,ROS_ADDR_2(r0)
	ls	r3,4(r3)		# get the ROS EP table
	get	r3,$(MMUBASE)		# get base address of MMU
	lis	r0,0
	iow	r0,MMU_ROS(r3)		# Map out ros so we can use kernel text again
	j	1b
      TTNOFRM
1:


	.align	2
	.globl _xadunload
 xadunload_ps:
	.long	xadunload-real0
         .short NOTRANS_ICS+INT_PRI1,0	# new ics: xlate off, PRIO 1

 xadunload_ps2:
	.long	xadunload2
	.short	0-0,0		# will be replaced by actual ics upon call

eye_profil(xadunload):
|-----------------| xadunload |-------------------|
	stm	%.LOWREG103,(.LOWREGVAR103-16)*4(sp)	# save registers 
	ai	sp,sp,(.LOWREGVAR103-16)*4		# room for r14...r15
 cas r0,r4,r0 | bfcode
 # go to non-translated mode
	mfs scr_iar,r15
1:	.using	1b,r15
	mfs	scr_ics,r14		# get current ics_cs
	lps	0,xadunload_ps		# turn off translate

	.using	real0,r0
xadunload:
 # following only works because translate & storage protect is off
	sth	r14,xadunload_ps2+old_ics_cs	# for later

	cis r5,0 | 85
	be L105 | EQ	(write)

	cis r2,0 | 85
	be L107 | NE	(no buffer)

 # read: transfer adapter to buffer
 # this code was written by Frank Bartucca, IBM Milford
	cis	r0,0		# compare hdcnt to 0
	ble	L118		# already done
	sis	r0,4
	bx	1f		# branch to read routine
2:	ls	r4,0(r3)	# pick up value 
	sis	r0,4		# decrement hdcnt by 4
	inc	r2,8		# increment buffaddr by 8
	st	r5,-4(r2)	# store r5 at buffaddr-4
1:	ble	3f		# if hdnct < 0 clean up 
	ls	r5,0(r3) 	# start next adapter read
	sis	r0,4		# decrement hdcnt by 4
	ble	0f		# if hdcnt <= 0 clean up 
	bx	2b		# else keep going
0:	sts	r4,0(r2)	# store r4 at buffaddr
	bx	L118		#branch to return code
	sts	r5,4(r2)	# store r5 at buffaddr
3:	bx	L118		# else keep going
	sts	r4,0(r2)	# store r4 at buffaddr

 # read: just reference the buffer to unload it and throw away the results
L107:
0:	si r0,r0,4 | 190
	bl L118 | LT
	bx 0b | branch
	ls r2,0(r3) | 94

 # come here to fill out a record with zero's
L117:
	 get r15,$0 | 92
0:
	si r0,r0,4 | 190
	bl L118 | LT
	bx 0b | branch
	sts r15,0(r3) | 80

 # come here to fill adapter buffer for write
L105:
	cis r2,0 | 85
	be L117 | NE
#ifndef notdef
	cis	r0,0		# compare hdcnt to 0 
	jle	L118		# jump to return code if hdcnt <= 0 
	sis	r0,4		# decrement hdcnt by 4 
	blex	0f		# clean up if hdcnt <= 0 
	ls	r4,0(r2)	# load r4 from buffaddr 
2:	ls	r5,4(r2)	# load r5 from buffaddr 
	sts	r4,0(r3)	# write r4 to adapter 
	sis	r0,4		# decrement hdcnt by 4 
	jle	1f		# clean up if hdcnt <= 0 
	inc	r2,8		# increment buffaddr by 8 
	ls	r4,0(r2)	# load r4 from buffaddr 
	sts	r5,0(r3)	# write r5 to adapter 
	sis	r0,4		# decrement hdcnt by 4 
	jh	2b		# if hdcnt > 0 keep going 
0:	bx	L118		# jump to return code 
	sts	r4,0(r3)	# write r4 to adapter 
1:	bx	L118		# branch to return code 
	sts	r5,0(r3)	# write r5 to adapter 
#else	/* old write code */
 # write case
	sis	r0,4	# compare hdcnt to 4
	ble	1f	# either 0 or 4 to do
0:	ls	r4,0(r2)	# get from buffer
	ls	r5,4(r2)	# start another read
	inc	r2,8		# increment pointer
	sis	r0,8		# decrement count
	sts	r4,0(r3)	# store into adapter
	bhx	0b		# branch and complete 
	sts	r5,0(r3)	# storing of second word
 # we have less than 8 to go
1:	bl	L118	# all done
	ls	r4,0(r2)	# can only be 1 word left to do
	bx	L118
	sts	r4,0(r3)	# complete last store
#endif

L118:
 lps	0,xadunload_ps2
xadunload2:
	lm	%.LOWREG103,0(sp)
	brx	r15
	ai	sp,sp,(16-.LOWREGVAR103)*4
.set .LOWREGVAR103, 14 | not optimized
.set .LOWREG103, r14
.set L103, (12 - .LOWREGVAR103) * 4
.set .R103, .LOWREG103
.set .V103, 0 | eobl2

 #
 # vtop done in assembler for efficiency
 # 1. inhibit interrupts 
 # 2. translate virtual to real
 # 3. enable interrupts again 
 # 
eye_profil(vtop):
         setsb scr_ics,INTMASK-16# disable interrupts
	 cau	r3,MMUBASE/UPPER(r0)	# get base address
	 iow	r2,MMU_CRA(r3)		# start CRA function
	 ior	RETREG,MMU_TRAR(r3)	# finish it
	 cis	RETREG,0		# test if < 0
	 bnlrx	r15			# no, return
	 clrsb scr_ics,INTMASK-16# enable interrupts now
	 brx	r15
	 cal	RETREG,-1(r0)		# return -1 

 #
 # upcmul(n,scale)
 # multiply n * scale and drop bottom 16 bits
 #
 # on entry r2 = n, r3 = scale
 #
 # normally 0x8000 <= r3 <= 0
 # and  MAXTEXT <= r2 < 0.
 # where MAXTEXT is <= 24,000,000 on most systems
 #
eye_profil(upcmul):

 
        mts     scr_mq,r3                  #copy x into multiplier quotient
 
        #multiply the mq by r2 and put the answer in r0
 
        s       r0,r0                   #zero answer and set carry on
 
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply
        m       r0,r2                   #incremental multiply

	jc0	0f		
	a	r0,r2			#add r2 in again if r3 >= 2^31	
0:
 
	mfs	scr_mq,r3		# low order result
	sri16	r3,16-16		# get top 16 bits of low order
	sli16	r0,16-16		# get bottom 16 bits of high order

	brx	r15			# return
	  cas	RETREG,r0,r3		# get result


 #
 # 	bali	r15,flipxlate
 #
 #	returns with the translate state flipped from it's current
 #	status.
 #
 #	clobbers r0, and r14
 #	r15 has return address modified to reflect translate on/off
 #
	.globl	flipxlate
flipxlate:
	mfs	scr_iar,r14
	.using	0f,r14
0:
	mfs	scr_ics,r0		# get ics
	xi	r0,r0,TRANS_ICS-NOTRANS_ICS	# flip translate bit
	xi	r15,r15,SYS_ORG		# flip segment number
	setsb scr_ics,INTMASK-16   	# no interrupts, please
	sth	r0,flipxps+old_ics_cs
	st	r15,flipxps+old_iar
	lps	0,flipxps		# and do it!

 #
 # copy from ROS into buffer 
 #
 #	r2	from address (in ROS)
 #	r3	to address (in real memory)
 #	r4	count	 (> 0)
 #
 # this version is very simple-minded and does byte copies
 # (but it doesn't get used very much)
 #
 # one complication is that ROS may not be mapped into our 
 # address space. If not we map it in for the duration of
 # this routine (turning off interrupts because an interrupt
 # routine might have its stack past 8meg).
 #

#ifdef IBMRTPC
eye_profil(roscopy):
	stm	r13,-12(sp)	# save registers
	ai	sp,sp,-12
	bali	r15,flipxlate	# turn off xlate
	get	r5,$(MMUBASE)	# get mmu base address
	ior	r13,MMU_ROS(r5)	# get ROS specification register
	cis	r13,0		# test if present
	jne	0f		# yes, all is ok

	setsb scr_ics,INTMASK-16   	# no interrupts, please
	get	r0,$MMU_ROS_SPEC# get new value
	iow	r0,MMU_ROS(r5)	# write it
 # loop copying r4 bytes from (r2) to (r3) 
0:
	getc	r0,0(r2)
	inc	r2,1
	putc	r0,0(r3)
	inc	r3,1
	si	r4,r4,1
	jne	0b

	cis	r13,0
	jne	0f		# normal case
	iow	r13,MMU_ROS(r5)	# restore original ROS value
	clrsb scr_ics,INTMASK-16   	# allow interrupts now
0:

	bali	r15,flipxlate
	lm	r13,0(sp)
	brx	r15
	ai	sp,sp,12
#endif IBMRTPC
 #
 # swapw - do a VAX* byte-order to IBM RT PC order 32-bit byte swap
 # (* VAX is a trade mark of Digital Equipment Corporation)
 # given  r2 = A B C D 
 # return r2 = D C B A
 #
 # input:
 #	r2	word (in vax byte order)
 # output:
 #	r2	word (in RT byte order) 
 #
 # this is used in the RVD checksum routine
 #
eye_profil(swapw):
	cas	r3,r2,r0	# r3 = r2 		( A B C D )
	sri	r2,8		# r2 = r2 >> 8		( 0 A B C )
	mc03	r2,r3		# r2  			( D A B C )
	mc13	r2,r2		# r2			( D C B C )
	brx	r15		# return ...  with result in r2
	 mc30	r2,r3		# r2			( D C B A )

 #
 # swapsum(ptr,length)
 # sum up the bytes in the region pointed to by "ptr" of "length"
 # words.
 #
 # reasonably optimized assembler version 
 #
eye_profil(swapsum):
	lis	r0,0		# start sum at zero
	sis	r3,1		# done already?
	jl	0f		# yes return with zero
	beqx	2f		# only do 1 word
	ls	r5,0(r2)	# get a word to prime it
1:
	srpi	r5,8		# r4 = r5 >> 8		( 0 A B C )
	mc03	r4,r5		# r4[0] = r5[3]		( D A B C )
	mc13	r4,r4		# r4[1] = r4[3]		( D C B C )
	mc30	r4,r5		# r4[3] = r5[0]		( D C B A )
	a	r0,r4		# add it in
	inc	r2,4
	sis	r3,1		# count down number of words
	bhx	1b		# if > 0 then keep going
	 ls	r5,0(r2)	# get a word
 # come here when r3 == 0, so only one more word to process
2:
	srpi	r5,8		# r4 = r5 >> 8		( 0 A B C )
	mc03	r4,r5		# r4[0] = r5[3]		( D A B C )
	mc13	r4,r4		# r4[1] = r4[3]		( D C B C )
	mc30	r4,r5		# r4[3] = r5[0]		( D C B A )
	brx	r15		# and return and ...
	 cas	r2,r0,r4	# add it in

0:
	brx	r15
	 lis	r2,0		# so return zero
 #
 # assember routine to do a 32 bit checksum add for in_cksum
 #
 #	sum = ck_sum(sum, w, mlen)
 #	r2	      r2  r3  r4
 #
 # note that the final loop will be done on loop mode on ROMP'c for that
 # little bit extra speed (we also do the inc and dec before referencing
 # r0 to get the last bit of overlap we can).
 #
eye_profil(ck_sum):
	ais	r2,0		# clear c0
	ci	r4,32
	jl	1f		# not 32 bytes left to do
2:
	ls	r0,0(r3)	# get 4 bytes
	ls	r5,4(r3)	# get 4 bytes
	ae	r2,r0		# add it in
	ls	r0,8(r3)	# get 4 bytes
	ae	r2,r5		# add it in
	ls	r5,12(r3)	# get 4 bytes
	ae	r2,r0		# add it in
	ls	r0,16(r3)	# get 4 bytes
	ae	r2,r5		# add it in
	ls	r5,20(r3)	# get 4 bytes
	ae	r2,r0		# add it in
	ls	r0,24(r3)	# get 4 bytes
	ae	r2,r5		# add it in
	ls	r5,28(r3)	# get 4 bytes
	ae	r2,r0		# add it in
	cal	r3,32(r3)	# incr by 32
	cal	r4,-32(r4)	# decr by 32
	ae	r2,r5		# add it in
	ci	r4,32
	jnl	2b
 # less then 32 bytes to go
1:
	cis	r4,4		# more to do?
	blrx	r15		# nope
	 aei	r2,r2,0		# add final carry
0:
	ls	r0,0(r3)	# get 32 bits
	inc	r3,4		# point to next
	dec	r4,4		# count down (we don't use sis because
				# it would change C0 which we need
	ae	r2,r0		# add in C0 from previous loop and the word
	cis	r4,4		# test if we're done
	jnl	0b		# not yet (C0 still set from ae)
	brx	r15		# return to caller and ...
	 aei	r2,r2,0		# add final carry
	
 #
 # store_instn(addr,value)
 # store the 4-byte instruction "value" at the 
 # real memory address "addr" with translation off.
 # translation is off since the kernel instructions
 # are usualy write-protected.
 # this is used to fix up the kernel floating point 
 # BALA's to be bali's.
 #
eye_profil(store_instn):
	stm	r14,-8(sp)	# save registers
	ai	sp,sp,-8
	bali	r15,flipxlate	# turn off xlate

 # end of prolog
	puth	r3,2(r2)	# store low order half
	sri16	r3,0		# get high order half
	puth	r3,0(r2)	# store high order half

 # start of epilog
	bali	r15,flipxlate
	lm	r14,0(sp)
	brx	r15
	ai	sp,sp,8

 # set bit 22 in scr 12 (ie set the bit in the IRB
eye_profil(setsoftint):
	brx	r15
	setsb	r12, 22-16

eye_profil(asmwait):
	wait
	br	r15

eye_profil(asmtgte):
	tgte	r1, r1
	br	r15

eye_profil(setint0):
	brx	r15
	setsb 	r12, 16-16

#ifndef	ATR
#ifndef KBDREBOOT
 # Called from C.  Interrupts are already masked.  Translate is on.
 # Hard ipl vector is at 0x24.  It goes through the device checks (which
 # run all the #s in the leds) and takes ~1min longer.
#define SOFTVEC 0x8
eye_profil(_reboot):
        bali    r15,flipxlate           # turn off xlate
        get     r7,$0xf0008c40          # address of component reset reg. A
        lis     r0,0                    # reset devices in all i/o slots
        stcs    r0,0(r7)                # |
        get     r7,$0xf0008c60          # address of component reset reg. B
        stcs    r0,0(r7)                # reset devices on planar board
        get     r7,$(MMUBASE)           # base i/o address of MMU
        lis     r0,14                   # map in 8 Meg of ram at 0
        iow     r0,MMU_RAM(r7)          # |
        get     r0,$MMU_ROS_SPEC        # map ros in at 8 Meg
        iow     r0,MMU_ROS(r7)          # |
        cau     r7,0x80(r0)             # goto ros soft ipl entry point
        l       r7,SOFTVEC(r7)          # |
        br      r7                      # |
#endif /* KBDREBOOT */
#endif /* ATR */
