#
# line 1 "EAL.s"
/
/
/      SCCS File Type - Emulator Source File
/
/      What identification string
/
.data
S_EAL_s: <@(#)EAL.s	3.3\0>
.text

/******************************************************************************
/ 
/ COPYRIGHT:  1979, by Ford Aerospace and Communications Corp.
/ ADDRESS:    Ford Aerospace and Communications Corp.
/             Western Development Laboratories
/             3939 Fabian Way
/             Palo Alto, California 94303
/             Attention: Software Technology Dept.
/             Mail Stop: V02 
/ 
/ CPCI:   Emulator
/ 
/ CPC:    EMS
/ 
/ CP:     EAL
/ 
/ TAG:    EAL
/ 
/ MODULE NAME:    Assembly Language Support
/ 
/ REFERENCES-
/   A Specs:  
/   B5 Specs:  
/ 
/ HISTORY:
/   AUTHOR:   
/   VERSION:  3.3 of 11/24/80
/   MODULE TYPE: Emulator Source File
/ PRIVILEGES:  
/ 
/ SPECIAL NOTES:  
/ 
/ ****************************************************************/
/ this must be loaded first in the emulator, to run on the Kernel simulator
/ because mfpi will not work with split I and D space when the Current and
/ the Previous mode are both User.  (This is a DEC feature).  Due to
/ this problem the emulator which runs with the Kernel simulator must
/ not use split I and D space because of the need to get the trap number from
/ I space for system calls.
/ The first instruction jumps to start which is the start of crt0.
/ It then allocates space that is used for the low memory pseudo interrupt
/ vectors and the user's stack.


/------------------------------------------------------------------------------
/
/       The following definition is used in conditional assembly
/       to distinguish between versions either supporting or not
/       supporting a user domain process.  Distinguishing values are:
/               0       no user domain process
/               1       user domain process
/       To change from one state to the other, it is necessary
/       to edit this file and manually change the definition.
/       (Note that the idiom .if 1-RUN_USER is roughly equivalent
/       to the C preprocessor's # ifndef RUN_USER).
/
RUN_USER = 1
/
/------------------------------------------------------------------------------

/------------------------------------------------------------------------------
/
/       The following defintion is used to distinguish between an
/       Emulator and an NKSR version of EAL.s.  Distinguishing values:
/               1:      Emulator version
/               0:      NKSR version
EMULATOR = 1
/
/------------------------------------------------------------------------------

.globl start
.text
	jmp     start

.data
.if 1-RUN_USER
. = .+2000      /       room for pseudo-interrupt vectors and stack
.endif
.if RUN_USER
. = .+300       /       pseudo-interrupt vectors actually run up through 274
.endif


.text
/ assembly language support
/ 11/70 CPUs

/ Kernel call emt numbers
Ksil    =  34.  / K_set_pil
Kintrtn =  10.  / K_interrupt_retrun

IOlev   =  4    / level of I/O interupts

/ non-UNIX instructions
mfpi    = 6500^tst
mtpi	= 6600^tst
mfpd	= 106500^tst
mtpd	= 106600^tst
emt     = 104000^sys
ldfps	= 170100^tst
stfps	= 170200^tst
halt	= 0
wait	= 1
reset	= 5
rtt	= 6

.globl  _fubyte, _subyte
.globl	_fuword, _suword
.globl	_fuibyte, _suibyte
.globl	_fuiword, _suiword
.globl  _nofault

_fuibyte:
	mov	2(sp),r1
	bic	$1,r1
	jsr	pc,giword
	br	2f

_fubyte:
	mov	2(sp),r1
	bic	$1,r1
	jsr	pc,gword

2:
	cmp	r1,2(sp)
	beq	1f
	swab	r0
1:
	bic	$!377,r0
	rts	pc

_suibyte:
	mov	2(sp),r1
	bic	$1,r1
	jsr	pc,giword
	mov	r0,-(sp)
	cmp	r1,4(sp)
	beq	1f
	movb	6(sp),1(sp)
	br	2f
1:
	movb	6(sp),(sp)
2:
	mov	(sp)+,r0
	jsr	pc,piword
	clr	r0
	rts	pc

_subyte:
	mov	2(sp),r1
	bic	$1,r1
	jsr	pc,gword
	mov	r0,-(sp)
	cmp	r1,4(sp)
	beq	1f
	movb	6(sp),1(sp)
	br	2f
1:
	movb	6(sp),(sp)
2:
	mov	(sp)+,r0
	jsr	pc,pword
	clr	r0
	rts	pc

_fuiword:
	mov	2(sp),r1
fuiword:
	jsr	pc,giword
	rts	pc

_fuword:
	mov	2(sp),r1
fuword:
	jsr	pc,gword
	rts	pc

giword:
	mov     r1,-(sp)        / save r1 on stack
	mov     r0,-(sp)        / save r0 on stack
	tst     -(sp)           / make room for retruned old level
	mov     $IOlev,-(sp)    / interrupt level to mask out all but
				/ hardware errors
	mov     sp,-(sp)        / set up pointer to param. block for Ksil
				/     to point to level (start of block)
	tst     -(sp)           / kernel expects a word here (normally pc)
/       emt     Ksil            / Call kernel to set level
	mov	_nofault,-(sp)
	mov	$err,_nofault
	mfpi	(r1)
	mov     (sp)+,r1        / use R1. R0 gets changed when setting level
	br	1f

gword:
	mov     r1,-(sp)        / save r1 on stack
	mov     r0,-(sp)        / save r0 on stack
	tst     -(sp)           / make room for retruned old level
	mov     $IOlev,-(sp)    / interrupt level to mask out all but
				/ hardware errors
	mov     sp,-(sp)        / set up pointer to param. block for Ksil
				/     to point to level (start of block)
	tst     -(sp)           / kernel expects a word here (normally pc)
/       emt     Ksil            / Call kernel to set level
	mov	_nofault,-(sp)
	mov	$err,_nofault
	mfpd    (r1)
	mov     (sp)+,r1        / use R1. R0 gets changed when setting level
	br	1f

_suiword:
	mov	2(sp),r1
	mov	4(sp),r0
suiword:
	jsr	pc,piword
	rts	pc

_suword:
	mov	2(sp),r1
	mov	4(sp),r0
suword:
	jsr	pc,pword
	rts	pc

piword:
	mov     r1,-(sp)        / save r1 on stack
	mov     r0,-(sp)        / save r0 on stack
	tst     -(sp)           / make room for retruned old level
	mov     $IOlev,-(sp)    / interrupt level to mask out all but
				/ hardware errors
	mov     sp,-(sp)        / set up pointer to param. block for Ksil
				/     to point to level (start of block)
	tst     -(sp)           / kernel expects a word here (normally pc)
/       emt     Ksil            / Call kernel to set level
	mov	_nofault,-(sp)
	mov     $err1,_nofault  / if error must pop extra value off stack
	mov     10.(sp),-(sp)   / old r0 - data to be moved.
	mtpi    (r1)
	br	1f

pword:
	mov     r1,-(sp)        / save r1 on stack
	mov     r0,-(sp)        / save r0 on stack
	tst     -(sp)           / make room for returned old level
	mov     $IOlev,-(sp)    / interrupt level to mask out all but
				/ hardware errors
	mov     sp,-(sp)        / set up pointer to param. block for Ksil
				/     to point to level (start of block)
	tst     -(sp)           / kernel expects a word here (normally pc)
/       emt     Ksil            / Call kernel to set level
	mov	_nofault,-(sp)
	mov     $err1,_nofault  / if error must pop extra value off stack
	mov     12.(sp),r1      / xxxxxxdebug
	mov     10.(sp),-(sp)   / old r0 - data to be moved.
	mtpd    (r1)
	br	1f

1:
	mov	(sp)+,_nofault
	mov     6(sp),4(sp)     / set level to saved level
/       emt     Ksil            / reset interrupt level
	add     $10.,sp         / move back stack pointer to return address
	mov     r1,r0           / put returned value in r0
	mov     (sp)+,r1        / restore r1
	rts	pc

err1:
	tst     (sp)+           / if mtpx failed- Kernel backed up instruction
				/ so value to move still on stack
err:
	mov	(sp)+,_nofault
	mov     6(sp),4(sp)     / set level to saved level
/       emt     Ksil            / reset interrupt level
	add     $14.,sp         / move back stack pointer to return address
				/ of the caller of the current routine
				/ - skip one level of subroutine return
				/ note: r1 not restored - returning to C.
	mov	$-1,r0
	rts	pc

.globl	_copyin, _copyout
.globl	_copyiin, _copyiout
_copyiin:
	jsr	pc,copsu
	mov     $4f,_nofault
1:
	mfpi	(r0)+
	mov	(sp)+,(r1)+
	sob	r2,1b
	br	2f

_copyin:
	jsr	pc,copsu
	mov     $4f,_nofault
1:
	mfpd	(r0)+
	mov	(sp)+,(r1)+
	sob	r2,1b
	br	2f

_copyiout:
	jsr	pc,copsu
	mov     $3f,_nofault
1:
	mov	(r0)+,-(sp)
	mtpi	(r1)+
	sob	r2,1b
	br	2f

_copyout:
	jsr	pc,copsu
	mov     $3f,_nofault
1:
	mov	(r0)+,-(sp)
	mtpd	(r1)+
	sob	r2,1b

	/ 2: = normal exit- restore level and nofault clear r0 and return
2:
	mov	(sp)+,_nofault
	mov     6(sp),4(sp)     / set level to saved level
/       emt     Ksil            / reset interrupt level
	add     $8.,sp          / move back stack pointer over interrupt level
				/ information. Now points to the saved value
				/ of r2
	mov	(sp)+,r2
	clr     r0
	rts	pc

copsu:
	mov     (sp)+,r1        / pick up the return pc
	mov     r2,-(sp)        / save r2

	tst     -(sp)           / make room for returned old level
	mov     $IOlev,-(sp)    / interrupt level to mask out all but
				/ hardware errors
	mov     sp,-(sp)        / set up pointer to param. block for Ksil
				/     to point to level (start of block)
	tst     -(sp)           / kernel expects a word here (normally pc)
/       emt     Ksil            / Call kernel to set level
	mov	_nofault,-(sp)

	mov     r1,-(sp)        / put the return pc back on stack
	mov     16.(sp),r0      / from address
	mov     18.(sp),r1      / to address
	mov     20.(sp),r2      / byte count
	asr     r2              / change byte count to word count
	rts	pc

	/ 3: and 4: are the address saved in nofault which cause goto when
	/ the interdomain transfers cause a memory fault
3:
	tst     (sp)+           / if mtpx failed- Kernel backed up instruction
				/ so value to move still on stack
4:
	mov	(sp)+,_nofault
	mov     6(sp),4(sp)     / set level to saved level
/       emt     Ksil            / reset interrupt level
	add     $8.,sp          / move back stack pointer over interrupt level
				/ information. Now points to the saved value
				/ of r2
	mov	(sp)+,r2
	mov	$-1,r0
	rts	pc


/-------------------------------------------------------------------------
/
/       FUNCTION        rsave
/
/       PURPOSE         Save R0-R4 on the stack;
/
/       INPUTS  {       None
/       }
/
/       DESCRIPTION {
/                       This assembly routine is called from the
/                       Pseudo interrupt routines upon first entry
/                       to save the registers.  The registers may be
/                       from the User or Emulator.
/                       Should be called using  jsr pc, _rsave
/       }
/
/       ASSERT {
/       }
/
/       EFFECT {
/       }
/
/----------------------------------------------------------------------
.globl _rsave

_rsave:
	mov     r4,-(sp)
	mov     r3,-(sp)
	mov     r2,-(sp)
	mov     r1,-(sp)
	mov     r0,-(sp)
	jmp     *12(sp)

/-------------------------------------------------------------------------
/
/       FUNCTION        rrestor
/
/       PURPOSE         Restor R0-R4 from the stack;
/
/       INPUTS  {       None
/       }
/
/       DESCRIPTION {
/                       This assembly routine is called just before the
/                       the K_interrupt_return call is made.  It
/                       Restores the registers saved by rsave.
/                       Should be called using  jsr pc, _rrestor
/       }
/
/       ASSERT {
/       }
/
/       EFFECT {
/       }
/
/----------------------------------------------------------------------
.globl _rrestor

_rrestor:
	mov     (sp)+,12(sp)    /save the return pc at the bottom of the
	mov     (sp)+,r0        /stack frame saved by rsave
	mov     (sp)+,r1
	mov     (sp)+,r2
	mov     (sp)+,r3
	mov     (sp)+,r4
	rts     pc

/-------------------------------------------------------------------------
/
/       FUNCTION        pi_base
/
/       PURPOSE         Handler (entry point) for base level(system calls)
/                       Pseudo Interrupts interrupts;
/
/       INPUTS  {       None;
/       }
/
/       DESCRIPTION {
/       }
/
/       ASSERT {
/       }
/
/       EFFECT {
/       }
/
/----------------------------------------------------------------------
.globl _pi_base
.globl _ESC_hd
.globl _saveUsp

.if 1-RUN_USER
.globl _in_USR
.endif

_pi_base:
.if 1-RUN_USER
	mov     sp,_saveUsp     /save the User's stack pointer
	mov     saveEsp,sp      /this is needed only for the Ksim version
				/because only one domain.
	dec     _in_USR
.endif
	jsr     pc,_rsave
.if EMULATOR
	mov     sp,-(sp)        /pass the value of the stack pointer
	jsr     pc,_ESC_hd
.endif
.if 1-EMULATOR
	mov     $0,-(sp)
	jsr     pc,_ECCpi
.endif
	tst     (sp)+           /remove the value from the stack
	jsr     pc,_rrestor

	/ restor the User stack pointer and
	/ return to the user

.if 1-RUN_USER
	mov     sp,saveEsp
	mov     _saveUsp,sp
	inc     _in_USR
.endif

	emt     Kintrtn

/-------------------------------------------------------------------------
/
/       FUNCTION        pi_ipc, pi_time, pi_sig, pi_io and pi_hard
/
/       PURPOSE         Handler (entry point) for Pseudo Interrupts
/                       other that pi_base.
/
/       INPUTS  {       None;
/       }
/
/       DESCRIPTION {
/                       each routine saves the regsters, places interrupt
/                       level on the stack and calls ECCpi.  When ECCpi
/                       returns each routine restores the registers then
/                       does a K_interrupt_return.
/       }
/
/       ASSERT {
/       }
/
/       EFFECT {
/       }
/
/----------------------------------------------------------------------
.globl _pi_ipc
.globl _pi_time
.globl _pi_sig
.globl _pi_io
.globl _pi_hard
.globl _ECCpi

/////// pi_ipc
_pi_ipc:
.if 1-RUN_USER
	tst     _in_USR
	beq     1f
	mov     sp, _saveUsp
	mov     saveEsp, sp
	dec     _in_USR
.endif
1:      jsr     pc, _rsave      / save all the registers
	mov     $1, -(sp)       / push interrupt level on stack
	jsr     pc, _ECCpi
	tst     (sp)+           / remove the interrupt level from the stack
	jsr     pc, _rrestor    /restore saved registers
.if 1-RUN_USER
	tst     _in_USR
	beq     2f
	mov     sp, saveEsp
	mov     _saveUsp, sp
	inc     _in_USR
.endif
2:      emt     Kintrtn

/////// pi_time
_pi_time:
.if 1-RUN_USER
	tst     _in_USR
	beq     1f
	mov     sp, _saveUsp
	mov     saveEsp, sp
	dec     _in_USR
.endif
1:      jsr     pc, _rsave      / save all the registers
	mov     $2, -(sp)       / push interrupt level on stack
	jsr     pc, _ECCpi
	tst     (sp)+           / remove the interrupt level from the stack
	jsr     pc, _rrestor    /restore saved registers
.if 1-RUN_USER
	tst     _in_USR
	beq     2f
	mov     sp, saveEsp
	mov     _saveUsp, sp
	inc     _in_USR
.endif
2:      emt     Kintrtn

/////// pi_sig
_pi_sig:
.if 1-RUN_USER
	tst     _in_USR
	beq     1f
	mov     sp, _saveUsp
	mov     saveEsp, sp
	dec     _in_USR
.endif
1:      jsr     pc, _rsave      / save all the registers
	mov     $3, -(sp)       / push interrupt level on stack
	jsr     pc, _ECCpi
	tst     (sp)+           / remove the interrupt level from the stack
	jsr     pc, _rrestor    /restore saved registers
.if 1-RUN_USER
	tst     _in_USR
	beq     2f
	mov     sp, saveEsp
	mov     _saveUsp, sp
	inc     _in_USR
.endif
2:      emt     Kintrtn

/////// pi_io
_pi_io:
.if 1-RUN_USER
	tst     _in_USR
	beq     1f
	mov     sp, _saveUsp
	mov     saveEsp, sp
	dec     _in_USR
.endif
1:      jsr     pc, _rsave      / save all the registers
	mov     $4, -(sp)       / push interrupt level on stack
	jsr     pc, _ECCpi
	tst     (sp)+           / remove the interrupt level from the stack
	jsr     pc, _rrestor    /restore saved registers
.if 1-RUN_USER
	tst     _in_USR
	beq     2f
	mov     sp, saveEsp
	mov     _saveUsp, sp
	inc     _in_USR
.endif
2:      emt     Kintrtn

/////// pi_hard
_pi_hard:
.if 1-RUN_USER
	tst     _in_USR
	beq     1f
	mov     sp, _saveUsp
	mov     saveEsp, sp
	dec     _in_USR
.endif
1:      jsr     pc, _rsave      / save all the registers
	mov     $5, -(sp)       / push interrupt level on stack
	jsr     pc, _ECCpi
	tst     (sp)+           / remove the interrupt level from the stack
	jsr     pc, _rrestor    /restore saved registers
.if 1-RUN_USER
	tst     _in_USR
	beq     2f
	mov     sp, saveEsp
	mov     _saveUsp, sp
	inc     _in_USR
.endif
2:      emt     Kintrtn



/------------------------------------------------------------------------------
/
/       The following routine exists in two versions: one for
/       an emulator supporting a user domain program, and the
/       other for a (test version) emulator running completely
/       in the supervisor domain.
/
.globl  _u_start

.if 1-RUN_USER       / no user domain version:
/ Test routine to start the user the first time:
/       Note the provision of a separate stack area
/       for the user domain program.
_u_start:
	mov     sp,saveEsp
	mov     $1500,sp
	inc     _in_USR
	emt     Kintrtn
.endif

.if RUN_USER         / user domain version:
/       Given that we use the user domain, all we have to do
/       is initialize the user stack pointer and interrupt-return
/       to the user program.
_u_start:
	mov     $177776,-(sp)   / initial value of user stack pointer
	jsr     pc,_set_usr_sp
	emt     Kintrtn
.endif


/-------------------------------------------------------------------------
/
/       FUNCTION        push_on_E_stack
/
/       PURPOSE         Push one word on the Emulator's stack.
/
/       INPUTS  {
/                       The argument is passed to routine on the stack.
/       }
/
/       OUTPUTS {       None
/       }
/
/       DESCRIPTION {
/               This assembly routine is called with one argument on the
/               stack.  The routine just does a jmp back to the calling
/               routine instead of doing a rts.  This leaves the argument
/               on the stack and the sp pointing to the next location.
/
/       }
/
/----------------------------------------------------------------------



.globl _push_on_E_stack
_push_on_E_stack:
	jmp *(sp)       / thats all folks

/-------------------------------------------------------------------------
/
/       FUNCTION        pop_E_stack
/
/       PURPOSE         Pop the specified number of bytes from the stack.
/
/       INPUTS  {
/                       Number of bytes to be popped off the stack. Should
/                       be an even number.
/       }
/
/       OUTPUTS {       None.
/       }
/
/       DESCRIPTION {
/                       The specified number of bytes are added to the
/                       stackpointer. Contents of R0 are destroyed.
/       }
/----------------------------------------------------------------------

.globl _pop_E_stack
_pop_E_stack:
	mov (sp)+,r0    /save return pc
	add (sp),sp
	jmp (r0)


.if RUN_USER
/------------------------------------------------------------------------------
/
/       FUNCTION        get_usr_sp
/                       set_usr_sp
/
/       PURPOSE         Get (Set) the user domain stack pointer.
/
/       INPUTS          (set_usr_sp):   the value to be set, on the stack
/
/       OUTPUTS         the value set or retrieved, in r0
/
/       DESCRIPTION     These routines use the m[tf]pd instructions to reach
/                       into the user domain data space and get or set the
/                       stack pointer (r6).
/
/       NOTE            These routines are defined only if RUN_USER is defined.
/
/------------------------------------------------------------------------------
.globl _get_usr_sp
.globl _set_usr_sp

_get_usr_sp:
	mfpd    sp
	mov     (sp)+,r0        / Mfpd has left the result on the stack.
	rts     pc

_set_usr_sp:
	mov     2(sp),r0        / The argument is on the stack immediately
				/ preceding our return address.
	mov     r0,-(sp)        / Push it for mtpd to gobble up.
	mtpd    sp
	rts     pc

.endif  / RUN_USER


/------------------------------------------------------------------------------
/
/               Data declarations:
/
.bss

_nofault:       . = .+2
_saveUsp:       . = .+2
saveEsp:        . = .+2
_in_USR:        . = .+2
# line 4 "Standard Input"
