AUSAM/sys106/conf/m70.s

Compare this file to the similar file:
Show the results in this format:

/  options.

.ht = 1		/ tu-16 is dump device
.mt = 0		/ tu-10 is dump device
.pdp70 = 1	/ 11/70 is target machine
.fp = 1		/ floating point processor present
.hpdisk = 0	/ enable ecc error correction code for hp disk
.newputc = 1	/ set if want new superior getc/putc
.display = 1	/ enable location 52 as magic pattern !!
.swtchdsp = 1	/ enable location 70 as switch count
			/ really needs .display as well
.idle = 0	/ 0=> place idle in l70.s 1=> place idle here
.powerfail = 0	/ 1=> support for powerfail 0=> no support
.systime = 1	/ 1=> code for _systime generated
.bufmap = 1	/ buffers addressed by KA5
.ubmapd = 1	/ used with above change if unibus devices
.newcopyseg = 1	/ don't use m[ft]pi instructions
.profile = 0	/ enable the profiling
.qswtch = 1	/ reflects state of PROCESS_QUEUES

/	indicate highest priority at which character queues
/	will be accessed

_spl_tty 	=	_spl5
tty_prio	=	5

/ machine language assist for a pdp-11/70 with fpp
/ extended and (improved) J. N. Rottman

/ This code will also work on an 11/45 if the test on the
/ CPU error register is replaced with a slower direct comparison
/ on the kernal SP. (pdp70=0)


/	External definitions for l.s

	.globl	dump, start, call, quickcall, code00, code01, code02, code03
	.globl	code04, code05, code06, pirqi

/	External data references

	.globl	_etext, _edata, _end, _regloc, _cfreelist, _cfreecount
	.globl	_runrun

/	External text references

	.globl	_main, _trap, _swtch
.if	.qswtch
	.globl	_qswtch
.endif

/	External data definitions

	.globl	_ka6, _cputype, nofault, ssr, _u, _uufec, _uufsav, _uuerror

/	External text definitions

	.globl	_savfp, _incupc, _display, _getc, _putc, _backup
	.globl	_fubyte, _fuword, _subyte, _suword, loadfp, _fkword
	.globl	_fuibyte, _suibyte,  _fuiword, _suiword, _spl_tty
	.globl	_savu, _retu, _aretu
.if	.idle
	.globl	_idle
.endif
.if	.bufmap
	.globl	_bswtch, _bufarea, _b
.endif
.if	.display
	.globl	diswflag
.endif
.if	.swtchdsp
	.globl	_swi_count,_lst_count
.endif
	.globl	_spl0, _spl1, _spl4, _spl5, _spl6, _spl7
	.globl	_copyin, _copyout, _clearseg, _copyseg
	.globl	_dpcmp, _ldiv, _longdiv, _lrem, csv, cret
	.globl	_btoc, _itol
	.globl	_systime, _time

/	Non-unix instructions

mfpi	=	6500 ^ tst
mtpi	=	6600 ^ tst
mfpd	=	106500 ^ tst
mtpd	=	106600 ^ tst
spl	=	230
ldfps	=	170100 ^ tst
stfps	=	170200 ^ tst
stst	=	170300 ^ tst
wait	=	1
rti	=	2
rtt	=	6
halt	=	0
reset	=	5


/
/	Mag-tape dump.
/	Save the registers in low core and write all
/	of core onto magtape.  Entry is from 44  abs.
/
/	Registers r0, r1, r2, r3, r4, r5, r6, KIA6
/	are saved in low core starting at location 4.
/	The blocksize for the type is 512. bytes.
/

.data

dump:	mov	r0, 4
	mov	$6,r0
	mov	r1,(r0)+
	mov	r2,(r0)+
	mov	r3,(r0)+
	mov	r4,(r0)+
	mov	r5,(r0)+
	mov	sp,(r0)+
	mov	KDSA6,(r0)+
.if	.bufmap
	mov	KDSA5,(r0)+
.endif
	mov	pc,46		/ protect in case of restart

.if	.mt
	mov	$MTC,r0
	mov	$60004,(r0)+
	clr	2(r0)

1:	mov	$-512.,(r0)
	inc	-(r0)

2:	tstb	(r0)
	bge	2b
	tst	(r0)+
	bge	1b

	reset
	mov	$60007,-(r0)
	br	.
.endif
.if .ht
	reset
	mov	$1300,*$HTTC
	mov	$HTCS1,r0
	mov	$60,(r0)
1:
	mov	$177000,*$HTFC
	mov	$177400,*$HTWC
	inc	(r0)
2:
	tstb	(r0)
	bge	2b
	tst	(r0)
	bge	1b
	mov	$27,(r0)
	br	.

HTCS1	=	172440
HTWC	=	172442
HTBA	=	172444
HTFC	=	172446
HTCS2	=	172450
HTTC	=	172472

.endif


/ Startup code.  Since core is shuffled, this code can
/ be execute but once.

start:	mov	$code15,*$0	/ set to catch spurious interrupts
				/ also prevent restart from zero
	reset
	clr	PS		/ These things are not defined after reset
.if	.pdp70
	clr	CPUERR
	mov	$-1,MEMERR
.endif

/ set KIO to physical 0

	mov	$77406,r3
	mov	$KISA0,r0
	mov	$KISD0,r1
	clr	(r0)+
	mov	r3,(r1)+

/ set KI1-6 to eventual text resting place

	mov	$_end+63.,r2
	ash	$-6,r2
	bic	$!1777,r2

1:	mov	r2,(r0)+
	mov	r3,(r1)+
	add	$200,r2
	cmp	r0,$KISA7
	blos	1b

/ set KI7 to IO segment for escape

	mov	$IO,-(r0)

/ set KD0-7 to  physical

	mov	$KDSA0,r0
	mov	$KDSD0,r1
	clr	r2

1:	mov	r2,(r0)+
	mov	r3,(r1)+
	add	$200,r2
	cmp	r0,$KDSA7
	blos	1b

/ Initialization :
/	get a temporary 1-word stack and turn on
/	segmentation.  Then copy text to I space
/	and clear the bss in data space.

	mov	$stk+2,sp
	mov	$67,SSR3		/ 22-bit map, K+U sep.
	bit	$20,SSR3
	beq	1f
	mov	$70.,_cputype

1:	inc	SSR0
	mov	$_etext,r0
	mov	$_edata,r1
	add	$_etext-8192.,r1

1:	mov	-(r1),-(sp)
	mtpi	-(r0)
	cmp	r1,$_edata
	bhi	1b

1:	clr	(r1)+
	cmp	r1,$_end
	blo	1b

/ Use KI escape to set KD7 to IO segment. Set KD6 to the
/ first available core to serve as the swap process's
/ u-table

	mov	$IO,-(sp)
	mtpi	*$KDSA7
	mov	$_etext-8192.+63.,r2
	ash	$-6,r2
	bic	$!1777,r2
	add	KISA1,r2
	mov	r2,KDSA6
	mov	$7406,KDSD6		/ USIZE long only (RW)

/ Set up the real stack at the top of the u-table, and
/ clear the rest of it

	mov	$_u+[usize*64.],sp
	mov	$_u,r0

1:	clr	(r0)+
	cmp	r0,sp
	blo	1b

.if	.bufmap
	/ set up KDSA5 for buffer pointer
	mov	KDSA7,KDSA5		/ hopefully illegal
	mov	$3406,KDSD5		/ 512 bytes, RW

.endif

/ Start system profiling

/	jsr	pc,_isprof

/ Set up previous mode as user mode and call main.
/ On return, enter user mode at 0R

	mov	$30000,PS
	jsr	pc,_main
	mov	$170000,-(sp)
	clr	-(sp)
	rtt



.text

/ Entry to the system from all traps, interrupts, and aborts is
/ handled in the following code.
/
/ Each device's vector contains a new kernal PS at the device's
/ bus grant priority,  and a pointer to a code segment of the
/ form:
/	jsr r0,call; _xxxxxxx
/	jsr r0,quickcall; _xxxxxxx
/ where `xxxxxxx' is the name of the device's interrupt routine.
/
/ Traps and aborts are more complicated. Entry is always in
/ kernal mode at priority 7, and enters the following routines:
/
/ 1)	code00		Floating point asynchronous interrupt. If
/			the user is active, the interrupt is reported
/			back immediately.  Otherwise, since the interrupt
/			is asynchronous, it could occur from kernal mode
/			or supervisor mode. In this case the interrupt is
/			just posted for the user, and if the interrupted
/			priority is high, the actual processing is PIRQ'd
/			at priority 1. Since the FEA and FEC are volitile,
/			they are saved when the interrupt occurs. They
/			cannot be restored, but may be retrieved via a system
/			call.
/
/ 2)	code01		IOT.  If the request came from the supervisor state,
/			it is a request for an interrupt exit from a super-
/			visor interrupt handler.  The handler could not do 
/			the rti directly since it could have interrupted a kernal
/			task.
/				If the previous mode was user mode, the trap
/			is posted in the usual way. For efficiency, no check
/			is made to distinguish supervisor from kernal iot's,
/			which should never occur.
/
/ 3)	code02		BPT/trace trap, illegal instruction, system entry:
/			If these are from the user they are handled in the
/			standard manner.
/				Any of these calls from the supervisor abort
/			it with an indicative error code.
/				Any of these calls from the kernal are fatal.
/
/  4)	code03		Parity errors.
/			errors.
/
/ 5)	code04		EMT. If this code is from the supervisor, it is a
/			request for a kernal function. If the function code
/			is legal, the function is performed and control returns;
/			otherwise, the supervisor is aborted.
/				From user mode this is just a trappable signal.
/
/ 6)	code05		Bus error. The cpu error register is interrogated to
/			see if this a stack overflow (code07) or a bus error.
/			The following applies just to real bus errors:
/				nofault_______ is checked; if it is non-zero it is
/			the address of an error catching routine to which control
/			should be returned on the rti. Otherwise, bus errors
/			are handled like class (3).
/
/ 7)	code06		Segmentation violation. If nofault is set, the
/			segmentation error registers are thawed, and control
/			returns immediately.  If the error comes from super-
/			visor state, the supervisor is aborted. If it comes
/			from kernal state, the system dies.  If it comes from
/			user state, the error registers are saved for a possible
/			stack page fault backup.
/
/ 8)	code07		Bad PIRQ, stack overfow. (see (6)). These are fatal
/			software botches.
/
/
/	The codes reported to trap are:
/	NON-FATAL
/		0	User floating point exception
/		1	Kernal floating point exception
/		2	Illegal instruction
/		3	BPT/trace trap
/		4	SYS entry
/		5	IOT
/		6	EMT
/		7	Bus error
/		10	Segmentation violation
/		12	Parity
/		15	Trap thru location zero
/		16	Power fail recovery completed
/			( trap is called from powerf.s )
/	FATAL-
/		22	Kernal illegal instruction
/		23	Kernal BPT
/		24	Kernal SYS
/		25	Kernal IOT
/		26	Kernal EMT
/		27	Kernal Bus error
/		30	Kernal Segmentation
/		32	Kernal parity
/		33	Bad PIRQ
/		34	Stack limit overflow
/

code00:	stst	*_uufec		/ save FEC and FEA in active u
	bit	$340,2(sp)	/ from high priority ?
	beq	codeff		/ no - handle immediately
	bis	$PIRQ1,PIRQ	/ set for later processing
	rti			/ and split

pirq1:	bic	$PIRQ1,PIRQ	/ dispatch from PIRQ request 1


codeff:	clr	-(sp)		/ trap code
	bit	$20000,PS	/ from user mode ?
	bne	1f		/ yes
	inc	(sp)		/ set to post and leave
1:	jbr	callt1		/ don't add in displacment

pirq2:
pirq3:
pirq4:
pirq5:
pirq6:
pirq7:
	clr	PIRQ		/ Illegal PIRQ's - clear register
	mov	$33,-(sp)	/ set code

	br	callt1		/ report fatal error

code05:

.if	.pdp70			/ Use CPU error register
	mov	CPUERR,_cpuereg	/ get CPU error register
	clr	CPUERR		/ now reset it !
	bit	$14,_cpuereg	/ yellow/red stack violation ??
	bne	3f		/ yes, so branch.
	bit	$160,_cpuereg	/ odd addr, bus timeout, no mem?
	bne	1f		/ yes, so branch
	bit	$200,_cpuereg	/ no, but illegal halt ??
	beq	1f		/ no, so branch
	mov	$2,-(sp)	/ yes, set illegal instruction
	br	callt1

.bss
slrbef:		. = . + 2
r0save:		. = . + 2
.globl	spsave
spsave:		. = . + 2
.globl	_cpuereg
_cpuereg:	. = . + 2
.text

3:
	tst	slrbef		/ prior stack limit trap ??
	bne	9f		/ --> yes
	bit	$4,_cpuereg
	beq	8f		/ --> YELLOW Violation
9:
	mov	r0,r0save
	mov	sp,spsave
	mov	sp,r0		/ save current (offending??) sp
	mov	$142000,sp	/ reset stack.
	mov	2(r0),-(sp)	/ save the troublesome ps
	mov	 (r0),-(sp)	/ save the troublesome pc
	mov	r0save,r0
	br	7f
8:	sub	$400,SLR	/ let the yellow happen
	inc	slrbef		/ indicate we already got one !!
7:
/*agsm
	mov	$34,-(sp)	/ report code
	br	callt1
.endif

1:	tst	nofault		/ catchable?
	beq	1f		/ no
2:	mov	nofault,(sp)	/ adjust return
	rti			/ exit

1:	mov	$7,-(sp)	/ proper code
	br	callt

code06:	tst	nofault		/ catchable ?
	beq	1f		/ no
	mov	$1,SSR0		/ thaw registers
	br	2b		/ and take nofault exit

1:	bit	$20000,PS	/ user mode ?
	beq	1f		/ no - don't overwrite ssr
	mov	SSR0,ssr	/ save for possible backup
	mov	SSR1,ssr+2
	mov	SSR2,ssr+4

1:	mov	$1,SSR0		/ thaw error registers
	mov	$10,-(sp)	/ segmentation code
	br	callt

code03:				/ Parity. Try to be clever about it.
.if	.pdp70
	bis	$3,MEMCNTRL	/ disable traps for ....
				/ don't want multiple errors
				/ unless they are aborts
	mov	MEMERR,_memereg	/ Save Mem error register
	mov	MEMHIA,_memhigha
	mov	MEMLOA,_memlowa
	mov	_memereg,MEMERR	/ turn off error bits
	mov	$12,-(sp)	/ trap type is 12
	bit	$101000,_memereg/ fatal error ??
	beq	callt1		/ --> no, just flag as a parity error
	tst	nofault		/ is the error capable of being caught ??
	beq	callt		/ --> no, clobber user/system then
	mov	nofault,2(sp)	/ fix return from trap
	br	callt1		/ and treat as simple parity error
.endif
.if	.pdp70 - 1
	mov	$12,-(sp)	/ Trap type 12
	br	callt
.endif

.if	.pdp70
.bss
	.globl	_memhigha, _memlowa, _memereg
_memereg:	. = . + 2
_memhigha:	. = . + 2
_memlowa:	. = . + 2
.text
.endif

code15:				/ Hardware-type botches
	mov	PS,-(sp)	/ previous mode is unimportant
	br	callt2		/ so ignore it here

code01:
code02:
code04:	mov	PS,-(sp)	/ save emt trap code
/	br	callt


callt:
	bit	$20000,PS	/ user fault ??
	bne	callt1		/ --> yes
	add	$20,(sp)	/ indicate kernal fault
callt1:
	spl	0		/ out of critical section
callt2:				/ entry if not to drop pri
	mov	(sp),-(sp)	/ save device code
	mov	r0,2(sp)
	mov	r1,-(sp)
	mfpd	sp		/ get a sp
	mov	4(sp),-(sp)	/ device again
	mov	$1f,r0		/ point to trap
	br	2f

.data; 1: _trap; .text




call:	mov	PS,-(sp)	/ Entry from device interrupt vector
	mov	r1,-(sp)
	mfpd	sp
	mov	4(sp),-(sp)

.if	.powerfail
	.globl	_powflag

2:	tst	_powflag	/ powerfail in progress ??
	beq	2f		/ --> NO
	inc	_powflag
	halt
.endif
2:	bic	$!37,(sp)	/ extra bits in code bit 4 indicates user/kernal
	mov	nofault,6(sp)
	clr	nofault		/ catch errors
	bit	$20000,PS	/ from user mode ?
	beq	1f		/ no - call routine and split

	mov	$20,*_uufsav	/ set maint. bit
	jsr	pc,*(r0)+	/ call routine

2:	spl	6		/ interlock
	tstb	_runrun
	beq	2f		/ see if we should schedule
	spl	0		/ end of interlock
	jsr	pc,_savfp
.if	.qswtch
	jsr	pc,_qswtch	/ return process to run queue
.endif
.if	.qswtch-1
	jsr	pc,_swtch
.endif
	br	2b

2:	jsr	pc,loadfp

	tst	(sp)+		/ "dev"
	mtpd	sp
	br	2f

1:	jsr	pc,*(r0)+
	cmp	(sp)+,(sp)+	/ dump dev and sp

2:	mov	(sp)+,r1
	mov	(sp)+,nofault
	mov	(sp)+,r0
	/ fix015	gregr & chrism
	/	to make t bit tracing work properly
	bit	$3400,2(sp)
	bne	1f
	rti
1:	bic	$3400,2(sp)
	/ end of fix015
	rtt

/
/ quickcall
/
/	Allows faster entry to device interrupt routines.
/	No call to 'swtch' on return. No save of 'dev'.
/	Use with discretion for block devices.
/
quickcall:
	mov	r1,-(sp)
	jsr	pc,*(r0)+
	mov	(sp)+,r1
	mov	(sp)+,r0
	rti

/
/
/	PIRQ interrupt
/

pirqi:	mov	PIRQ,-(sp)	/ PIRQ interrupt dispatch
	movb	(sp),PS		/ set to active PIRQ priority
	bic	$!16,(sp)	/ prepare word dispatch
	add	$1f-2,(sp)
	mov	*(sp)+,pc	/ disptach on PIRQ priority

.data; 1: pirq1; pirq2; pirq3; pirq4; pirq5; pirq6; pirq7; .text

/
/	Save the user's floating point registers.
/	Use the maint. bit to indicate if done.
/

_savfp:

.if	.fp
	mov	_uufsav,r1
	bit	$20,(r1)
	beq	1f
	stfps	(r1)+
	setd			/ added by KFH 24/12/79
	movf	fr0,(r1)+
	movf	fr4,fr0
	movf	fr0,(r1)+
	movf	fr5,fr0
	movf	fr0,(r1)+
	movf	fr1,(r1)+
	movf	fr2,(r1)+
	movf	fr3,(r1)+
.endif

1:	rts	pc

/
/	Reload the user's floating point registers.
/

loadfp:

.if	.fp
	mov	_uufsav,r1
	bit	$20,(r1)	/ floating registers saved?
	bne	1f		/ no
	mov	(r1),r0		/ saved fps
	bic	$4000,(r1)	/ interrupt on floating undefined
	ldfps	(r1)+
	setd			/ added by KFH 24/12/79
	movf	(r1)+,fr0
	movf	(r1)+,fr1
	movf	fr1,fr4
	movf	(r1)+,fr1
	movf	fr1,fr5
	movf	(r1)+,fr1
	movf	(r1)+,fr2
	movf	(r1)+,fr3
	ldfps	r0		/ user's cc's
.endif

1:	rts	pc

/
/	Handle counts for user profiles
/

_incupc:
	mov	r2,-(sp)
	mov	6(sp),r2	/ base of prof with base, leng, off, scale
	mov	4(sp),r0	/ pc
	sub	4(r2),r0	/ offset
	clc
	ror	r0
	mul	6(r2),r0	/ scale
	ashc	$-14.,r0
	inc	r1
	bic	$1,r1
	cmp	r1,2(r2)	/ length
	bhis	1f
	add	(r2),r1		/ base
	mov	$2f,nofault
	mfpd	(r1)
	inc	(sp)
	mtpd	(r1)
	br	3f

2:	clr	6(r2)

3:	clr	nofault

1:	mov	(sp)+,r2
	rts	pc

/
/	Display the contents of the word whose address is
/	in the switch registers. If bit 0 is set, the word
/	refers to user space; otherwise, it refers to
/	kernal data space
/

_display:
.if	.display
	tst	diswflag		//// previously waiting ??
	bne	0f			//// -> yes.
	mov	$5,displw		//// slow up the display.
	br	2f
0:	clr	diswflag
	dec	displw
	jge	2f			//// -> display not to change 
	mov	$2,displw
	mov	dispat+0,r0
	mov	dispat+2,r1
	ashc	dishift,r0		//// form next dispat in sequence
	mov	r0,dispat+0
	mov	r1,dispat+2
	ashc	$8.,r0			//// extract the dispat for display
	bit	$077776,r0		//// need to start dishifting the other way ??
	bne	1f			//// -> no.
	neg	dishift
1:	mov	r0,*$52			//// store for later display
2:

.data
dispat:	17;0			//// starting pattern (only use middle 22 bits)
dishift:	1		//// either 1 or -1 (the dishift direction)
displw:		1		//// use to delay the display
diswflag:	0		//// set by _idle to indicate wait done
.text
.endif
.if	.swtchdsp
	mov	_lst_count,r0
	mov	r0,r1
	ash	$-3,r1
	adc	r1		/ round, not truncate
	sub	r1,r0
	add	_swi_count,r0
	mov	r0,_lst_count
	clr	_swi_count
	mov	$177777,r1
	ash	r0,r1
	com	r1
	mov	r1,*$70		/// save here for later display
.endif
	mov	PS,-(sp)
	mov	$30340,PS	/ previous mode is user
	mov	nofault,-(sp)	/save
	mov	$3f,nofault
1:	mov	CSW,r1
	bit	$1,r1
	beq	1f
	dec	r1
	mfpi	(r1)
	mov	(sp)+,r0
	br	4f

1:	mov	(r1),r0
4:	mov	r0,CSW
3:	mov	(sp)+,nofault	/restore
	mov	(sp)+,PS
	rts	pc

/
/	Character list get/put
/

.if	.newputc

.globl	_cblockm, _cblockl


/	c = getc( cp )		struct clist *cp;

_getc:
	mov	r2,-(sp)
	mov	4(sp),r2
	mov	PS,-(sp)
	spl	6
	mov	2(r2),r1	/ first ptr
	beq	5f		/ buffer empty
0:
	movb	(r1)+,r0
	bic	$!377,r0
	dec	(r2)+		/ update count
	beq	4f		/ return last block to free
	bit	_cblockm,r1
	beq	2f		/ return empty block to free
	mov	r1,(r2)
1:
	mov	(sp)+,PS
	mov	(sp)+,r2
	rts	pc

2:
	sub	_cblockl,r1
	mov	(r1),(r2)
	add	$2,(r2)		/ update first pointer
3:
	mov	_cfreelist,(r1)
	mov	r1,_cfreelist
	br	1b

4:
	clr	(r2)+
	clr	(r2)
	dec	r1
	bic	_cblockm,r1
	br	3b

5:
	mov	$-1,r0
	br	1b


/	putc( c , cp )		struct clist *cp;

_putc:
	mov	4(sp),r0
	mov	PS,-(sp)
	spl	6
	mov	4(r0),r1	/ last ptr
	beq	4f		/ buffer empty
	bit	_cblockm,r1
	beq	2f		/ block full
0:
	movb	4(sp),(r1)+
	mov	r1,4(r0)
	inc	(r0)		/ update count
	clr	r0
1:
	mov	(sp)+,PS
	rts	pc

2:
	sub	_cblockl,r1
	mov	_cfreelist,-(sp)
	beq	3f		/ freelist empty ( r0 != 0 )
	mov	*(sp),_cfreelist
	mov	(sp),(r1)
	mov	(sp)+,r1
	clr	(r1)+
	br	0b

3:
	tst	(sp)+
	br	1b

4:
	mov	_cfreelist,r1
	beq	1b		/ freelist empty ( r0 != 0 )
	mov	(r1),_cfreelist
	clr	(r1)+
	mov	r1,2(r0)	/ set first ptr
	br	0b

.endif

.if	.newputc - 1
_getc:	mov	2(sp),r1
	mov	PS,-(sp)
	mov	r2,-(sp)
	spl	tty_prio
	mov	2(r1),r2	/ first ptr
	beq	9f		/ empty
	movb	(r2)+,r0	/ character
	bic	$!377,r0
	mov	r2,2(r1)
	dec	(r1)+
	bne	1f
	clr	(r1)+
	clr	(r1)+		/ last ptr
	br	2f

1:	bit	$7,r2
	bne	3f
	mov	-10(r2),(r1)	/ next block
	add	$2,(r1)

2:	dec	r2
	bic	$7,r2
	mov	_cfreelist,(r2)
	mov	r2,_cfreelist
	inc	_cfreecount

3:	mov	(sp)+,r2
	mov	(sp)+,PS
	rts	pc

9:	clr	4(r1)
	mov	$-1,r0
	br	3b

_putc:	mov	2(sp),r0
	mov	4(sp),r1
	mov	PS,-(sp)
	mov	r2,-(sp)
	mov	r3,-(sp)
	spl	tty_prio
	mov	4(r1),r2	/ last ptr
	bne	1f
	mov	_cfreelist,r2
	beq	9f
	mov	(r2),_cfreelist
	dec	_cfreecount
	clr	(r2)+
	mov	r2,2(r1)
	br	2f

1:	bit	$7,r2
	bne	2f
	mov	_cfreelist,r3
	beq	9f
	mov	(r3),_cfreelist
	dec	_cfreecount
	mov	r3,-10(r2)
	mov	r3,r2
	clr	(r2)+

2:	movb	r0,(r2)+
	mov	r2,4(r1)
	inc	(r1)
	clr	r0
3:	mov	(sp)+,r3
	mov	(sp)+,r2
	mov	(sp)+,PS
	rts	pc

9:	mov	pc,r0
	br	3b
.endif

/
/	Backup a user's registers after a stack page
/	fault
/

_backup:
	mov	2(sp),r0
	movb	ssr+2,r1
	jsr	pc,1f
	movb	ssr+3,r1
	jsr	pc,1f
	movb	_regloc+7,r1
	asl	r1
	add	r0,r1
	mov	ssr+4,(r1)
	clr	r0
	rts	pc

1:	mov	r1,-(sp)
	asr	(sp)
	asr	(sp)
	asr	(sp)
	bic	$!7,r1
	movb	_regloc(r1),r1
	asl	r1
	add	r0,r1
	sub	(sp)+,(r1)
	rts	pc

/
/	Interspace communitcation routines
/

_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
	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
	rts	pc

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

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

giword:
	mov	$err,nofault
	mfpi	(r1)
	br	1f

gword:
	mov	$err,nofault
	mfpd	(r1)
1:	mov	(sp)+,r0
	br	2f


_suiword:
	mov	2(sp),r1
	mov	4(sp),r0
	jsr	pc,piword
	rts	pc
_suword:
	mov	2(sp),r1
	mov	4(sp),r0
	jsr	pc,pword
	rts	pc
piword:
	mov	$err,nofault
	mov	r0,-(sp)
	mtpi	(r1)
	br	1f

pword:
	mov	$err,nofault
	mov	r0,-(sp)
	mtpd	(r1)

1:	clr	r0
2:	clr	nofault
	rts	pc


EFAULT = 14.				/ fix037

err:	mov	$-1,r0
	movb	$EFAULT, *_uuerror	/ fix037
	tst	(sp)+
	br	2b

/ fix036
/ check the existence of a word in kernel D space
/	fkword(addr)
/ returns 1 for success, 0 for failure
_fkword:
	mov	nofault,-(sp)
	mov	$1f,nofault
	tst	*4(sp)
	mov	(sp)+,nofault
	mov	$1,r0
	rts	pc
1:
	mov	(sp)+,nofault
	clr	r0
	rts	pc
	

/
/	Block/word transfers to/from kernal/user/supervisor space
/
/
/	call from C is
/		copy[in/out](from, to, byte_count, segflag)
/	on entry previous mode must be user
/	from and to must be even addresses,
/	byte_count must also be even
/	segflag is:
/		0:	to/from user data
/		1:	to/form kernal data
/		2:	to/from user text
/		3:	to/from supervisor region



_copyin:
	jsr	pc,copsu
		br 4f		/ transfer from user data
		br 2f		/ transfer from kernal data
		br 1f		/ transfer from supervisor

1:	mfpi	(r0)+
	mov	(sp)+,(r1)+
	sob	r2,1b
	br	5f

2:	mov	(r0)+,(r1)+	/ transfer from krnal data
	sob	r2,2b		/ word count
	br	5f

4:	mfpd	(r0)+		/ transfer from user data
	mov	(sp)+,(r1)+
	sob	r2,4b
	br	5f

_copyout:
	jsr	pc,copsu
		br 4f		/ transfer to user data
		br 2b		/ transfer to system data
		br 3f		/ transfer to user text

3:	mov	(r0)+,-(sp)	/ transfer to supervisor i/d
	mtpi	(r1)+
	sob 	r2,3b
	br	5f

4:	mov	(r0)+,-(sp)
	mtpd	(r1)+		/ transfer to user data
	sob	r2,4b

5:	clr	r0		/ successful transfer
6:	mov	(sp)+,PS	/ common exit
	clr	nofault
	mov	(sp)+,r2	/ count register
	rts	pc		/ exit

copsu:	mov	(sp)+,r0	/ general set-up for copyxx
	mov	r2,-(sp)
	mov	PS,-(sp)
	mov	14(sp),-(sp)	/ get segflag
	cmp	(sp),$3		/ if its to supervisor mod
	bne	1f		/ then set previous mode
	bic	$20000,PS	/ to supervisor mode

1:	asl	(sp)		/ word displacment
	add	r0,(sp)		/return address
	mov	10(sp),r0	/ from
	mov	12(sp),r1	/ to
	mov	14(sp),r2	/ byte count
	asr	r2		/ to word count
	mov	$1f,nofault	/ error catcher
	rts	pc		/ to offset branch

1:	mov	$-1,r0		/ error catcher
	br	6b		/ exit with indicator




.if	.idle
/
/	Just idle while nothing is active to speed up transfers
/

_idle:
.if	.display
	inc	diswflag	/ indicate wait in progress
.endif
	wait
	rts	pc
.endif

/
/	Routines to do context switching
/

_savu:	mov	(sp)+,r1
	mov	(sp),r0
	mov	sp,(r0)+
	mov	r5,(r0)+
.if	.bufmap
	mov	KDSA5,(r0)+		/buffer address
.endif
	jmp	(r1)

_aretu:	mov	(sp)+,r1
	mov	(sp),r0
	spl	7		/ critical part where stack is switched
	br	1f

_retu:	mov	(sp)+,r1
	spl	7		/ critical region
	mov	(sp),KDSA6
	mov	$_u,r0
1:
	mov	(r0)+,sp
	mov	(r0)+,r5
.if	.bufmap
	mov	(r0)+,KDSA5
.endif
	spl	0
	jmp	(r1)

_bswtch:
.if	.bufmap
	/ converts a buffer header pointer
	/ to a memory block reference and sets KA5

baddr = 16		/ offset of b_addr in buf header struct

	mov	2(sp),r0
	mov	baddr(r0),r1
	mov	baddr+2(r0),r0
	ashc	$-6,r0
.if	.ubmapd
	add	_bufarea,r1
.endif
	mov	r1,KDSA5
.endif
	rts	pc


/
/	Routine to set priorities
/

_spl0:	spl	0
	rts	pc

_spl1:	spl	1
	rts	pc

_spl4:	spl	4
	rts	pc

_spl5:	spl	5
	rts	pc

_spl6:	spl	6
	rts	pc

_spl7:	spl	7
	rts	pc


/
/	Copy and clear user sements (64 bytes)
/	Called with previous mode = user mode
/

_copyseg:
.if	1-.newcopyseg
	mov	UISA0,-(sp)		/ appropriate bottom two user regs.
	mov	UISA1,-(sp)
	mov	UISD0,-(sp)
	mov	UISD1,-(sp)
	mov	12(sp),UISA0		/from segment
	mov	14(sp),UISA1		/ to segment
	mov	$6,UISD0
	mov	$6,UISD1
	mov	r2,-(sp)
	clr	r0
	mov	$8192.,r1
	mov	$32.,r2

1:	mfpi	(r0)+			/ get a word
	mtpi	(r1)+			/ put a word
	sob	r2,1b			/ loop 'till done

	mov	(sp)+,r2
	mov	(sp)+,UISD1
	mov	(sp)+,UISD0
	mov	(sp)+,UISA1
	mov	(sp)+,UISA0
	rts	pc
.endif
.if	.newcopyseg
parvec = 114
	mov	PS, -(sp)		/ save priority etc
	mov	r2, -(sp)
	clr	r0
	mov	$5*20000, r1
	mov	$8., r2			/ count for sobbing
	mov	*$parvec,-(sp)		/ in case of parody
	mov	$3f,*$parvec
	spl	7
	mov	10(sp), KDSA0		/ from addr
	mov	12(sp), KDSA5		/ to addr
1:
	mov	(r0)+, (r1)+
	mov	(r0)+, (r1)+
	mov	(r0)+, (r1)+
	mov	(r0)+, (r1)+
	sob	r2, 1b

	clr	KDSA0
.if	1-.bufmap
	mov	$5*200, KDSA5
.endif
	mov	(sp)+, *$parvec
	mov	(sp)+, r2
	mov	(sp)+, PS
	rts	pc
3:	/ new parity trap routine
	mov	2(sp),-(sp)		/ a convenient PS
	clr	KDSA0
.if	1-.bufmap
	mov	$5*200,KDSA5
.endif
	jsr	pc,*6(sp)		/ saved spot
	/ rti comes to here - note that the ps is not on the stack anymore
	mov	14(sp),KDSA0
	mov	16(sp),KDSA5
	rti
.endif

_clearseg:
.if 1-.newcopyseg
	mov	UISA0,-(sp)		/ get a user register
	mov	UISD0,-(sp)
	mov	6(sp),UISA0
	mov	$6,UISD0
	mov	$32.,r1
	clr	r0

1:	clr	-(sp)			/ clear 32. words
	mtpi	(r0)+
	sob	r1,1b
	
	mov	(sp)+,UISD0
	mov	(sp)+,UISA0
	rts	pc
.endif
.if	.newcopyseg
parvec = 114
	mov	$5*20000, r0
	mov	$32.,r1			/ count for sobbing
.if	1-.bufmap
	mov	PS, -(sp)		/ save priority etc
	mov	*$parvec,-(sp)		/ in case of parody
	mov	$3f,*$parvec
	spl	7
	mov	6(sp), KDSA5		/ to addr
.endif
.if	.bufmap
	mov	2(sp), KDSA5		/ to addr
.endif
1:
	mov	$0,(r0)+		/ A clr causes a DATIP cycle
					/ which can give unwanted parities
	sob	r1, 1b

.if	1-.bufmap
	mov	$5*200, KDSA5
	mov	(sp)+, *$parvec
	mov	(sp)+, PS
.endif
	rts	pc
.if	1-.bufmap
3:	/ new parity trap routine
	mov	2(sp),-(sp)		/ a convenient PS
	mov	$5*200,KDSA5
	jsr	pc,*6(sp)		/ saved spot
	/ rti comes to here - note that the ps is not on the stack anymore
	mov	12(sp),KDSA5
	rti
.endif
.endif



.if	.hpdisk
.globl	_hpecc

/
/	Error correction for hp disk
/

_hpecc:
	mov	r3,-(sp)	/ save some registers
	mov	r2,-(sp)
	mov	UISA0,-(sp)	/ and some segmentation registers
	mov	UISD0,-(sp)
	mov	PS,-(sp)	/ for previous mode set
	mov	HPPOS,r3	/ bit position of error burst
	dec	r3		/ adjust for zero offset
	clr	r2		/ into word and bit pair
	div	$16.,r2		/ r2 word, r3 bit offset
	mov	r2,-(sp)	/ save for later end check
	mov	r2,r1		/ convert to bytes
	asl	r1
	sub	$512.,r1	/ back up one sector
	sxt	r0		/ will be negative always
	add	HPBAE,r0	/ high order physical address
	add	HPBA,r1		/ low order physical address
	adc	r0		/ long arithmetic
	div	$64.,r0		/ into KT-11 pages
	bis	$30000,PS	/ previous is now user mode
	mov	$406,UISD0	/ short read/write page (128 bytes)
	mov	r0,UISA0	/ into this page
	mov	r1,r2		/ word offset in block
	mov	HPPAT,r1	/ get correction pattern
	clr	r0		/ double precision
	ashc	r3,r0		/ fix by bit offset
	mfpi	(r2)		/ get first word
	xor	r1,(sp)		/ fix low order
	mtpi	(r2)+		/ replace word
	cmp	(sp)+,$255	/ don't exceed block
	beq	1f		/ only one word correction
	mfpi	(r2)		/ fetch second word
	xor	r0,(sp)		/ high order correction
	mtpi	(r2)		/ and replace word
1:
	mov	(sp)+,PS	/ now do the mandatory restore
	mov	(sp)+,UISD0	/ sequence
	mov	(sp)+,UISA0
	mov	(sp)+,r2
	mov	(sp)+,r3
	mov	HPWC,r0		/ see if in mid-transfer
	beq	1f		/ no - return 0, we're done
	inc	HPCS1		/ complete transfer and return(!=0)
1:	
	rts	pc

HPCS1	=	176700		/ Disk registers used above
HPWC	=	176702
HPBA	=	176704
HPPOS	=	176744
HPPAT	=	176746
HPBAE	=	176750
.endif

/	General utility routines
/

_btoc:	mov	2(sp),r1
	clr	r0
	add	$63.,r1
	adc	r0
	ashc	$-6,r0
	mov	r1,r0
	rts	pc

_dpcmp:	mov	2(sp),r0
	mov	4(sp),r1
	sub	6(sp),r0
	sub	8(sp),r1
	sbc	r0
	bge	1f
	cmp	r0,$-1
	bne	2f
	cmp	r1,$-512.
	bhi	3f

2:	mov	$-512.,r0
	rts	pc

1:	bne	2f
	cmp	r1,$512.
	blo	3f

2:	mov	$512.,r1

3:	mov	r1,r0
	rts	pc


_ldiv:	clr	r0
	mov	2(sp),r1
	div	4(sp),r0
	rts	pc


_longdiv:
	mov	2(sp),r0
	mov	4(sp),r1
	div	6(sp),r0
	rts	pc

_lrem:	clr	r0
	mov	2(sp),r1
	div	4(sp),r0
	mov	r1,r0
	rts	pc

/	routine to return a address of string representing
/	system idea of the time
/	call	systime( &string )
/	string to contain after call 'hh:mm'


_systime:
.if	.systime
	jsr	r5,csv		/ save registers
	mov	4(r5),r4	/ address of string area
	add	$6,r4		/ address end of string
	clrb	-(r4)		/ null at end
	mov	_time,r0	/ get systems idea of time
	mov	_time+2,r1

	div	$28800.,r0	/ r0= no of 8 hr lots since start 1970
				/ r1= no of seconds into 8 hour lot
	mov	r0,r3
	clr	r2
	div	$3,r2		/ r2= no of days since start of 1970
				/ r3= no of 8 hours in day
	clr	r0
	div	$60.,r0		/ r0= no of minutes
	mov	r0,r1
	clr	r0
	div	$60.,r0		/ r0= no of hour into 8 hr grp
				/ r1= no of minutes
	jsr	pc,numbin	/ put in minutes
	movb	$':,-(r4)	/ separator

	mov	r3,r1
	mul	$8.,r1
	add	r0,r1		/ r1= no of hours
	jsr	pc,numbin	/ put in hours
	mov	r4,r0		/ pass back address of string
	jmp	cret		/ return
numbin:
	mov	r0,-(sp)
	clr	r0
	div	$10.,r0
	bis	$'0,r0
	bis	$'0,r1
	movb	r1,-(r4)
	movb	r0,-(r4)
	mov	(sp)+,r0
.endif
	rts	pc

_itol:	mov	4(sp),r1
	mov	2(sp),r0
	rts	pc

csv:	mov	r5,r0
	mov	sp,r5
	mov	r4,-(sp)
	mov	r3,-(sp)
	mov	r2,-(sp)
	jsr	pc,(r0)


cret:	mov	r5,r2
	mov	-(r2),r4
	mov	-(r2),r3
	mov	-(r2),r2
	mov	r5,sp
	mov	(sp)+,r5
	rts	pc

_u	= 140000
usize	= 16.
.if	.bufmap
_b	= 120000
bsize	= 8.
.endif

CSW	= 177570
PS	= 177776
SSR0	= 177572
SSR1	= 177574
SSR2	= 177576
SSR3	= 172516
KISA0	= 172340
KISA1	= 172342
KISA7	= 172356
KISD0	= 172300
KDSA0	= 172360
KDSA5	= 172372
KDSA6	= 172374
KDSA7	= 172376
KDSD0	= 172320
KDSD5	= 172332
KDSD6	= 172334
SISD0	= 172200
SISA0	= 172240
SISD7	= 172216
SISD6	= 172214
SISA6	= 172254
MTC	= 172522

UISA0	= 177640		/ user instruction address 0
UISA1	= 177642		/ user instruction address 1
UISD0	= 177600		/ user instruction descriptor 0
UISD1	= 177602		/ user instruction descriptor 1

PIRQ	= 177772		/ program interrupt request
PIRQ1	= 001000		/ request at priority 1
PIRQ2	= 002000		/ request at priority 2
PIRQ3	= 004000		/ request at priority 3
PIRQ4	= 010000		/ request at priority 4
PIRQ5	= 020000		/ request at priority 5
PIRQ6	= 040000		/ request at priority 6
PIRQ7	= 100000		/ request at priority 7

.if	.pdp70
MEMLOA	= 177740		/ low address of parity
MEMHIA	= 177742		/ hi  address of parity
MEMERR	= 177744		/ memory system error register
MEMCNTRL= 177746		/ memory control register
CPUERR	= 177766		/ cpu error register
.endif
SLR	= 177774		/ stack limit register

IO	= 177600


.data

_ka6:		KDSA6		/ pointer to u-page segment address register
_cputype:	 45.		/ pdp-11/45 or pdp-11/70
stk:		0		/ one word stack for segmentation set-up

.bss
nofault:	.=.+2	/ bus error/segmentation violation bypass
ssr:		.=.+6	/ saved backup registers
_cfreecount:	.=.+2	/ free character count

.text
	.globl	_halt
_halt:
	mov	2(sp),*$CSW
	halt
	rts	pc

.data

.if	.powerfail-1		/ powerfail not supported
	.globl	powfail		/ must be in data segment

powfail:				/ entry at priority level 7
	0				/ halt - nought else to do
	br	powfail			/ loop just in case 'continued'
.endif


.if	.profile
/ System Profiler - Greg Rose july 78.

.globl	_profstart,_pshift,_pmask,_pusertix,_pfreq,_pnbytes,_pspls
.bss
_profstart:	. = . + 2	/ start addr of profile area (64 byte blocks)
_pusertix:	. = . + 4	/ long number of ticks in user space
_pnbytes:	. = . + 2	/ number of bytes in the profile area
_pspls:		. = . + [4*8.]	/ number of ticks at each priority level
_pshift = 0			/ number of bits shift for addr
_pmask = [177777 \< [16.-_pshift]] | 3	/ bits to turn off after shifting
_pfreq = -6353.			/ number of half micros between ticks
				/ in fact PRIME, no relation to HZ

/ Note - initialisation is all done in once.c, since it allocates core for the
/ profile buffer, and it's easier there.

.text
.globl	profile
profile:
	mov	$_pfreq,*$160002	/ schedule next interrupt
	mov	2(sp),r0	/ get previous ps - < 0 => was user mode.
	bmi	1f		/ branch if was user
	bic	$!340,r0	/ clear all but priority
	ash	$-3,r0		/ r0 = pri * 4
	add	$1,_pspls+2(r0)
	adc	_pspls(r0)
	mov	(sp),r0		/ old pc
.if _pshift
	ash	$-_pshift,r0
.endif
	bic	$_pmask,r0
	mov	$014340,PS
	mfpd	(r0)		/ fetch first word - note reverse of a normal long
	inc	(sp)
	bne	2f
	mtpd	(r0)+
	mfpd	(r0)
	inc	(sp)
2:
	mtpd	(r0)
	rti
1:
	add	$1,_pusertix
	adc	_pusertix+2
	rti
.endif