|
|	 "$Header: locore.s,v 820.1 86/12/04 19:53:30 root Exp $"
|	 "%W% %Y% %Q% %G%"
|
|------------------------------------------------------------------------
|
|				Copyright  1984
|
|			VALID  LOGIC  SYSTEMS  INCORPORATED
|
|	This listing contains confidential proprietary information which
|	is not to be disclosed to unauthorized persons without written
|	consent of an officer of Valid Logic Systems Incorporated.
|
|	The copyright notice appearing above is included to provide
|	statutory protection in the event of unauthorized or
|	unintentional public disclosure.
|
|------------------------------------------------------------------------

#include "../machine/psl.h"
#include "../machine/pte.h"

#include "../h/errno.h"
#include "../s32/cpu.h"		/* Registers, etc */
#include "../s32/clock.h"
#include "../s32/trap.h"
#include "../DOT/sky.h"
#include "../s32dev/skyreg.h"

|-----------------------------------------------------------------------------
|  Machine code assist for Valid Unix {M68010, M68020}
|
|  start() is called from the PROM monitor with these assumptions:
|
|	-  Segment and page maps convert virtual addresses to their
|	   corresponding physical addresses (one-to-one mapping) except
|	   for multibus memory (starting at VA 0x100000) and multibus i/o
|	   (starting at VA 0x1F0000).
|	-  Context register set to zero.
|	-  Supervisor state set.
|-----------------------------------------------------------------------------

|  This must be the first location in the data segment
|  It will be modified by the boot program to contain the
|  number of bytes in the symbol table, which it will also
|  append to the end of the dsta segment (starting at
|  address _edata)

	.globl	symbytes,oldsyms, godebugger
	.data
symbytes:.ascii "SYMS"		| Must be location _etext+0x00
cSYMS:	.ascii "SYMS"
oldsyms:.long 0
godebugger:.long 0		| Must be location _etext+0x0C

	.asciz "@(#)locore.s	1.5   4/23/84" 
	.even

	.text

|  these must match constants in autoconf.h!

	.globl	kstkbot		| (int)&u + sizeof(struct user) + 64
	.globl	pageshift	| bits to shift from address to page
	.globl	cnt		| count of various things
u		= UPAGENUM*NBPG	| u page VA
	.globl u
#ifdef	M68020_REV_B
U_sMaps		= U_SMAPSNUM*NBPG	| U_sMaps @ top of u-page 
	.globl U_sMaps
#endif	M68020_REV_B

|
|   For the large virtual address spaces
|   we need a table of 'virtual segment maps'
|   to contain an LRU linear list of the real
|   smaps that have been allocated.
|
|   Also maintained therein are the allocated
|   but not currently instanciated smaps.
|   The smap freelist for the process is also
|   reflected in the U_sMaps table.
|
|   Hence we start the system call stack at the beginning
|   of U_sMaps, so that the first stack push happens
|   just underneath the table.
|
K_STKTOP	= U_sMaps		| Per-user kernel stack starts here

SUMASK		= 0x2000	| Supervisor mode bit
INTMASK		= 0x0700	| Interrupt bits in status register

|
|  These must match constants in machine/cpu.h!
|
	CERROR=CHIPTYPE_ERROR

#if	defined(M68000) || defined(M68010)
	C68000=CHIPTYPE_68000		| 'c' code uses CHIPTYPE_680nn
	C68010=CHIPTYPE_68010
#undef	V_STATUS			| Defined in s32/cpu.h for 'c'
	V_STATUS =STATUS0_HW_ADDR	| Same: {M68000, M68010, M68020}
#undef	V_STATUS0			| Defined in s32/cpu.h for 'c'
	V_STATUS0=STATUS0_HW_ADDR	| Access as byte
#endif	defined(M68000) || defined(M68010)


#if	defined(M68010) || defined(M68020)
#undef	V_STATUS1			| Defined in s32/cpu.h for 'c'
	V_STATUS1=STATUS1_HW_ADDR	| Access as 16-bit word: >> 8
#endif	defined(M68010) || defined(M68020)


#ifdef	M68020
	C68020=CHIPTYPE_68020
#endif	M68020

|
| Allocate space for the system page tables.
| Also define the globals which define the
| addresses of both the page tables (mname)
| and the areas mapped by them (vname).
|
| Because the assembler does not allow multiple
| statements per line we must have three different
| of the SYSMP macros.
|

#define vaddr(x)	[[[x] - Sysmap]*NPTEPG + [KVBASE*NBPG]]
#define SYSMP0(mname, vname, npte)         .globl mname
#define SYSMP1(mname, vname, npte)mname:  .zerol npte
#define SYSMP2(mname, vname, npte)vname = vaddr(mname)
#define SYSMP3(mname, vname, npte)         .globl vname
#define KVMAP0(mname, vname, npte)         .globl mname
#define KVMAP1(mname, vname, npte)mname:  .zerol npte
#define KVMAP2(mname, vname, npte)         .globl vname
#define KVMAP3(mname, vname, npte)vname:   .long 0

	.data
	.even

SYSMP0(Sysmap	,Sysbase	,SYSPTSIZE	)
SYSMP0(Forkmap	,forkutl	,UPAGES		)
SYSMP0(Xswapmap	,xswaputl	,UPAGES		)
SYSMP0(Xswap2map,xswap2utl	,UPAGES		)
SYSMP0(Swapmap	,swaputl	,UPAGES		)
SYSMP0(Pushmap	,pushutl	,UPAGES		)
SYSMP0(Vfmap	,vfutl		,UPAGES		)
SYSMP0(Cmap1	,caddr1		,1		)
SYSMP0(Cmap2	,caddr2		,1		)
SYSMP0(Pcopymap	,pcopyarea	,1		)
SYSMP0(mcrmap	,mcr		,1		)
SYSMP0(mmap	,vmmap		,1		)
SYSMP0(msgbufmap,msgbuf		,MSGBUFPTECNT	)
SYSMP0(camap	,cabase		,16*CLSIZE	)
SYSMP0(ecamap	,calimit	,0		)

SYSMP1(Sysmap	,Sysbase	,SYSPTSIZE	)
SYSMP1(Forkmap	,forkutl	,UPAGES		)
SYSMP1(Xswapmap	,xswaputl	,UPAGES		)
SYSMP1(Xswap2map,xswap2utl	,UPAGES		)
SYSMP1(Swapmap	,swaputl	,UPAGES		)
SYSMP1(Pushmap	,pushutl	,UPAGES		)
SYSMP1(Vfmap	,vfutl		,UPAGES		)
SYSMP1(Cmap1	,caddr1		,1		)
SYSMP1(Cmap2	,caddr2		,1		)
SYSMP1(Pcopymap	,pcopyarea	,1		)
SYSMP1(mcrmap	,mcr		,1		)
SYSMP1(mmap	,vmmap		,1		)
SYSMP1(msgbufmap,msgbuf		,MSGBUFPTECNT	)
SYSMP1(camap	,cabase		,16*CLSIZE	)
SYSMP1(ecamap	,calimit	,0		)

SYSMP2(Sysmap	,Sysbase	,SYSPTSIZE	)
SYSMP2(Forkmap	,forkutl	,UPAGES		)
SYSMP2(Xswapmap	,xswaputl	,UPAGES		)
SYSMP2(Xswap2map,xswap2utl	,UPAGES		)
SYSMP2(Swapmap	,swaputl	,UPAGES		)
SYSMP2(Pushmap	,pushutl	,UPAGES		)
SYSMP2(Vfmap	,vfutl		,UPAGES		)
SYSMP2(Cmap1	,caddr1		,1		)
SYSMP2(Cmap2	,caddr2		,1		)
SYSMP2(Pcopymap	,pcopyarea	,1		)
SYSMP2(mcrmap	,mcr		,1		)
SYSMP2(mmap	,vmmap		,1		)
SYSMP2(msgbufmap,msgbuf		,MSGBUFPTECNT	)
SYSMP2(camap	,cabase		,16*CLSIZE	)
SYSMP2(ecamap	,calimit	,0		)

SYSMP3(Sysmap	,Sysbase	,SYSPTSIZE	)
SYSMP3(Forkmap	,forkutl	,UPAGES		)
SYSMP3(Xswapmap	,xswaputl	,UPAGES		)
SYSMP3(Xswap2map,xswap2utl	,UPAGES		)
SYSMP3(Swapmap	,swaputl	,UPAGES		)
SYSMP3(Pushmap	,pushutl	,UPAGES		)
SYSMP3(Vfmap	,vfutl		,UPAGES		)
SYSMP3(Cmap1	,caddr1		,1		)
SYSMP3(Cmap2	,caddr2		,1		)
SYSMP3(Pcopymap	,pcopyarea	,1		)
SYSMP3(mcrmap	,mcr		,1		)
SYSMP3(mmap	,vmmap		,1		)
SYSMP3(msgbufmap,msgbuf		,MSGBUFPTECNT	)
SYSMP3(camap	,cabase		,16*CLSIZE	)
SYSMP3(ecamap	,calimit	,0		)

eSysmap:

KVMAP0(Usrptmap	,usrpt		,USRPTSIZE	)
KVMAP0(Mbmap	,mbUtl		,NMBCLUSTERS*CLSIZE)

KVMAP1(Usrptmap	,usrpt		,USRPTSIZE	)
KVMAP1(Mbmap	,mbUtl		,NMBCLUSTERS*CLSIZE)

KVMAP2(Usrptmap	,usrpt		,USRPTSIZE	)
KVMAP2(Mbmap	,mbUtl		,NMBCLUSTERS*CLSIZE)

KVMAP3(Usrptmap	,usrpt		,USRPTSIZE	)
KVMAP3(Mbmap	,mbUtl		,NMBCLUSTERS*CLSIZE)

|
| Syssize is set by the start code below.
| It is the number of page table entries
| in the system page table.
|
	.globl	Syssize

Syssize:
	.long	0

	.text
	.globl	start, _end, _edata, _etext, main, pagesize, startup, startup1

start:

#ifdef WHITE
	orb	#V_REDLED,V_STATUS	| Turn red led on to say "hi"
#endif WHITE

|
| The boot routine calls unix with two parameters, the "boot type" (autoboot
| or not)  and the boot routine input line (e.g. "rim(0,6)unix") 
|
| NOTE that we take 'boottype' and 'bootline'
| absolutely on faith at this juncture.
| We leave it to the higher layers to validate them.
|
	movl	sp@(4),boottype	| save the parameters
	movl	sp@(8),bootline 

#ifdef KERN_RESTART
|
| Copy the data segment up to 3/4 meg so that savekernel() can
| find and save it for later restarting of the kernel.
|
	movl	#_edata,d0
	subql	#_etext,d0	| size of data in bytes in d0
	subql	#1,d0
	lsrl	#2,d0		| long word count (rounded up) -1 in d0
	movl	#_etext,a0	| start of data (source) in a0
	movl	#0xC0000,a1	| 3/4 meg (destination) in a1
1$:
	movl	a0@+,a1@+	| loop mode copying data
	dbf	d0,1$
donesaving:

#endif KERN_RESTART

|
| This kludge maps pages C, D, and E to the
| physical pages with the same address.  We
| must do this since the boot code has changed
| their mapping and we need to store symbols
| there.
|
	CTXTLOWPAGEM=V_ACCPM|V_ACCLOW

	movb	#CTXTLOWPAGEM,CONTEXT_HW_ADDR	| Modify low page map
	movw	#0xC,V_PAGEMAP+0xC000	| Map page C
	movw	#0xD,V_PAGEMAP+0xD000	| Map page D
	movw	#0xE,V_PAGEMAP+0xE000	| Map page E
	movb	#0x00,CONTEXT_HW_ADDR	| Set context back to normal mode

	.data
	.globl 	symOnce
symOnce:.long	0		| 0 ==> Haven't done symbol table copy
	.text

	tstl	symOnce		| We only need do this once; allow for restart
	jne	nosyms		| Brn if already done once
|
|  copy the symbol table from _edata to address SYM_PA
|  symbytes contains the number of bytes in the symbol table
|
	movl	symbytes,d0	| the size of the symbol table
	cmpl	cSYMS,d0
	jne	2$
	clrl	symbytes	| tell debugger there are no symbols
	jra	nosyms
2$:
	clrl	oldsyms		| assume new format
	bclr	#31,d0
	jeq	3$		| new (4.1C) format
	addql	#1,oldsyms
3$:
	movl	d0,symbytes	| store back with bit 31 off

	movl	#_edata,a0
	movl	#SYM_PA,a1
	subql	#1,d0
	lsrl	#2,d0		| long word count (rounded up) -1 in d0
1$:
	movl	a0@+,a1@+	| loop mode copying symbols
	dbf	d0,1$
nosyms:

|
|  clear kernel bss (from _edata to _end)
|
	movl	#_end,d0
	subl	#_edata,d0	| byte count in d0
	movl	#_edata,a0	| address in a0
	subql	#1,d0
	lsrl	#2,d0		| long count (rounded up) -1 in d0
1$:
	clrl	a0@+		| loop mode clearing bss
	dbf	d0,1$

	addl	#1,symOnce	| Show that we did it once
|
|  put the kernel virtual address space size (in pages) into Syssize
|
	movl	#eSysmap,d0
	subl	#Sysmap,d0
	asrl	#2,d0		| This is a divide by sizeof(struct pte)
	movl	d0,Syssize	| Syssize = (eSysmap - Sysmap) / 4;

|
|  call processor specific startup code (in machdep.c)
|
	movw	#0x2700,sr	| no interrupts, please
	movl	#TMPSTACK,sp	| a temporary stack for startup() to use
	jsr	startup1

#if	defined(M68010) || defined(M68020)
|
| set the alternate function code registers to user data so that
| the moves instruction can be used in place of fubyte and family.
|
	movb	#1,d0		| movb	#FCODE_USERDATA,d0
	.word	0x4E7B, 0x0001	| movec	d0,dfc
	.word	0x4E7B, 0x0000	| movec	d0,sfc
#endif

|
|  set kernel stack and call main() (in main.c)
|
	movl	#K_STKTOP,d0	| set process #0 kernel stack
	movl	d0,sp
|||||||	movw	#PSL_SMODE,sr	| ok to interrupt now
	jsr	main		| call unix, init process will return
	clrw	sp@-		| rte format word = 0000
	movl	#USRTEXT,sp@-	| pc = starting VA of init code
	clrw	sp@-		| sr = zero (user mode, spl0)
	rte			| resume to init code

	.data
	.globl 	boottype,bootline
boottype:.long	0	| Ptr to string describige type of boot: eg., "a\0"
bootline:.long	0	| Ptr to string: ~~ "riom(0,6,9)vmunix\0"
	.text

|
| Do a dump.
| Called by auto-restart.
| may be called manually.
|
rpb  = 0x0F00		| This must be defined differently
erpb = 0x1000		| This must be defined differently

	.globl	rpb, erpb
	.globl	doadump, dumpsys

doadump:
	jra	doadump		| No dumps yet.
	tstl	rpb+RP_FLAG	| Already tried to dump?
	jne	can_treboot
	movl	sp,erpb		| Save the stack pointer
	movl	#erpb,sp	| Put the stack at the top of the rpb
	movw	#2700,sr
	jsr	dumpsys
can_treboot:
	jra	can_treboot	| No reboots yet.

|
|  Save all registers at the address supplied as
|  an argument.  Also store PS and the return PC.
|
	.globl	saveregs

saveregs:
	movl	a0,sp@-
	movl	sp@(8),a0	| get address to store registers in a0
	moveml	#0xFFFF,a0@	| store d0-d7, a1-a7 (and bad copy of a0)
	movl	sp@,a0@(32.)	| save correct copy of a0
	clrl	d0
	movw	sr,d0
	movl	d0,a0@(68.)	| store sr as a long
	movl	sp@(4),a0@(72.)	| store return address
	movl	sp@+,a0
	rts

|
|  Prototype interrupt/exception vector table entry.
|  Code in startup() makes each 68000 exception vector
|  points to one of these.
|

	.data

	.globl	proto

proto:
	jsr	fault		| call the fault handler
	.word	0		| filled with the exception number

	.text

|
|  Trap and fault entry, called thru interrupt/exception vector:
| 
| 	jsr	fault		| leaves ptr to following word on stack
| 	.word	n		| n will be fault number


	.globl	fault, trap
	.globl	userregs	| points to user's registers on the stack
|
|  The 'fault' STACK processing is microprocessor independent.
|  We are only preserving a0-a7, d0-d7, and the usp value.
|
fault:

#ifndef	M68020
	orb	#V_REDLED,V_STATUS	| M68000 & M68010 -- show a system call
#else
	orb	#V_REDLED,V_STATUS0	| M68020
#endif

| Grunge...for compatibility with the VAX style of stack accessing/stupidity,
| we re-align the front portion of the stack so that the array of longs
| in s32/reg.h may be used to get at the processor state's bits.
| NOTE that we are NOT pushing a word directly in front of the SSR.

	clrw	sp@-		| Make PC addressable via array of longs (reg.h)
| . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
|
| At this point the stack looks like...
|
|	sp+0:	0		From the 'clrw'
|	sp+2:	retAdd(h.o.)	From 'jsr fault'
|	sp+4:	retAdd(l.o.)	From 'jsr fault'
|
|	sp+6:	ssr		The balance is the exception info pushed by h/w
|	sp+8:	PC(h.o.)
|	sp+A:	PC(l.o.)
|	sp+C:	(4-bits of zero) + (4-bit effn) + (12-bit vector)
|	sp+E:			Remainder of the appropriate exception-frame.
| . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 

	moveml	#0xFFFF,sp@-	| save all registers:  a7-a0, d7-d0

	movl	usp,a0		| Save USR stack ptr in the stack
	movl	a0,sp@(60)	| ...rather than the SYSTEM's stack pointer

	movl	sp,userregs	| Pointer to saved registers

	movl	sp@(66),a0	| Return-ptr from the 'jsr fault':
	movw	a0@,d0		| ...to the fault # left by addrErr/busErr
	extl	d0
	movl	d0,sp@-		| ...argument to trap()
#if 0
#ifdef	M68881	/* Only if the kernel itself is going to use the FPU. */

	jsr	save68881FPU	| Uses no args and preserves stack and FPU regs

#endif	M68881	/* Only if the kernel itself is going to use the FPU. */
#endif 0
	jsr	trap		| 'C' handler for traps and faults
|
| This  is what is now on the stack:
|
| Low address:	sp+0:	 Return address, here
|		sp+4:	 Fault # (NOTE: trap() adds 0x1000 to this for USERmode)
|		sp+8:	 d0..d7
|		sp+0x18: a0..a7
|		sp+0x28: Address of dispatch table entry via 'jsr fault'
|		sp+0x2C: PS		(as a LONG quantity)
|		sp+0x30: PC at which fault originally happened
| High address:
|
	addql	#1,cnt+V_TRAP	| increment trap count
	addql	#4,sp		| Pop the 'fault #' argument pushed for trap()

	movl	sp@(60),a0	| restore usr stack ptr
	movl	a0,usp

	movl	sp@(66),a0	| Return ptr from the 'jsr fault'
	movw	a0@,d0		| ...to the fault # left by addrErr/busErr
	cmpw	#T_BUSERR,d0	| Was it a bus error?
	jeq	doneBerr	| yes, do not perform softclock checks

	cmpw	#T_ADDRERR,d0	| Was it an address error?
	jeq	doneAerr	| yes, do not perform softclock checks

	moveml	sp@+,#0x7FFF	| Restore all other regs:  a6-a0, d7-d0
				| ...don't screw up our (system) stack ptr!

	addl	#10,sp		| 2: De-align PS; +4: a7; +4: from 'jsr fault'
	bra	chksoftclk

doneAerr:
doneBerr:

#ifdef	M68020
|
| Cleanup our DEBUG audit trail.
| We also do this in machine/trap.c within the 'nofault' longjmp().
|
	movl	eReg32_1,eReg32_0	| Pop error ADDR from simulated stack
	movl	eReg32_2,eReg32_1	| ...
	movl	eReg32_3,eReg32_2	| ...
	clrl	eReg32_3		| ...

	movl	errTypeQueue,d0	| Pop addr/bus error TYPE from simulated stack
	lsrl	#NBBY,d0	| ...
	movl	d0,errTypeQueue	| ...
|
| Continue unwinding the nominal stack
|
#endif	M68020
	moveml	sp@+,#0x7FFF	| Restore all other regs:  a6-a0, d7-d0
				| ...don't screw up our (system) stack ptr!
	addl	#10,sp		| 2: De-align PS; +4: a7; +4: from 'jsr fault'

#if	defined(M68020) && defined(Erata0A45J)
|
| Deal with M68020 mask botch -- "Errata (0)A45J Corrigendum: 28Mar85"
| (Note that 'bset' and 'btst' deal ONLY with byte operands.)
|
	movl	d0,saveD0
	clrl	d0
	movb	sp@(6),d0	| Exception frame format #:  eeee????
	lsrl	#4,d0		| ... normalized (shifted right):  h.o. always 0

	movw	d0,effn		| DEBUGGING

	cmpb	#0xB,d0		| See if a LONG stack frame
	jne	1$		| Brn if NOT long frame -- no fixup needed

	btst	#0,sp@(0xA)	| Is DF set in SSW?
	jne	1$		| Brn if DataFault NOT set -- no fixup needed

	bset	#2,sp@(8+1)	| See if Pending ReRun (PRR) active (and SET it)
	jne	1$		| Brn if already set -- no fixup needed

	movl	a6,saveA6
|
| Perform the 0A45J RTE-fixup,
| which is NONE of the 1A45J fixups.
|
	movb	sp@(8),d0	| SIZ of the operand
	lsrl	#6,d0		| ...normalized

	movl	sp@(0x14),a6	| Get address for pending Data Cycle
	btst	#9,sp@(8)	| Bit #9%8==1: See if Read/Write (R/W) active
	jne	2$		| Brn if we should do a READ fixup
|
| A WRITE-fixup
|
	cmpb	#0x0,d0		| See if a LONG reference
	jne	4$		| Brn if not a long

	movl	sp@(0x28),a6@	| Write to Pending Data Cycle address
	jmp	3$

4$:
	cmpb	#0x2,d0		| See if a WORD reference
	jne	5$		| Brn if not a word

	movw	sp@(0x2a),a6@	| Write to Pending Data Cycle address
	jmp	3$

5$:

	cmpb	#0x1,d0		| See if a BYTE reference
	jne	6$		| Brn if not a byte

	movb	sp@(0x2b),a6@	| Write to Pending Data Cycle address
	jmp	3$

6$:
|
| BUG: 3-byte WRITE not handled
|
	movl	#A45JWriteBotchMsg,sp@-	| cdebugger("fault: A45JWriteBotch");
	jsr	cdebugger		| Possible flaming death upon return!
	jmp	3$

2$:
|
| A READ-fixup
|
	cmpb	#0x0,d0		| See if a LONG reference
	jne	7$		| Brn if not a long

	movl	a6@,sp@(0x2C)	| Read from Pending Data Cycle address
	jmp	3$

7$:
	cmpb	#0x2,d0		| See if a WORD reference
	jne	8$		| Brn if not a word

	clrw	sp@(0x2C)	| (BUG: needed?)
	movw	a6@,sp@(0x2E)	| Read from Pending Data Cycle address
	jmp	3$

8$:
	cmpb	#0x1,d0		| See if a BYTE reference
	jne	9$		| Brn if not a byte

	clrl	sp@(0x2C)	| (BUG: needed?)
	movb	a6@,sp@(0x2F)	| Read from Pending Data Cycle address

9$:
	jmp	3$

|
| BUG: 3-byte READ not handled
|
	movl	#A45JReadBotchMsg,sp@-	| cdebugger("fault: A45JReadBotch");
	jsr	cdebugger		| Possible flaming death upon return!

3$:
|
| Cleanup...
|
	movl	saveA6,a6
1$:
	movl	saveD0,d0
#endif	defined(M68020) && defined(Erata0A45J)

	rte



#if	defined(M68020) && defined(Erata0A45J)

	.data
A45JReadBotchMsg:
	.asciz	"fault: A45JReadBotch"

A45JWriteBotchMsg:
	.asciz	"fault: A45JWriteBotch"
	.even
	.text
#endif	defined(M68020) && defined(Erata0A45J)

|
| Trap #0 is a system call.  Handle this
| exception differently from other traps.
| Note that we did NOT come through a
| dispatch table entry.
|
	.globl	scall, syscall

scall:
#ifndef	M68020
	orb	#V_REDLED,V_STATUS	| M68000 & M68010 -- show a system call
#else
	orb	#V_REDLED,V_STATUS0	| M68020
#endif
	clrw	sp@-		| this makes ps long aligned
	clrl	sp@-		| extra junk word so offsets in reg.h work
	moveml	#0xFFFF,sp@-	| save all registers
	movl	usp,a0		| save usr stack ptr
	movl	a0,sp@(60)
	movl	sp,userregs	| pointer to saved registers
	jsr	syscall		| C handler for system calls
	addql	#1,cnt+V_SYSCALL | increment system call count

	movl	sp@(60),a0	| restore usr stack ptr
	movl	a0,usp
	moveml	sp@+,#0x7FFF	| Restore all other regs:  a6-a0, d7-d0
				| ...don't screw up our (system) stack ptr!
	addl	#10,sp		| pop other register, alignment word, and junk
	bra	chksoftclk
|
| getChipType():
|
| Causes an address error to occur so that we can discover on
| which processor we are running -- 68000/8, 68010 or 68020.
|
| The depth of the stack after an address error distinguishes the type
| of the microprocessor.  After cleaning up the intentional mess,
| we return the processor type to the caller in D0:
|
|		 0 ==>	68000/08;
|	      0x10 ==>	68010;
|	      0x20 ==>	68020;
|		-1 ==>	Don't know! Error.
|
| Addr-err vector:
		GVECT_ADDR=T_ADDRERR<<2

| Chip types:
		G68000=CHIPTYPE_68000 & 0xFF
		G68010=CHIPTYPE_68010 & 0xFF		| Be careful...
		G68020=CHIPTYPE_68020 & 0xFF
		GERROR=-1

		.globl	chipType, aeStackDepth
		.data
		.even
chipType:	.long	CHIPTYPE_68000	| Default microprocessor type
aeStackDepth:	.long	-1		| Address Error stack depth
		.text

	.globl	getChipType

getChipType:
	movl	GVECT_ADDR,a1	| Save the old 'address error' exception vector
	movl	#1$,GVECT_ADDR	| Use our (local) exception vector...
	movl	sp,a0		| Preserve the current stack ptr
|
| The 68000, 68008, and 68010 enforce even boundary data alignment.
| (The 68020 does not enforce any data alignment restrictions.)
|
	tstl	1		| Cause address error: access odd data address
1$:
	movl	a1,GVECT_ADDR	| Restore the old exception vector
	movl	sp,a1		| Get the new stack pointer for comparing
	movl	a0,sp		| Restore the stack pointer

	clrl	d0		| Assume	68000
	subl	a1,a0		| Find out by how much the stack grew...
	movl	a0,aeStackDepth	| DEBUG: Preserve the address-error stack depth
	movl	a0,d1
	cmpb	#14,d1		| Is it a	68000?
	jeq	2$		| Yes, return	68000

	movb	#G68010,d0	| No, pressume	68010
	cmpb	#58,d1		| Is it a	68010?
	jeq	2$		| Yes, return	68010

	movb	#G68020,d0	| No, try 	68020
	cmpb	#0,d1		| Is it a	68020?
	jeq	2$		| Yes, return	68020

	movl	#GERROR,d0	| No, fails all our tests: signify error!
2$:
	orl	d0,chipType	| Save the microprocessor type
	movl	chipType,d0	| Pass chipType back to caller
	rts

#ifdef	M68881
|
| getCoProcessorType  --  Determine which if any co-processor we have.
|
| Returns:  Coprocessor type in register d0.
|	    E.g., 0x68881.
|
| NOTE:	Registers d0, d1, a0, and a1 are used and NOT preserved.
|	Register a2 is preserved; others not mentioned, are untouched.
|
| F-1111 Exception Vector:
		GVECT_1111=T_1111<<2


		.globl	m68881, f1111StackDepth, fpuCtlRegs
		.globl	okToDo68881FPU
		.data
		.even
m68881:		.word	0		| Default coprocessor type
f1111StackDepth:.long	-1		| F-1111 Emulator Error stack depth
fpuCtlRegs:				| Savearea for FPU Control Registers
FPCR:		.long	-1		| FPU Control Register
FPSR:		.long	-1		| FPU Status Register
FPIAR:		.long	-1		| FPU Instruction Address Register
		.text

	.globl	getCoProcessorType

getCoProcessorType:
	clrl	d0		| Default for caller:  NO FPU chip, etc.
	tstw	okToDo68881FPU
	jeq	5$		| Brn to ignore the M68881 FPU

	clrw	m68881		| Assume no operational FPU coprocessor
	movl	GVECT_1111,a1	| Save old 'F-line Emulator' exception vector
	movl	#1$,GVECT_1111	| Use our (local) exception vector...
	movl	a2,sp@-		| Preserve a2
	movl	sp,a0		| Preserve the current stack ptr
|
| Attempt to use the coprocessor:
| Cause 'F-Line' error; or push the FPU's Control Register
| onto the stack.
|
	lea	fpuCtlRegs,a2		| Ptr to end of savearea for cntl regs

|	FMOVE	FPCR/FPSR/FPIAR,a2@+	| Save all of the FPU's Control Regs
	.word	0xf21a,0xbc00		| (ok)
|
| NOTE:	An FNOP has the side effect of putting the 68881 FPU
|	into the "IDLE" state, rather than the "NULL" state
|	that accompanies a hardware reset and/or power-on.
|
|	The "NULL" state requires only a TOTAL of 4 bytes -- no fpu data regs.
|
|	However, the "IDLE" state induced, e.g., by the execution of an FNOP,
|	requires:
|		 28 (0x1C) bytes for the fpu "IDLE" system-frame;
|		 12 (0x0C) bytes for the 3 fpu control registers:  CR, SP, IAR;
|		+96 (0x60) bytes for the 8 FPU data regs as well:  FP0-FP7;
|		----------------
|		136 (0x88) bytes TOTAL!
|
|	...a subtle, though expensive, difference.
|
#if 0
|	FNOP			| M68881 FPU do-nothing: Forces out exceptions
	.word	0xf280,0	| (ok)
#endif 0
|
| NOTE: Even if we get here via the T_1111 exception vector,
|	we ignore any 680?0 exception stack frame
|	by restoring the stack pointer.
|	This allows us to safely RTS back to our caller.
1$:
	movl	a1,GVECT_1111	| Restore the old Line-1111 Exception vector
	movl	sp,a1		| Get the new stack pointer for comparing
	movl	a0,sp		| Restore the stack pointer: should be unchanged

	subl	a1,a0			| Find out if the stack changed
	movl	a0,f1111StackDepth	| DEBUG: Preserve any F-1111 stack depth
	movl	a0,d1

	tstl	d1		| 0 ==> M68881 FPU operational.
	jne	2$		| Brn if FPU not present and ok

	movl	#0x68881,d0	| Say the MC68881 is present and functional
	movw	d0,m68881	| Set flag-value for FPU save/restore context
	jmp	3$		| Continue with normal processing
2$:
|
| NOTE:	There was NO MC68881, or the JUMPER @ H26 on the cpu board was absent.
|	Therefore we have latched up the bus error logic on the boardset.
|
|	Unless we allow subsequent errors to flow through, we will NOT, eg,
|	get bus errors for absent memory.  This will produce an erroneously
|	high value of 'physmem' to be computed in startup1(),
|	with subsequent dire results.
|
| Strobe the CLR.TIMEOUT.PND status bit to allow "pending" of timeouts.
| Any pending timeout will cause a busErr as soon as the errReg is cleared.
|
| NOTE that this bit is active LOW. It is cleared by reset, therefore
| all timeout bus errors are inhibited until is is set by software.
|
	movl	EREG32_HW_ADDR,d0	| Preserve the h/w error register
	andb	#BERR_MASK,d0		| (Virtual) "TIMEOUT.BERR" is SUM.BERR*
					| ...and none of the other l.o. bits
	jne	4$			| Brn if not "TIMEOUT.BERR"
|
| We only toggle CLR.TIMEOUT.PND if virtual "TIMEOUT.BERR" asserted...
|
	orw	#S1_CLR_TIMEOUT_PND,V_STATUS1		| Set
|
| Now arm for the NEXT (possibly extant)
| timeout bus error.
|
	andw	#NOT_S1_CLR_TIMEOUT_PND,V_STATUS1	| Clear/reset

4$:
	clrl	d0		| For caller:  NO FPU chip, etc.
3$:
	movl	sp@+,a2		| Restore a2
5$:
	rts			| Pass coProcessorType back to caller in reg d0

#endif	M68881

|
|  Bus and address exceptions are handled a little differently.
|  Because the 68000 pushes more stuff on the stack during these
|  exceptions (as opposed to interrupts, etc.) we must fix the stack
|  before calling fault().
|
|	busaddr() in machine/util.c saves the extra info
|  in the u page for future reference.
|
|	startup() in machine/startup.c points the 68000's exception vectors
|  directly at the appropriate busErr680nn() and addrErr680nn(),
|  where n=={00,10,20}.
|
|  For the 68010, our task is easier.  We simply record the necessary
|  information and go on to the fault routine.
|

	.globl	buserr, busaddr

buserr:

#ifdef	M68000
|-------------------------------------------------------------------------------
|
|		M68000 (Data) Bus Error exception stack:
|
|			-------------------------------------------------
|	sp+0(0):	|	fCode:	16-bit Func Code      |4|3|2|1|0|
|			-------------------------------------------------
|	sp+2(2):	|	aAddr:	Fault Address: H.O 16-bits 	|
|			-------------------------------------------------
|	sp+4(4):	|	  "	Fault Address: L.O 16-bits 	|
|			-------------------------------------------------
|	sp+6(6):	|	iReg: 16-bit Instruction Op Register	|
|			-------------------------------------------------
|	sp+8(0x8):	|	ssr(ps):16-bit 68000 Status Register	|
|			-------------------------------------------------
|	sp+10(0xA):	|	pc:	Program Counter: H.O. 16-bits	|
|			-------------------------------------------------
|	sp+12(0xC):	|	 "	Program Counter: L.O. 16-bits	|
|			-------------------------------------------------
|
|   Fine structure of some of the variables:
|   ========================================
|
|   fCode<15..0>:	Access type, etc.
|
|   	fCode<15..5>:	Unused -- probably zero;
|
|   	fCode<4>:	0 ==> Write cycle aborted;
|			1 ==> Read cycle aborted;
|
|   	fCode<3>:	0 ==> Instruction in progress;
|			1 ==> Exception processing;
|
|   	fCode<2..0>:	Function_Code<2..0>: {FC2, FC1, FC0}.
|
|-------------------------------------------------------------------------------

	.globl	busErr68000

busErr68000:
	movw	#0x2700,sr			| No interrupts, please
	movb	CONTEXT_HW_ADDR,ctxtReg+1	| Context Register
	movw	sp@(0),fCode	| Save Access-Type & Function Code
	movl	sp@(2),aAddr	| This is actually the fault address
	movw	sp@(6),iReg	| The instruction that failed
	movw	#T_BUSERR,trapType

	moveml	#0xC0C0,sp@-	| Save registers that C clobbers: a1,a0,d1,d0
	jsr	busaddr		| Put fCode, aAddr, & iReg in the u-page.

	moveml	sp@+,#0x0303	| Restore registers: d0,d1,a0,a1
	jsr	fault		| Pretend it was an ordinary fault
	.word	T_BUSERR	| 680nn exception id for "bus error"
				| ...we never return here.

#endif	M68000

#ifdef	M68010
|-------------------------------------------------------------------------------
|
|		M68010 (Data) Bus Error exception stack:
|
|			-------------------------------------------------
|	sp+0(0):	|	ssr(ps):16-bit 68010 Status Register	|
|			-------------------------------------------------
|	sp+2(2):	|	pc:	Program Counter: H.O. 16-bits	|
|			-------------------------------------------------
|	sp+4(4):	|	 "	Program Counter: L.O. 16-bits	|
|			-------------------------------------------------
|	sp+6(6):	| 4-bit FmtCode	|	12-bit Vector Offset	|
|			-------------------------------------------------
|	sp+8(0x8):	|	ssw:	16-bit Special Status Word	|
|			-------------------------------------------------
|	sp+10(0xA):	|	aAddr:	Fault Address: H.O 16-bits 	|
|			-------------------------------------------------
|	sp+12(0xC):	|	  "	Fault Address: L.O 16-bits 	|
|			-------------------------------------------------
|	sp+14(0xE):	|	        16 bits: UNUSED, RESERVED	|
|			-------------------------------------------------
|	sp+16(0x10):	|	doBuf:  16-bit Data Output Buffer	|
|			-------------------------------------------------
|	sp+18(0x12):	|	        16 bits: UNUSED, RESERVED	|
|			-------------------------------------------------
|	sp+20(0x14):	|	diBuf:  16-bit Data Input Buffer	|
|			-------------------------------------------------
|	sp+22(0x16):	|	        16 bits: UNUSED, RESERVED	|
|			-------------------------------------------------
|	sp+24(0x18):	|     <noName>: 16-bit Instruction Input Buffer	|
|			-------------------------------------------------
|			|						|
|	sp+26(0x1A):	|		Internal Information		|
|			|						|
|			-------------------------------------------------
|	sp+54(0x36):	|	iReg:   16-bit Instruction Op Register	|
|			-------------------------------------------------
|			|						|
|	sp+56(0x38):	|		Internal Information		|
|			|						|
|			-------------------------------------------------
|	sp+58(0x3A):
|	     
|
|
|-------------------------------------------------------------------------------

	.globl	busErr68010

busErr68010:
	movw	#0x2700,sr			| No interrupts, please
	movb	CONTEXT_HW_ADDR,ctxtReg+1	| Context Register
	movw	sp@(8),ssw	| save Special Status Word -- see page 5-12
	movl	sp@(10),aAddr	| this is actually the fault address
	movw	sp@(16),doBuf	| Data Output Buffer
	movw	sp@(20),diBuf	| Data  Input Buffer
	movw	sp@(54),iReg	| heuristically determined: 16-bit instruction
	movw	#T_BUSERR,trapType
	moveml	#0xC0C0,sp@-	| save registers that C clobbers: a1,a0,d1,d0
	jsr	busaddr		| put it in the u page
	moveml	sp@+,#0x0303	| restore registers: d0,d1,a0,a1
	jsr	fault		| pretend it was an ordinary fault
	.word	T_BUSERR	| 680nn exception id for "bus error"
				| ...we never return here.
#endif	M68010

#ifdef	M68020
|-------------------------------------------------------------------------------
|
|		M68020 (Data) Bus Error exception -- LONG stack frame:
|
|			-------------------------------------------------
|	sp+0(0):	|	ssr(ps):16-bit System Status Register	|
|			-------------------------------------------------
|	sp+2(2):	|	pc:	Program Counter: H.O. 16-bits	|
|			-------------------------------------------------
|	sp+4(4):	|	 "	Program Counter: L.O. 16-bits	|
|			-------------------------------------------------
|	sp+6(6):	| 4-bit effn	|	12-bit Vector Offset	|
|			|		|				|
|			-F.E.D.C.-B-.A.--9--.--8--.-7.-6.5.-4.-3.-2-.1.0.
|			| | | | |   | |     |     |     |       |   | | |
|	sp+8(8):	|*|*|*|*| * |*| R/W | RMC | SIZ |  FCn  |PRR|*|*|
|	A45J-ireg-->	| | | | |   | |     |     |     |       |   | | |
|			-------------------------------------------------
|	sp+10(0xA):	|	ssw:	16-bit Special Status Word	|
|			-------------------------------------------------
|	     ~		~						~
|	     ~		~						~
|			-------------------------------------------------
|	sp+16(0x10):	|	dcFaddr:DATA fault Address: H.O 16-bits	|
|			-------------------------------------------------
|	sp+18(0x12):	|	  "	DATA fault Address: L.O 16-bits	|
|===============================================================================
|	(This is the point where the LONG-frame differs from the SHORT-frame.)
|	(This is the LONG-frame.  C.f., addrErr68020 for the SHORT-frame.)
|===============================================================================
|			-------------------------------------------------
|	sp+20(0x14):	|	Pending Data Cycle Address: H.O 16-bits	|
|			-------------------------------------------------
|	sp+22(0x16):	|		"	"	  : L.O 16-bits	|
|			-------------------------------------------------
|	sp+24(0x18):	|	<2 words of internal registers>		|
|			-------------------------------------------------
|	sp+28(0x1C):	|	iReg:	16-bit Instruction Op Register	|
|			-------------------------------------------------
|	sp+30(0x1E):	|	<1 word of internal register>		|
|			-------------------------------------------------
|	sp+32(0x20):	|	aAddrB:	B-stage fault Addr: H.O 16-bits	|
|			-------------------------------------------------
|	sp+34(0x22):	|	  "	B-stage fault Addr: L.O 16-bits	|
|			-------------------------------------------------
|	sp+36(0x24):	|	<2 words of internal registers>		|
|			-------------------------------------------------
|	sp+40(0x28):	|	doBuf:	16-bit Data Output Buffer: H.O.	|
|			-------------------------------------------------
|	sp+42(0x2A):	|	  "	16-bit Data Output Buffer: L.O.	|
|			-------------------------------------------------
|	sp+44(0x2C):	|	diBuf:	16-bit Data  Input Buffer: H.O.	|
|			-------------------------------------------------
|	sp+46(0x2E):	|	  "	16-bit Data  Input Buffer: L.O.	|
|			-------------------------------------------------
|	     ~		~						~
|	     ~		~						~
|	     ~		~						~
|			-------------------------------------------------
|	sp+48(0x30):	|	<20 words of internal registers>	|
|			-------------------------------------------------
|=END===sp+96(0x56):=======================================================END==
|-------------------------------------------------------------------------------

BERR_MASK	=V_SUM_BERR_BAR | V_BAD_LADR_BERR | V_SMAP_BERR |V_PMAP_BERR

NOT_S1_CLR_TIMEOUT_PND	=~S1_CLR_TIMEOUT_PND


	.globl	busErr68020

busErr68020:
	movw	#0x2700,sr			| No interrupts, please
#ifdef	s32	/* EXCEPTION_BUT_NO_ERROR */
	movl	EREG32_HW_ADDR,lcwEReg		| Private copy of h/w error reg
#endif	s32	/* EXCEPTION_BUT_NO_ERROR */
	movw	sp@(0),ssr			| System Status Register (ps)
	movb	CONTEXT_HW_ADDR,ctxtReg+1	| Context Register

	movl	d0,saveD0

	movl	eReg32_2,eReg32_3	| Push THIS bus error on simulated stack
	movl	eReg32_1,eReg32_2
	movl	eReg32_0,eReg32_1

	movl	EREG32_HW_ADDR,d0	| Preserve the h/w error register
	movl	d0,eReg32_0		| ...and fend off additional errors
					| ...until we get well into trap()
|
| Firedoor for double bus errors, which would otherwise completely HALT
| the microprocessor -- "give us this day our daily (diagnostic information)..."
|
| Strobe the CLR.TIMEOUT.PND status bit to allow "pending" of timeouts.
| Any pending timeout will cause a busErr as soon as the errReg is cleared.
|
| NOTE that this bit is active LOW. It is cleared by reset, therefore
| all timeout bus errors are inhibited until is is set by software.
|
	andb	#BERR_MASK,d0	| (Virtual) "TIMEOUT.BERR" is SUM.BERR*
				| ...and none of the other l.o. bits
	jne	0$		| Brn if not "TIMEOUT.BERR"
|
| We only toggle CLR.TIMEOUT.PND if virtual "TIMEOUT.BERR" asserted...
|
	orw	#S1_CLR_TIMEOUT_PND,V_STATUS1		| Set
|
| Now arm for the NEXT (possibly extant)
| timeout bus error.
|
	andw	#NOT_S1_CLR_TIMEOUT_PND,V_STATUS1	| Clear/reset

0$:
#ifdef	s32	/* EXCEPTION_BUT_NO_ERROR */
	andb	#BERR_MASK,d0		| Look at all of the error bits
	cmpb	#V_SUM_BERR_BAR,d0	| (ERR_REG&BERR_MASK)==V_SUM_BERR_BAR
	jne	1$			| Brn if not "no error"

	addql	#1,lcwTOCnt		| Timeout counter
	tstw	lcwDebug		| 1==> do something about the occurrance
	jeq	1$			| Brn if no debugging

	jsr	asmdebugger		| TEMPORARY DEBUGGING ******************
1$:
#endif	s32	/* EXCEPTION_BUT_NO_ERROR */
	movl	errTypeQueue,d0	| Double bus error firewall
	asll	#NBBY,d0	| Byte-wide multiple bus/addr err firewall stack
	orb	#T_BUSERR,d0	| ...identified by error type
	movl	d0,errTypeQueue	| ...

	movw	sp@(0),ssr	| System Status Register (ps)
				| We delayed in case sp is foobar...
	clrl	d0
	movb	sp@(6),d0	| Save Exception Frame Format #
	lsrl	#4,d0		| ... normalized -- highbits always 0
	movw	d0,effn

	movw	sp@(8),a45jReg	| Save potential Corrigendum info
	movw	sp@(10),ssw	| Save Special Status Word

	movl	sp@(16),dcFaddr	| Data Cycle Fault Address
	movl	dcFaddr,aAddr	| ...1st guess @ access addr that faulted
	movw	sp@(28),iReg	| Determined from 1A45J errata corrigendum
|
| Now undertake the frame-dependent processing.
| We compute all of the possible fault addresses.
|
	cmpw	#0xA,effn	| Short bus cycle fault stack?
	jne	3$		| Brn if LONG-stack.
|
| SHORT stack frame
|
	movl	sp@(2),d0	| C-stage instruction fault
	addql	#2    ,d0
	movl	d0,aAddrC

	addql	#2    ,d0	| B-stage instruction fault
	movl	d0,aAddrB

	movl	sp@(24),doBuf	| DEBUG: Data Output Buffer
	clrl	diBuf		| DEBUG: Data  Input Buffer -- not present
	jmp	4$
|
| LONG stack frame
|
3$:	movl	sp@(32),d0	| B-stage instruction fault
	movl	d0,aAddrB

	subql	#2    ,d0	| C-stage instruction fault
	movl	d0,aAddrC

	movl	sp@(40),doBuf	| DEBUG: Data Output Buffer -- in LONG-fmt stack
	movl	sp@(44),diBuf	| DEBUG: Data  Input Buffer
|
| Set address of any fault into 'aAddr',
| the access-address of the fault.
| It depends upon which of:  a data or an instruction fault.
| Instruction fault can be B-stage and/or C-stage pipeline.
|
| Process data faults, C-stage, B-stage,
| in that order, for no particular reason.
|
4$:	btst	#8,ssw
	jne	5$		| Brn if DF asserted -- aAddr already OK

	btst	#15,ssw
	jeq	6$		| Brn if FC not asserted
|
| C-stage
|
	movl	aAddrC,aAddr	| (Fix C-stage 1st: rerun will re-catch others)
	jmp	5$

6$:	btst	#14,ssw
	jeq	7$		| Brn if FB not asserted
|
| B-stage
|
	movl	aAddrB,aAddr	| B-stage seems only thing broken
	jmp	5$
|
| Grieveous error -- panic!!
|
7$:	movl	#stageBotchMsg,sp@-
	jsr	cdebugger	| cdebugger("busErr68020: no faulted stage(s)");
	addql	#4,sp

5$:	movl	saveD0,d0
	movw	#T_BUSERR,trapType

|
| Preserve these valuse in the u-page
|
	moveml	#0xC0C0,sp@-	| Save registers that C clobbers: a1,a0,d1,d0
	jsr	busaddr		| Put it in the u page
	moveml	sp@+,#0x0303	| Restore registers: d0,d1,a0,a1

	jsr	fault		| Pretend it was an ordinary fault
	.word	T_BUSERR	| 680nn exception id for "bus error"
				| ...we never return here.

	.data
#ifdef	s32	/* EXCEPTION_BUT_NO_ERROR */
	.globl	lcwDebug, lcwEReg, lcwTOCnt
	.even
lcwDebug:.word	0		| Debugging: 1==>enable; 0==>disable
lcwEReg: .long	0		| Private copy of h/w error reg
lcwTOCnt:.long	0		| Private TimeOut counter
#endif	s32	/* EXCEPTION_BUT_NO_ERROR */
stageBotchMsg:
	.asciz	"panic: busErr68020: no faulted stage(s)"
	.even
	.text
	
#endif	M68020

	.globl	addrerr
addrerr:

#ifdef	M68000
|-------------------------------------------------------------------------------
|
|		M68010 (Instruction-stream) Address Error exception stack:
|
|			-------------------------------------------------
|	sp+0(0):	|	fCode:	16-bit Func Code      |4|3|2|1|0|
|			-------------------------------------------------
|	sp+2(2):	|	aAddr:	Fault Address: H.O 16-bits 	|
|			-------------------------------------------------
|	sp+4(4):	|	  "	Fault Address: L.O 16-bits 	|
|			-------------------------------------------------
|	sp+6(6):	|	iReg: 16-bit Instruction Op Register	|
|			-------------------------------------------------
|	sp+8(0x8):	|	ssr(ps):16-bit 68000 Status Register	|
|			-------------------------------------------------
|	sp+10(0xA):	|	pc:	Program Counter: H.O. 16-bits	|
|			-------------------------------------------------
|	sp+12(0xC):	|	 "	Program Counter: L.O. 16-bits	|
|			-------------------------------------------------
|
|   Fine structure of some of the variables:
|   ========================================
|
|   fCode<15..0>:	Access type, etc.
|
|   	fCode<15..5>:	Unused -- probably zero;
|
|   	fCode<4>:	0 ==> Write cycle aborted;
|			1 ==> Read cycle aborted;
|
|   	fCode<3>:	0 ==> Instruction in progress;
|			1 ==> Exception processing;
|
|   	fCode<2..0>:	Function_Code<2..0>: FC2, FC1, FC0;
|
|-------------------------------------------------------------------------------

	.globl	addrErr68000

addrErr68000:
	movw	#0x2700,sr			| No interrupts, please
	movb	CONTEXT_HW_ADDR,ctxtReg+1	| Context Register

	movw	sp@(0),fCode	| Save Access-Type & Function Code
	movl	sp@(2),aAddr	| This is actually the fault address
	movw	sp@(6),iReg	| The instruction that failed
	movw	sp@(8),ssr	| System Status Register (ps)
	movw	#T_ADDRERR,trapType

	moveml	#0xC0C0,sp@-	| Save registers that C clobbers: a1,a0,d1,d0
	jsr	busaddr		| Put it in the u page
	moveml	sp@+,#0x0303	| Restore registers: d0,d1,a0,a1

	jsr	fault		| Pretend it was an ordinary fault
	.word	T_ADDRERR	| 68010 exception id for addr error
				| ...we never return here.
#endif	M68000

#ifdef	M68010
|-------------------------------------------------------------------------------
|
|		M68010 (Instruction-stream) Address Error exception stack:
|
|			-------------------------------------------------
|	sp+0(0):	|	ssr(ps):16-bit 68010 Status Register	|
|			-------------------------------------------------
|	sp+2(2):	|	pc:	Program Counter: H.O. 16-bits	|
|			-------------------------------------------------
|	sp+4(4):	|	 "	Program Counter: L.O. 16-bits	|
|			-------------------------------------------------
|	sp+6(6):	| 4-bit FmtCode	|	12-bit Vector Offset	|
|			-------------------------------------------------
|	sp+8(0x8):	|	ssw:	16-bit Special Status Word	|
|			-------------------------------------------------
|	sp+10(0xA):	|	aAddr:	Fault Address: H.O 16-bits 	|
|			-------------------------------------------------
|	sp+12(0xC):	|	  "	Fault Address: L.O 16-bits 	|
|			-------------------------------------------------
|	sp+14(0xE):	|	        16 bits: UNUSED, RESERVED	|
|			-------------------------------------------------
|	sp+16(0x10):	|	doBuf:  16-bit Data Output Buffer	|
|			-------------------------------------------------
|	sp+18(0x12):	|	        16 bits: UNUSED, RESERVED	|
|			-------------------------------------------------
|	sp+20(0x14):	|	diBuf:  16-bit Data Input Buffer	|
|			-------------------------------------------------
|	sp+22(0x16):	|	        16 bits: UNUSED, RESERVED	|
|			-------------------------------------------------
|	sp+24(0x18):	|     <noName>: 16-bit Instruction Input Buffer	|
|			-------------------------------------------------
|			|						|
|	sp+26(0x1A):	|		Internal Information		|
|			|						|
|			-------------------------------------------------
|	sp+54(0x36):	|	iReg:   16-bit Instruction Op Register	|
|			-------------------------------------------------
|			|						|
|	sp+56(0x38):	|		Internal Information		|
|			|						|
|			-------------------------------------------------
|	sp+58(0x3A):
|	     
|
|
|-------------------------------------------------------------------------------

	.globl	addrErr68010

addrErr68010:
	movw	#0x2700,sr			| No interrupts, please
	movb	CONTEXT_HW_ADDR,ctxtReg+1	| Context Register

	movw	sp@(0),ssr	| System Status Register (ps)
	movw	sp@(8),ssw	| Save Special Status Word
	movl	sp@(10),aAddr	| This is actually the fault address
	movw	sp@(16),doBuf	| DEBUG: Data Output Buffer
	movw	sp@(20),diBuf	| DEBUG: Data  Input Buffer
	movw	sp@(54),iReg	| Heuristically determined location in stack
	movw	#T_ADDRERR,trapType

	orw	#0x8000,sp@(8)	| Lie: s/w reran the bus cycle (SSW: for RTE.)

	moveml	#0xC0C0,sp@-	| Save registers that C clobbers: a1,a0,d1,d0
	jsr	busaddr		| Put it in the u page
	moveml	sp@+,#0x0303	| Restore registers: d0,d1,a0,a1

	jsr	fault		| Pretend it was an ordinary fault
	.word	T_ADDRERR	| 68010 exception id for addr error
				| ...we never return here.
#endif	M68010

#ifdef	M68020
|-------------------------------------------------------------------------------
|
|	M68020 (Instruction-stream) Address Error exception SHORT -- stack frame
|
|			-------------------------------------------------
|	sp+0(0):	|	ssr(ps):16-bit System Status Register	|
|			-------------------------------------------------
|	sp+2(2):	|	pc:	Program Counter: H.O. 16-bits	|
|			-------------------------------------------------
|	sp+4(4):	|	 "	Program Counter: L.O. 16-bits	|
|			-------------------------------------------------
|	sp+6(6):	| 4-bit FmtCode	|	12-bit Vector Offset	|
|			|		|				|
|			-F.E.D.C.-B-.A.--9--.--8--.-7.-6.5.-4.-3.-2-.1.0.
|			| | | | |   | |     |     |     |       |   | | |
|	sp+8(8):	|*|*|*|*| * |*| R/W | RMC | SIZ |  FCn  |PRR|*|*|
|	A45J-ireg-->	| | | | |   | |     |     |     |       |   | | |
|			-------------------------------------------------
|	sp+10(0xA):	|	ssw:	16-bit Special Status Word	|
|			-------------------------------------------------
|	     ~		~						~
|	     ~		~						~
|			-------------------------------------------------
|	sp+16(0x10):	|    dcFaddr:DATA Cycle Fault Addr: H.O 16-bits |
|			-------------------------------------------------
|	sp+18(0x12):	|      "     DATA Cycle Fault Addr: L.O 16-bits |
|===============================================================================
|	(This is the point where the LONG-frame differs from the SHORT-frame.)
|	(This is the SHORT-frame.  C.f., busErr68020 for the LONG-frame.)
|===============================================================================
|	sp+20(0x14):	|		<internal register>		|
|			-------------------------------------------------
|	sp+22(0x16):	|		<internal register>		|
|			-------------------------------------------------
|	sp+24(0x18):	|	doBuf:	H.O. 16-bit Data Output Buffer	|
|			-------------------------------------------------
|	sp+26(0x1A):	|	  "	L.O. 16-bit Data Output Buffer	|
|			-------------------------------------------------
|	sp+28(0x1c):	|	iReg:	16-bit Instruction Op Register	|
|			-------------------------------------------------
|	sp+30(0x1E):	|		<internal register>		|
|			-------------------------------------------------
|=END===sp+32(0x20):=======================================================END==
|	     ~		~						~
|	     ~		~						~
|	     ~		~						~
|-------------------------------------------------------------------------------

	.globl	addrErr68020

addrErr68020:
	movw	#0x2700,sr			| No interrupts, please
	movb	CONTEXT_HW_ADDR,ctxtReg+1	| Context Register
	movw	sp@(0),ssr			| System Status Register (ps)

	movl	d0,saveD0

	movl	eReg32_2,eReg32_3	| Push THIS bus error on simulated stack
	movl	eReg32_1,eReg32_2
	movl	eReg32_0,eReg32_1

	movl	EREG32_HW_ADDR,d0	| Preserve the h/w error register
	movl	d0,eReg32_0		| ...and fend off additional errors
					| ...until we get well into trap()
|
| Firedoor for double bus errors, which would otherwise completely HALT
| the microprocessor -- "give us this day our daily (diagnostic information)..."
|
| Strobe the CLR.TIMEOUT.PND status bit to allow "pending" of timeouts.
| Any pending timeout will cause an error as soon as the errReg is cleared.
|
| NOTE that this bit is active LOW. It is cleared by reset, therefore
| all timeout bus errors are inhibited until is is set by software.
|

	andb	#BERR_MASK,d0	| (Virtual) "TIMEOUT.BERR" is SUM.BERR*
				| ...and none of the other l.o. bits
	jne	0$		| Brn if not "TIMEOUT.BERR"
|
| We only toggle CLR.TIMEOUT.PND if virtual "TIMEOUT.BERR" asserted...
|
	orw	#S1_CLR_TIMEOUT_PND,V_STATUS1		| Set
|
| Now arm for the NEXT (possibly extant)
| timeout bus error.
|
	andw	#NOT_S1_CLR_TIMEOUT_PND,V_STATUS1	| Clear/reset

0$:
	movl	errTypeQueue,d0	| Double bus error firewall
	asll	#NBBY,d0	| Byte-wide multiple bus/addr err firewall stack
	orb	#T_ADDRERR,d0	| ...identified by error type
	movl	d0,errTypeQueue	| ...

	clrl	d0
	movb	sp@(6),d0	| Save Exception FRame Format #
	lsrl	#4,d0		| ... normalized -- highbits always 0
	movw	d0,effn
	movl	saveD0,d0

	movw	sp@(8),a45jReg	| Save potential Corrigendum info
	movw	sp@(10),ssw	| Save Special Status Word
|
|  Check and repair the B-stage
|  of the instruction pipeline:
|
	btst	#4,ssw		| RB: Rerun Flag for Stage B of instruction pipe
	jeq	2$		| Brn if RB-flag NOT set: nothing to do.

	cmpw	#0xA,effn	| Short bus cycle fault stack?
	jne	1$		| Brn if LONG-fmt stack.

	movl	sp@(24),doBuf	| DEBUG: Data Output Buffer -- in SHRT-fmt stack
	clrl	diBuf		| DEBUG: Data  Input Buffer -- not present

	movl	sp@(2),aAddrB	| B-stage: Fault address in SHORT-stack
	addl	#4,aAddrB	| ... actually PC+4
	jmp	2$
1$:
	movl	sp@(40),doBuf	| DEBUG: Data Output Buffer -- in LONG-fmt stack
	movl	sp@(44),diBuf	| DEBUG: Data  Input Buffer

	movl	sp@(32),aAddrB	| B-stage: Fault address in long-stack
2$:
|
|  Now (also) check and repair the C-stage
|  of the instruction pipeline:
|
	btst	#5,ssw		| RC: Rerun Flag for Stage C of instruction pipe
	jeq	4$		| Brn if RC-flag NOT set: nothing to do.

	cmpw	#0xA,effn	| Short bus cycle fault stack?
	jne	3$		| Brn if NOT short-stack.

	movl	sp@(2),aAddrC	| C-stage: Fault address in short-stack
	addl	#2,aAddrC	| ... actually PC+2
	jmp	4$
3$:
	movl	sp@(32),aAddrC	| C-stage: Fault address in long-stack
	subl	#2,aAddrC	| ... actually B-stage - 2
4$:
	movw	sp@(54),iReg	| Heuristically determined -- jam

	orw	#0x3000,sp@(10)	| Lie: s/w did all rerun for both B & C stages.
				| (Actually we NEVER fixup an address fault
				| ...because we are ABENDing the process:
				| ...this is not a page fault.)
||5$:
	movw	#T_ADDRERR,trapType
	moveml	#0xC0C0,sp@-	| Save registers that C clobbers: a1,a0,d1,d0
	jsr	busaddr		| Put it in the u page
	moveml	sp@+,#0x0303	| Restore registers: d0,d1,a0,a1

	jsr	fault		| pretend it was an ordinary fault
	.word	T_ADDRERR	| 68000 exception id for addr error
				| ...we never return here.
#endif	M68020

|
|  The additional fields the 680nn pushes on the stack are saved here
|  for reference by busaddr() in s32/util.c
|
	.globl	aAddr, iReg, ctxtReg, trapType
	.data
	.even
aAddr:	.long	0		| Access Address
iReg:	.word	0		| Instruction Opcode Register
ctxtReg:.word	0		| Context Register
trapType:.word	0		| TBUSERR, T_ADDRERR, etc.


#ifdef	M68000
	.globl	fCode
fCode:	.word	0		| Function Code:  FC0, FC1, FC2
#endif	M68000


#if	defined(M68010) && !defined(M68020)
	.globl	diBuf, doBuf
diBuf:	.word	0		| Data  Input Buffer	-- 16 bits for 68010...
doBuf:	.word	0		| Data Output Buffer
#endif	defined(M68010) && !defined(M68020)


#if	defined(M68010) || defined(M68020)
	.globl	effn, ssr, ssw
effn:	.word	0		| Exception Frame Fmt #
ssr:	.word	0		| System  Status Reg
ssw:	.word	0		| Special Status Word
#endif	defined(M68010) || defined(M68020)


#ifdef	M68020
	.globl	dcFaddr						| uP bucket
	.globl	iRegB,	iRegC,	aAddrB,	aAddrC,	diBuf,	doBuf	| uP buckets
	.globl	eReg32,	a45jReg,saveA6,	saveD0,	errTypeQueue	| Workareas
	.globl	eReg32_0, eReg32_1, eReg32_2, eReg32_3,		| Err stack

dcFaddr:.long	0		| Data Cycle Fault Address

iRegB:	.word	0		| stage B Instruction pipe
iRegC:	.word	0		| stage C Instruction pipe

aAddrB:	.long	0		| B-stage instruction-stream Address error
aAddrC:	.long	0		| C-stage instruction-stream Address error

diBuf:	.long	0		| Data  Input Buffer	-- 32 bits for 68020...
doBuf:	.long	0		| Data Output Buffer

a45jReg:.word	0		| Savearea shared by addrErr68020 & busErr68020


errTypeQueue:.long 0		| Queue    shared by addrErr68020 & busErr68020

eReg32:				| Current h/w error reg as of addr/bus err entry
eReg32_0:.long	0		| Top of pushdown automata for error reg history
eReg32_1:.long	0		| 
eReg32_2:.long	0		| 
eReg32_3:.long	0		| Bottom of the pushdown

saveA6:	.long	0		| Savearea shared by addrErr68020 & busErr68020
saveD0:	.long	0		| Savearea shared by addrErr68020 & busErr68020

#endif	M68020
	.text

|
| Remove all bus error information from the
| stack so that the instruction can be restarted
| from the beginning.
|
| We are jsr'd here from trap().
|
|	cleanberr(&regs);
|
	.globl	cleanberr

cleanberr:

#ifdef	M68020
	cmpl	#C68020,chipType	| 68020?
	jeq	cleanBerr68020		| Brn if M68020 mpu
#endif
#ifdef	M68010
	cmpl	#C68010,chipType	| 68010?
	jeq	cleanBerr68010		| Brn if M68010 mpu
#endif


#ifdef	M68010
	.globl	cleanBerr68010

cleanBerr68010:
	movl	sp@(4),sp	| Parameter from caller: ptr to saved registers

	movl	sp@(60),a0	| restore usr stack ptr
	movl	a0,usp

	moveml	sp@+,#0x7FFF	| Restore all other regs:  a6-a0, d7-d0
				| ...don't screw up our (system) stack ptr!

	addl	#10,sp		| 2: De-align PS; +4: a7; +4: from 'jsr fault'
|
| Now we come to the 68010 dependent stuff:
|	sp now points at the current bus error exception stack frame.
|
| We have to replace the current RTE-frame with an RTS stack frame:
|
|	effn==9, always.
|	Hence, there are 29 16-bit words in this RTE frame: 
|		58 - (fmt#0 stack frame) = ...
|		58 - (sr + pc(hi) + pc(lo) + effn|vectorOffset) = ...
|		58 - 8 = 46
| 
	movl	sp@+,sp@(46)	| move SR, PC(hi) to new return frame
	movl	sp@+,sp@(46)	| move PC(lo), format to new return frame
	lea	sp@(42),sp	| remove bus error junk

	andw	#0x0FFF,sp@(6)	| convert to normal short exception format
				| ...effn <-- 0
	bra	chksoftclk

#endif	M68010


#ifdef	M68020
	.globl	cleanBerr68020

cleanBerr68020:
	tstl	godebugger
	jeq	0$		| Brn to avoid debugger
	jsr	asmdebugger	| TEMPORARY DEBUGGING **************************
0$:
	movl	sp@(4),sp	| Parameter from caller: ptr to saved registers

	movl	sp@(60),a0	| restore usr stack ptr
	movl	a0,usp

	moveml	sp@+,#0x7FFF	| Restore all other regs:  a6-a0, d7-d0
				| ...don't screw up our (system) stack ptr!

	addl	#10,sp		| 2: De-align PS; +4: a7; +4: from 'jsr fault'
|
| Now we come to the 68020 dependent stuff:
|	sp now points at the current bus error exception stack frame.
|
| We have to replace the current RTE-frame with an RTS stack frame,
| based upon the exception frame format #:
|	effn==N;
|	Hence, there are M 16-bit words in this RTE frame: 
|		2*M - (fmt#0 stack frame) = ...
|		2*M - (sr + pc(hi) + pc(lo) + effn|vectorOffset) = ...
|		2*M - 8 = K
| 
	movl	d0,saveD0	| Work-reg
	clrl	d0
	movb	sp@(6),d0	| Save Exception Frame Format #
	lsrl	#4,d0		| ... normalized -- highbits always 0
	movw	d0,effn		| ...DEBUGGING

				| MC68020UM(ADI), p6-22,23 is WRONG - says 44!!!
effn0xB:			| 46 (16-bit) words:  92-8 = 84
	cmpb	#0xB,d0		| "Long bus cycle"?
	jne	effn0xA		| Brn if NOT
	movb	#84,d0		| Index
	jmp	effnDoIt

effn0xA:			| 16 words:  32-8=20
	cmpb	#0xA,d0		| "Short bus cycle"?
	jne	effn0x9		| Brn if NOT
	movb	#20,d0		| Index
	jmp	effnDoIt

effn0x9:			| 10 words:  20-8 = 12
	cmpb	#0x9,d0		| "Coprocessor Mid-Instruction"?
	jne	effn0x2		| Brn if NOT
	movb	#12,d0		| Index
	jmp	effnDoIt
|
| We don't traverse this code if we have a 68010,
| so we don`t have to account for the effn==8 exception frame
| that is produced only by the 68010.  The 68000's bus/addr error
| exception is already accounted for, but notheless unused (by a 68000.)
|
effn0x2:			| 6 words:  12-8 = 4
	cmpb	#0x2,d0		| "Normal six word"?
	jne	effn0x1		| Brn if NOT
	movb	#4,d0		| Index
	jmp	effnDoIt

effn0x1:			| 4 words:  8-8 = 0
	cmpb	#0x1,d0		| "Throwaway"?
	jne	effn0x0		| Brn if NOT
	clrl	d0		| Index
	jmp	effnDoIt

effn0x0:			| 4 words:  8-8 = 0
	cmpb	#0x0,d0		| "Normal four word"?
	jne	effnBotch	| Brn if NOT
	clrl	d0		| Index
	jmp	effnDoIt

effnBotch:				| ? words:  ?-8 = ?
	movl	#effnBotchMsg,sp@-	| cdebugger("panic: effnBotch");
	jsr	cdebugger		| Possible flaming death upon return!
	addql	#4,sp
	jmp	effnDoIt

	.data
effnBotchMsg:
	.asciz	"panic: effnBotch"
	.even
	.text
	
	.globl	effnDoIt
effnDoIt:
	movl	sp@(0),sp@(0,d0:w)	| Move sr, pc(hi)       to new RTS frame
	movl	sp@(4),sp@(4,d0:w)	| Move     pc(lo), effn to new RTS frame

	lea	       sp@(0,d0:w),sp	| Point @ our new frame:  discard junk

	andw	#0x0FFF,sp@(6)		| effn=0: Convert to normal short frame
					| ...effn <-- 0
|
| Cleanup our DEBUG audit trail.
| We do this in machine/locore.s at the backend of the 'fault' code.
| We also do this in machine/trap.c within the 'nofault' longjmp().
|
	movl	eReg32_1,eReg32_0	| Pop error ADDR from simulated stack
	movl	eReg32_2,eReg32_1	| ...
	movl	eReg32_3,eReg32_2	| ...
	clrl	eReg32_3		| ...

	movl	errTypeQueue,d0	| Pop addr/bus error TYPE from simulated stack
	lsrl	#NBBY,d0	| ...
	movl	d0,errTypeQueue	| ...
|
| Continue unwinding the nominal stack
|
	movl	saveD0,d0
	bra	chksoftclk

#endif	M68020

|
| Resume saves the current process' context
| in the u.u_pcb.pcb area and restores the
| context for the process whose u page is
| specified by the argument.
|
| Called:
|	resume(paddr)
|    or
|	resumesr(paddr, oldsr)
|
| where paddr is a pointer to the u page pte's for
| the new u page.
|
| resumesr is just like resume except that its first
| argument is the status register to save away with
| the process.  resume uses the current value of the
| SR instead.
|
	.globl	suregp0br, suregp0lr, suregp1br, suregp1lr
	.globl	sureg, setpagemap, panic
	.globl	resume, resumesr
#if NSKY > 0
	.globl skysave,skyrestor
SKYBOARD=SKYVIRTADDR
#endif NSKY > 0

resumesr:
	movl	sp@(8),d0	| get SR saved by swtch
	jra	resumex
resume:
	movw	sr,d0		| get SR to be saved
resumex:
	subql	#2,sp		|   and adjust the stack pointer accordingly
	movl	sp@(2),sp@	| move the PC to make room for the format word
	clrw	sp@(4)		| rte stack format type = 0000
	movw	d0,sp@-		| make it look like an exception stack
	clrl	userregs	| indicate that the userregs is invalid
	movl	#u,a0		| place to store things (u.u_pcb.pcb_regs)
	moveml	#0xFCFC,a0@	| save d2 - d7, a2 - a7
	movl	sp@(8),a2	| pointer to u page pte's in a2
	movl a0,a5
	clrl	d1
	movw	sp@,d1
	movl	d1,a5@(PCB_SR)	| save caller's SR for debugging
	movl	sp@(2),a1
	movl	a1,a5@(PCB_PC)	| save return PC for debugging
#if NSKY > 0
	tstw a5@(U_FPPC)
	jeq savnofp
	pea a5@(U_FPPC)
	pea a5@(U_FPSAV)
	pea SKYBOARD
	jsr skysave
	lea sp@(12),sp
savnofp:
#endif NSKY > 0

#ifdef	M68881
	.globl	save68881FPU, no68881ToSave
|
| If we have a 68881 Floating Point Coprocessor,
| then preserve its state in the u-page for the current context.
|
| NOTE:	Register a3 is used and NOT preserved.
|	Register a5 is presumed to point at the origin of the u-page,
|	thanks to the preceeding code.
|
| NOTE: We cannot use the current a7-stack for long term storage
| 	of the FPU state because this stack is a global physical resource.
|	I.e., the stack-space will be reused, thereby destroying
|	that which we would preserve.
|
| NOTE:	The successive conjuctions of m68881!=0, U_FPIAR!=0 and !nullFrame
|	enable preservation of the programmer's model of the 68881 FPU.
|
|	m68881	0 ==> No FPU present on the cpu board;
|	U_FPIAR	0 ==> No FPU usage for the corresponding process;
|	U_FPSSF	0 ==> NULL system state frame for the FPU ==> no pgmmr's model;
|
save68881FPU:
	tstw	okToDo68881FPU
	jeq	5$			| Brn to ignore the M68881 FPU

	tstw	m68881
	jeq	no68881ToSave		| Brn if no 68881 co-processor

	movl	a3,sp@-			| Preserve a3
	lea	a5@(U_FPSSF),a3		| MC68881 System State Frame to u-page
|
| NOTE:	The data comprising the system-frame for the fpu
|	is always left-adjusted in the savearea:
|	The frame-format 16-bit word is at location a3@.
|
|	FSAVE	a3@			| NOTE: Sys frame varies: 4 - 0xB8 bytes
	.word	0xf313			| (ok)	C.f., s32/fpu68881.h

	movl	a3,a5@(U_FPSSFP)	| Save ptr to start of fpu's sys frame
|
| NOTE:	We overload the semantics of U_FPIAR with the additional meaning
|	that if U_FPIAR==0, then there was a "NULL" fpu system-frame
|	at "save-time",	(and we wouldn't be restoring the FPIAR anyway.)
|
|	If the fpu system-frame was "non-NULL", then we additionally
|	preserve the FPIAR, thus rendering the latter also non-NULL.
|
| NOTE:	The only hole in this logic would be if the user's application
|	somehow loads the FPIAR with zero.  Of course this in itself
|	constitutes an error since no user (or kernel) code exists
|	at zero to be run.  (Actually the long-word at zero contains
|	the the hardware reset jump-vector address.)
|	At worst, we would have some confusion about the details
|	of a user-instigated problem.
|
| BUG:	Perhaps the FPU could get out of sync for subsequent useage.
|
	clrl	a5@(U_FPIAR)		| PRESUME nothing to do:  FPU's PC=0
	tstb	a3@			| Check for a NULL frame
	jeq	4$			| Brn if no progmmr's-model to preserve

|
| NOTE: According to Motorola, the 80-bit/10-byte floating point
|	data registers each take up <<<12-bytes>>> of primary storage.
|	This is probably done to maintain long-alignment of the registers.
|	The two-bytes of padding is located between the mantissa and
|	the (fractional part of) the floating point number.
|
	lea	a5@(U_FPDR),a3		| Save the 8 FPU Data Regs in u-page

|	FMOVEM	FP0-FP7,a3@		| Only store in descending addr order
	.word	0xf213,0xF0ff		| (OK)

|
| Finally, preserve the three 'control' registers,
| also in the current u-page.
| NOTE:	The control registers are stored in the order:
|	FPCR, FPSR, FPIAR.
|
	lea	a5@(U_FPCR),a3		| Save all three FPU cntl regs in u-page

|	FMOVEM	FPCR/FPSR/FPIAR,a3@
	.word	0xf213,0xbc00		| (OK)
4$:
	movl	sp@+,a3		| Restore a3
5$:

no68881ToSave:	

#endif	M68881

	movw	#0x2700,sr	| no interrupts, please
	movl	Cmap2,a5@(PCB_CMAP2) | have to save this in case we
				|     need to resume to a copyseg() which
				|     page faulted
|
| Save pseudo-registers which simulate the
| Vax registers.
|
	movl	suregp0br,a5@(PCB_P0BR)
	movl	suregp1br,a5@(PCB_P1BR)
	movl	suregp0lr,a5@(PCB_P0LR)
	movl	suregp1lr,a5@(PCB_P1LR)
|
| Get a temporary stack so we can call
| setpagemap to map in the new u page.
|
	movl	#TMPSTACK,sp	| setup temporary stack for setpagemap() call
	movl	#UPAGENUM,d3	| first virtual page of u area in d3
	movw	#UPAGES-1,d4	| loop count for dbf below
umaploop:
	movl	a2@+,d2		| get next u pte in d2
	andl	#0xFFF,d2	|   and strip all but the page frame number
#ifdef WHITE
	orl	#0x2000,d2	| make sure that V_PRESENT bit is set in entry
#endif WHITE
	movl	d2,sp@-		| push physical page number
	movl	d3,sp@-		| push virtual page number
	jsr	setpagemap	| setpagemap(btopg(&u)+i, paddr[i].pg_pfnum)
	addql	#8,sp		| pop arguments
	addql	#1,d3		| increment virtual page
	dbf	d4,umaploop	| loop until last page of u area mapped
|
| Load pseudo-registers which simulate the
| Vax registers.
|
	movl	a5@(PCB_P0BR),suregp0br
	movl	a5@(PCB_P1BR),suregp1br
	movl	a5@(PCB_P0LR),suregp0lr
	movl	a5@(PCB_P1LR),suregp1lr
	.globl	resume9
resume9:
	jsr	sureg		| copy the user's page table entries
				|    into the hardware
|
| Restore the mapping for caddr2 (Cmap2)
| in case we are resuming to copyseg() which
| page faulted.
|
	movl	a5@(PCB_CMAP2),Cmap2
	beq	cmapnotvalid
#ifdef WHITE
	movl	Cmap2,d0	| physical page number of caddr2
	orl	#0x2000,d0	| make sure that the V_PRESENT bit is set
	movl	d0,sp@-
#else WHITE
	movl	Cmap2,sp@-	| physical page number of caddr2
#endif WHITE
	movl	#caddr2,d0
	movl	pageshift,d1
	asrl	d1,d0		| virtual page number of caddr2
	movl	d0,sp@-
	jsr	setpagemap	| setpagemap(btopg(&caddr2), Cmap2)
cmapnotvalid:

	movl	#u,a0		| address to restore registers from
#if NSKY > 0
	tstw a0@(U_FPPC)
	jeq resnofp
	pea a0@(U_FPPC)
	pea a0@(U_FPSAV)
	pea SKYBOARD
	jsr skyrestor
	lea sp@(12),sp
	movl #u,a0
resnofp:
#endif NSKY > 0

#ifdef	M68881
	.text
	.globl	restore68881FPU, no68881ToRestore
|
| If we have a 68881, then preserve its state.
|
| NOTE: We restore the system-frame even if the FPU's PC, U_FPIAR, is 0.
|	Of course we also restore the system-frame if the frame format word
|	indicate a non-"NULL" frame.
|
|	We restore any altered 68020 registers.
|
restore68881FPU:
	tstw	okToDo68881FPU
	jeq	5$			| Brn to ignore the M68881 FPU

	tstw	m68881
	jeq	no68881ToRestore	| Brn if no 68881 co-processor

	tstb	a5@(U_FPSSF)		| Check for "NULL" FPU Sys-Status-Frame
	jeq	4$			| Brn if no pgmmr's-model to restore

	movl	a3,sp@-			| Preserve a3
	lea	a5@(U_FPCR),a3		| Restore all FPU cntl regs from u-page

|	FMOVEM	FPCR/FPSR/FPIAR,a3@+
 	.word	0xf21b,0x9c00		| (OK)

	lea	a5@(U_FPDR),a3		| Restore all FPU Data Regs from u-page

|	FMOVEM	FP7-FP0,a3@+		| Restore the FPU data registers
	.word	0xf21b,0xd0ff		| (ok)

	movl	a5@(U_FPSSFP),a3	| Start of fpu's sys frame in U_FPSSF

4$:
|	FRESTOR	a3@+			| NOTE: Sys frame varies: 4 - 0xB8 bytes
	.word	0xf35b			| (OK)	C.f., s32/fpu68881.h

	movl	sp@+,a3			| Restore a3
5$:

no68881ToRestore:	

#endif	M68881

#ifdef	M68020
|
| Flush the OnChipCache iff same is enabled.
| Different contexts share the same user address space!
|
| There is only a remote possibility that cache remnants
| from a prior context would have survived this long
| in the 64-word OnChipCache.  Hopefully we are not
| squandering cpu resources in this effort.
|
	.globl	cowClearCACR

cowClearCACR:
	cmpl	#C68020,chipType	| 68020?
	jne	0$			| Brn if NOT M68020 mpu

	movw	V_STATUS1,d0		| Should we flush OnChip cache?
	andw	#S1_INT_CACHE_EN,d0	| ...(we use the machine/cpu.h mnemonic)
	jne	0$			| Brn if OnChipCache disabled

	movl	#0,d0		| Disable cache
	.word	0x4e7a,0x0002	| movec	d0,cacr

	movl	#8,d0		| Clear cache
	.word	0x4e7a,0x0002	| movec	d0,cacr

	movb	#1,d0		| Enable cache
	.word	0x4e7a,0x0002	| movec	d0,cacr
0$:
#endif	M68020
	moveml	a0@,#0xFCFC	| restore d2 - d7, a2 - a7
|
|  firewall: check for an invalid kernel stack
|
|  SHOULD REALLY IMPLEMENT A KERNEL STACK REDZONE
|
	movl	sp,d1
	cmpl	#K_STKTOP,d1	| kernel stack underflow?
	jgt	badstack
	movl	kstkbot,d0
	cmpl	d0,d1		| kernel stack overflow?
	jlt	badstack
	btst	#0,d1		| kernel stack pointer even?
	jne	badstack
|
| If u.u_pcb.pcb_sswap is non-zero then do a longjmp
| with u.u_pcb.pcb_sswap as the address of the save area.
| Do this by setting up the argument on the stack (which
| would otherwise have been set up to return to resume)
| and clobber the return pc to be longjmp and the stacked
| SR to be at priority zero.
|
	tstl	a0@(PCB_SSWAP)	| longjmp?
	beq	res1		| no, just rte back to where we left off
	movl	a0@(PCB_SSWAP),sp@(4) | argument to longjmp was in pcb.pcb_sswap
	clrl	a0@(PCB_SSWAP)
	clrw	sp@-		| rte format word = 0000
	pea	longjmp		| make rte return to longjmp
	movw	#0x2000,sp@-	| at priority zero
res1:
	rte			| return to caller

	.globl setjmp,longjmp
setjmp:
	movl sp@(4),a0		| address of save area
	movl sp@+,a1		| pop return address
	moveml #0xfcfc,a0@	| save d2-d7, a2-a7
	movl a1,a0@(PCB_PC)	| save pc
	moveq #0,d0		| return value
	jmp a1@			| return
longjmp:
	movl sp@(4),a0		| address of save area
	moveml a0@,#0xfcfc	| restore the registers
	movl a0@(PCB_PC),a1	| where to resume to
	moveq #1,d0		| return non-zero
	jmp a1@
	
badstack:
	movl	#TMPSTACK,sp
	movl	#badmsg,sp@-
	jsr	panic

	.data
badmsg:	.asciz	"longjmp: bad upage/stack"
	.text


#ifdef WHITE
	.data
	.even
	.globl	viafail
viafail: .long 0
	.text
#endif WHITE

|
| No processes to run.  Turn off the green LED
| on the processor board to indicate idle
| and stop the processor at priority 0.
|
	.globl	idle, idlestop, runq
idle:
	movw	sr,d0
#ifndef	M68020
	andb	#0xFF-V_GREENLED,V_STATUS	| M68000 & M68010 -- turn off
#else
	andb	#0xFF-V_GREENLED,V_STATUS0	| M68020 -- turn off green LED
#endif
idleloop:
	stop	#0x2000
idlestop:
	tstl	runq		| Is anyone runable?
	jeq	idleloop	| No, don't bother returning to swtch()

#ifndef	M68020
	orb	#V_GREENLED,V_STATUS	| M68000 & M68010 -- turn on green LED
#else
	orb	#V_GREENLED,V_STATUS0	| M68020 -- turn on green LED
#endif
	movw	d0,sr
	rts

|  clock interrupt handled here so we can pass along the pc and sr

	.globl	clkint, hardclock, noproc
	.data
	.even
	.globl	procprof, profpid
procprof:
	.word 0
profpid:
	.word 0
	.text
#ifndef WHITE
	.globl	clkparam

#ifdef	s32		| VALID_CLOCKFIX
|
|   All values are in terms of clock cycles/second.
|   This resolves to the crystal frequency
|   driving the h/w duration-clock.
|
	CCLOCK_CYCLES_PER_SECOND=C_RATE		| 1Mhz: from machine/clock.h

||	CLATCHUP=32
||	CCOMMONBIAS=64

	CLATCHUP=25
	CCOMMONBIAS=0

	CNOMINALBIAS=32
	CLONGBIAS=48+24
	CPRONTOBIAS=44

	CNORML=CCLOCK_CYCLES_PER_SECOND/HZ-CLATCHUP-CCOMMONBIAS
	CPRONTO=CNORML/2


	.globl	backlogOfTicks,	   ticksPerClkRupt,	prontoTicker
	.globl	absOfOverrun,	   aggregatBacklog
	.globl	tallySmallBackLog, tallyGoneLONG,	tallyProntoTicks

	.data
	.even

backlogOfTicks:	 .long	0	| long	backlogOfTicks	 = 0;
ticksPerClkRupt: .long	CNORML	| long	ticksPerClkRupt;
prontoTicker:	 .long	CPRONTO	| long	prontoTicker;	

absOfOverrun:	 .long	0	| long	absOfOverrun; /* For debugging */
aggregatBacklog: .long	0	| long	aggregatBacklog;/* Aggregated backlog */

tallySmallBackLog: .long 0	| # of times of ignorable backlog
tallyGoneLONG:	   .long 0	| # of times large overrun
tallyProntoTicks:  .long 0	| # of times quick-tick

	.text

#endif	s32		| VALID_CLOCKFIX

#endif WHITE

KPROFBYTES=24576		| Enough for 384K of kernel text

	.comm kprof,KPROFBYTES	| kernel pc histogram area
#ifdef WHITE
clkint:
	movw	#0x2600,sr
#ifdef HZ60
	movb	#0x95,0x830F69	| VIAADDR->v_t1cl = 17045;
	movb	#0x42,0x830F6B	| VIAADDR->v_t1cl = 17045 >> 8;
#else HZ60
	| 4295 is 60hz, 27f3 is 100hz
	movb	#0xF3,0x830F69
	movb	#0x27,0x830F6B
#endif HZ60
	moveml	#0xC0C0,sp@-	| save registers that C clobbers: a1,a0,d1,d0
#else WHITE

#ifndef	s32		| VALID_CLOCKFIX
clkint:	moveml	#0xC0C0,sp@-	| save regs that C clobbers: a1,a0,d1,d0
|
| Restart the clock first.  This must be
| done at spl7()
|
	movw sr,d0
	movw #0x2700,sr
	lea  CLKADDR+C_C0,a0
	movb #C_LATCH+C_SEL0,a0@(C_MODE-C_C0)
	movb #C_MODE0+C_WORD+C_SEL0,a0@(C_MODE-C_C0)
	movb a0@,d1
	rorw #8,d1
	movb a0@,d1
	rorw #8,d1
	addw clkparam,d1

#else	s32		| VALID_CLOCKFIX

|-------------------------------------------------------------------------------
|
|  History:
|  --------
|	850506 (jht) Origional version;
|
|  Glossary:
|  ---------
|	computational overhead	- All the instruction overhead between
|				  'clkGetPIT' and 'clkSetPIP'.
|
|	   CLATCHUP		- Overhead from 'clkPIT_latchup' to 'clkGetPIP';
|	
|	   CCOMMONBIAS=40	- The rest of the common, non CLATCUP overhead;
|
|	   CNOMINALBIAS=20	- Overhead only for clkNotEnoughBacklog;
|
|	   CLONGBIAS=40		- Overhead only for clkGoneLONG;
|
|	   CPRONTOBIAS=15	- Overhead only for clkProntoTick;
|
|	CNORML			- # ticks minus aggregated "nominal" overhead;
|
|	CPRONTO			- A mere fraction of the CNORML # of ticks;
|
|	backlogOfTicks	- All time beyond the 10msec virtual ticks we need,
|			  including	1) computational overhead: fudge factors
|					2) the duration of "pronto ticks";
|  Algorithm:
|  ----------
|	The processing is comprised of three parts:
|		1) Accumulation of backlogOfTicks iff (PIT latency >  10msec);
|		2) Consumption of any of the above backlogOfTicks  >= 10msec;
|		3) Otherwise, adjust the PIT so next tick @  (GMT mod 10msec);
|
|-------------------------------------------------------------------------------

#ifdef	M68020
#define	mbusDelay()	cmpl	K_A,d0			| Cause 2-3 cache      \
			cmpl	K_A+CACHE_SIZE_BYTES,d0	| ...read-misses for   \
			cmpl	K_A,d0			| ... 1.0-1.5usec delay
#endif	M68020

clkint:
	moveml	#0xE0C0,sp@-	| save regs that C clobbers: d0,d1,(+d2),a0,a1
|
| Restart the clock first.  This must be
| done at spl7()
|
	movw sr,d0
	movw #0x2700,sr

	lea  CLKADDR+C_C0,a0
	movb #C_LATCH+C_SEL0,a0@(C_MODE-C_C0)
#ifdef	M68020
	cmpl	K_A,d0			| Cause 2-3 cache
	cmpl	K_A+CACHE_SIZE_BYTES,d0	| ...read-misses for
	cmpl	K_A,d0			| ... 1.0-1.5usec delay
					| within 1 micro-second of the last
					| access to any other clock register.
#endif	M68020

clkPIT_latchUp:
	movb #C_MODE0+C_WORD+C_SEL0,a0@(C_MODE-C_C0)
#ifdef	M68020
	cmpl	K_A,d0			| Cause 2-3 cache
	cmpl	K_A+CACHE_SIZE_BYTES,d0	| ...read-misses for
	cmpl	K_A,d0			| ... 1.0-1.5usec delay
					| within 1 micro-second of the last
					| access to any other clock register.
#endif	M68020

clkGetPIT:			| # cycles:
				| ---------
	movb a0@,d1		| 8: Read overrun: expect slightly < 0
	rorw #8,d1		| 6+16=22:
#ifdef	M68020
	cmpl	K_A,d0			| Cause 2-3 cache
	cmpl	K_A+CACHE_SIZE_BYTES,d0	| ...read-misses for
	cmpl	K_A,d0			| ... 1.0-1.5usec delay
					| within 1 micro-second of the last
					| access to any other clock register.
#endif	M68020
	movb a0@,d1		| 8:
	rorw #8,d1		| 6+16=22:
|
|  We presume that the overrun-value
|  for the PIT is always non-positive.
|
|  NOTE: occassionally the overrun counter
|  is observed to ROLL THROUGH ZERO.
|  Ostensively, the operating system was busy at spl6.
|
	orl   #0xffff0000,d1	| 16: Sign extension (0X7xxx won't extend!)
	negl  d1		|  6: ...abs(pitOverrun) for 'cmpl'
	movl  d1,absOfOverrun	| 10: ...debugging

	movl  ticksPerClkRupt,d2|  4: Setup...
|
|   (The conditions in these two 'jxx yyyy' instructions
|   seem backwards, but they produce correctly running code!)
|   ('jxx' code produces (short) pc-relative jumps; 'bxx' produces abs jumps;)
|
	cmpl  ticksPerClkRupt,d1| 6:
	jge   clkGoneLONG	| 8/10: Brn if we were locked out a LONG time

	cmpl  backlogOfTicks,d2	| 6:    Is (backlogOfTicks < ticksPerClkRupt) ?
	jlt   clkTickPronto	| 8/10: Brn if have sufficient backlog of ticks
|
|   We have only a small backlog
|   of ticks -- less than 'ticksPerClkRupt',
|   so we don't bother.
|
clkNotEnoughBacklog:
	negl  d1		 | 6: ...(restore SIGNED value of pitOverrun)...
	addl  ticksPerClkRupt,d1 | 6: newPitValue += ticksPerClkRput -pitOverrun

	subl  #CNOMINALBIAS,d1	  | 8: - BIAS;  (Fudge addtn'l "nominal" ovrhd)
	addl  #1,tallySmallBackLog| 8: Debugging/statistics
	jmp   clkSetPIT		  | 4:
|
|   We were at spl6 for a VERY long time:
|   Add ticks to the 'backlogOfTicks' aggregate:
|   We are "behind the (GMT) times."
|
clkGoneLONG:
	addl  d1,backlogOfTicks	| 8: backlogOfTicks += pitOverrun ...
#if 1								/* Debugging */
	addl  d1,aggregatBacklog| 8: aggregatBacklog += pitOverrun ...
#endif
	movl  prontoTicker,d1	| 4: ...
	addl  d1,backlogOfTicks	| 8: ... + (newPitValue	  = prontoTicker)
	subl  d2,backlogOfTicks	| 8: ... - ticksPerClkRupt;
#if 1								/* Debugging */
	addl  d1,aggregatBacklog| 8: ... + (newPitValue	  = prontoTicker)
	subl  d2,aggregatBacklog| 8: ... - ticksPerClkRupt;
#endif
	subl  #CLONGBIAS,d1	| 8: Fudge for addtn'l "GoneLONG" ovrhd
	addl  #1,tallyGoneLONG	| 8: Debugging/statistics
	jmp   clkSetPIT		| 4:
|
|   We have enough 'backlogOfTicks' to merit using one of them:
|   Remove ticks from the 'backlogOfTicks' aggregate:
|   We have gained back some of the lost time.
|
clkTickPronto:
	addl  d1,backlogOfTicks	| 8: backlogOfTicks +=	+ pitOverrun ... 
	subl  d2,backlogOfTicks	| 8: ...		- ticksPerClkRupt
	movl  prontoTicker,d1	| 4: ...  (newPitValue	= prontoTicker)
	addl  d1,backlogOfTicks	| 8: ...			+ prontoTicker

	subl  #CPRONTOBIAS,d1	 | 8: Fudge for addtn'l "TickPronto" ovrhd
	addl  #1,tallyProntoTicks| 8: Debugging/statistics
||	jmp   clkSetPIT		 | 4:

clkSetPIT:

#endif	s32		| VALID_CLOCKFIX

	movb #C_MODE0+C_WORD+C_SEL0,a0@(C_MODE-C_C0)
#ifdef	M68020
	cmpl	K_A,d0			| Cause 2-3 cache
	cmpl	K_A+CACHE_SIZE_BYTES,d0	| ...read-misses for
	cmpl	K_A,d0			| ... 1.0-1.5usec delay
					| within 1 micro-second of the last
					| access to any other clock register.
#endif	M68020
	movb d1,a0@
	rorw #8,d1
#ifdef	M68020
	cmpl	K_A,d0			| Cause 2-3 cache
	cmpl	K_A+CACHE_SIZE_BYTES,d0	| ...read-misses for
	cmpl	K_A,d0			| ... 1.0-1.5usec delay
					| within 1 micro-second of the last
					| access to any other clock register.
#endif	M68020
	movb d1,a0@
	movw d0,sr
#endif WHITE
|
| If we came from user mode then don't
| do any kernel profiling.
|
#ifdef s32	| VALID_CLOCKFIX
	movw sp@(20),d0		| get the interrupt SR to test user mode
#else s32	| VALID_CLOCKFIX
	movw sp@(16),d0		| get the interrupt SR to test user mode
#endif s32	| VALID_CLOCKFIX
	btst #13,d0
	jeq clkintu		| were in user mode
|
| Do not profile the time spent with
| the processor stopped.
|
#ifdef s32	| VALID_CLOCKFIX
	movl sp@(22),d0		| pc
#else s32	| VALID_CLOCKFIX
	movl sp@(18),d0		| pc
#endif s32	| VALID_CLOCKFIX
	cmpl #idlestop,d0
	jeq clkintu
|
| Increment the correct bin for kernel
| profiling.
|
	subl #K_A,d0		| Base of text
	asrl #5,d0		| 16:1 compression of even numbers to integers
	addw d0,d0		| Bins are short words in size
	cmpl #KPROFBYTES-2,d0
	jle 1$
	movw #KPROFBYTES-2,d0	| Last bin gets out of range values
1$:
	tstw procprof		| If procprof is not set...
	jeq 2$			| profile for all processes
	movl u+U_PROCP,a0	| otherwise, we are looking for a specific 
	movw a0@(P_PID), d1	| process.
	cmpw profpid, d1	| The process id is kept in "profpid".
	jne  clkintu		| If equal and "noproc" is not set, profile it.
	tstl noproc
	jne clkintu
2$:
	lea kprof,a0
	addqw #1,a0@(0,d0:w)
|
| Call the once per tick clock handler
| as:
|	hardclock(pc, ps)
|
clkintu:
#ifndef WHITE
#ifndef	s32		| VALID_CLOCKFIX
	movw	sp@(16),sp@-	| pass along ps from exception frame
	clrw	sp@-		| long align ps
	movl	sp@(22),sp@-	| pass along pc from exception frame
#else	s32		| VALID_CLOCKFIX
|
| Compensate for the extra 4 bytes
| pushed on the stack (for d2)
| upon entry to clkint.
|
	movw	sp@(20),sp@-	| pass along PS from exception frame
	clrw	sp@-		| long align PS
	movl	sp@(26),sp@-	| pass along PC from exception frame
#endif	s32		| VALID_CLOCKFIX
#else WHITE
	movw	sp@(16),sp@-	| pass along ps from exception frame
	clrw	sp@-		| long align ps
	movl	sp@(22),sp@-	| pass along pc from exception frame
#endif WHITE
	jsr	hardclock	| hardclock(pc, ps)
	addql	#8,sp		| remove ps,pc
	addql	#1,cnt+V_INTR	| increment interrupt count
#ifndef WHITE
#ifndef	s32		| VALID_CLOCKFIX
	moveml	sp@+,#0x0303	| restore d0,d1,a0,a1
#else	s32		| VALID_CLOCKFIX
	moveml	sp@+,#0x0307	| restore d0,d1,(+d2),a0,a1
#endif	s32		| VALID_CLOCKFIX
#else WHITE
	moveml	sp@+,#0x0303	| restore d0,d1,a0,a1
#endif WHITE
	bra	chksoftclk	| check if a soft clock interrupt is pending

|
| Pseudo interrupt request flags.  THE CODE
| IN chksoftclk ASSUMES THAT wantsoft AND
| astflag OCCUPY THE FOUR BYTES OF A SINGLE
| 32 BIT WORD.
|
	.data
	.globl	wantsoft, astflag, sirnetflag

	.even
pseudopend:
wantsoft:			| Pseudo level 1 interrupt request is pending
	.byte	0x00		|   if wantsoft is non-zero
astflag:			| An Asynchronous System Trap (pseudo
	.byte	0x00		|   interrupt is pending if astflag is non-zero
sirnetflag:			| Software interrupt request for the network
	.byte	0x00		|   is requested if sirnetflag is set
_sirwaste:
	.byte	0x00

	.text
|
| Set a flag indicating that the soft
| clock pseudo-interrupt should occur
| as soon as the processor priority
| drops to 0.
|
	.globl	setsoftclock

setsoftclock:
	movb	#1,wantsoft
	rts
	.text
|
| Just before performing an rte check if
| we are about to return to a low priority level
| If we are and there is software interrupt
| of some kind pending then execute the
| appropriate interrupt code.
|
	.globl	chksoftclk, softclock
	.globl	wantdebug, asmdebugger
#ifdef WHITE
#ifndef REALNIRQL
	.globl	lvl1int
#endif REALNIRQL
#endif WHITE

chksoftclk:
	tstb	wantdebug	| should we enter the debugger ?
	jeq	nodebug
	jsr	asmdebugger	| yes, call the debugger
nodebug:
#ifdef WHITE
#ifndef REALNIRQL
	btst	#4,0x830A01	| Is the cv disk interrupting?
	jne	nocvint		| No, don't call its interrupt routine

	movl	d0,sp@-		| Preserve d0
	movw	sp@(4),d0	| get a copy of the sr
	andw	#0x700,d0	| get the previous mask level
	cmpw	#0x200,d0	| is it lower than 2?
	jge	skipcvint	| no, we are locked out

	movl	sp@+,d0		| restore D0
	jmp	lvl1int		| simulate a disk interrupt

skipcvint:
	movl	sp@+,d0		| restore D0
nocvint:
#endif REALNIRQL
#endif WHITE
	tstl	pseudopend	| is a pseudo interrupt pending?
	jeq	dorte		| no, do an rte
	movw	sp@,sp@-	| copy the sr
	tstb	sirnetflag	| is there a network interrupt pending?
	jeq	nonet		| no, try AST and softclock
	andw	#INTMASK,sp@	| are we returning to priority 0?  BUG:?
	bne	nosoftint	| no, don't do any software interrupts
	clrb	sirnetflag	| clear the pseudo interrupt request

#include "../net/netisr.h"
	.globl	netisr
	.globl	rawintr

	movw	#0x2100,sr	| run at level 1
	moveml	#0xC0C0,sp@-	| push a1,a0,d1,d0
	bclr	#NETISR_RAW,netisr+3
	jeq	skipisr
	jsr	rawintr
skipisr:


#ifdef INET
#include "../netinet/in_systm.h"
	.globl	ipintr

	bclr	#NETISR_IP,netisr+3
	jeq	skipinet
	jsr	ipintr
skipinet:
#endif INET


#ifdef NS
	.globl	nsintr

	bclr	#NETISR_NS,netisr+3
	jeq	skipns
	jsr	nsintr
skipns:
#endif NS


#ifdef VALID_RPC
	.globl	conn_input

	bclr	#NETISR_CONN-8,netisr+2
	jeq	skipconn
	jsr	conn_input
skipconn:


#ifdef VALID_BULK
	.globl	bulk_input

	bclr	#NETISR_BULK-8,netisr+2
	jeq	skipbulk
	jsr	bulk_input
skipbulk:
#endif VALID_BULK
#endif VALID_RPC


#ifdef DECnet
	.globl	DNrtrInput
	bclr	#NETISR_DECnet-16,netisr+1
	jeq	skipdecnet
	jsr	DNrtrInput
skipdecnet:
#endif DECnet


	moveml	sp@+,#0x0303	| restore: d0,d1,a0,a1
	addql	#2,sp		| pop extra copy of sr
	jra	chksoftclk	| go back and look for an AST or softclock
|
| No network interrupt, try soft clock
|
nonet:
	tstb	wantsoft	| is there a soft clock interrupt pending?
	jeq	doast		| no, it must be an AST
	andw	#INTMASK,sp@	| are we returning to priority 0?  BUG: ?
	bne	nosoftint	| no, don't call softclock
	clrb	wantsoft	| clear the pseudo interrupt request
	movw	#0x2100,sr	| run softclock at level 1

	moveml	#0xC0C0,sp@-	| push a1,a0,d1,d0
	movw	sp@(18),sp@-	| push ps
	clrw	sp@-		| long align ps
	movl	sp@(24),sp@-	| push pc
	jsr	softclock	| softclock(pc, ps)
	addql	#8,sp		| pop the arguments
	moveml	sp@+,#0x0303	| restore: d0,d1,a0,a1

	addql	#2,sp		| pop extra copy of sr
	jra	chksoftclk	| go back and look for an AST
|
| Process an AST if we are about to return
| to user mode.
|
doast:
	andw	#SUMASK,sp@	| is the supervisor bit set?  BUG: ?
	jne	nosoftint	| yes, not returning to user mode so skip AST
	addql	#2,sp		| pop extra copy of sr
	jsr	fault		| pretend we just got an AST interrupt and
	.word	T_AST		|   go to trap...and never return here

nosoftint:
	addql	#2,sp		| pop extra copy of sr
dorte:
	cmpl	userregs,sp	| are the saved register values invalid?
	bcs	regok		| stack is below them, they're still valid

	clrl	userregs	| indicate that the userregs is invalid
regok:
#ifndef	M68020
	andb	#0xFF-V_REDLED,V_STATUS		| M68000 & M68010 -- turn off
#else
	andb	#0xFF-V_REDLED,V_STATUS0	| M68020 -- turn off red LED
#endif
	rte

| Semaphore Test and Set.
| Parameter is char *semaphore.
| returns int 1 if semaphore was obtained, 0 otherwise.

	.globl tas

tas:	movl	a0,d0		| save a0, our only work register
	movl	sp@(4),a0	| a0 contains address of semaphore
	tas	a0@		| test and set. cc=eq if we got the lock.
	exg	d0,a0		| restore a0 without changing condition code
	seq	d0		| if we got lock, d0=$ff (else 0)
	andl	#1,d0		| convert to 1 or 0.
	rts			| and return.

| Semaphore Test and Set with timeout.
| Parameters:
|    char *semaphore
|    long busycount.

| Loops "busycount" times trying to obtain semaphore, decrementing busycount.
| returns remaining busycount when semaphore is obtained,
| 0 if unsuccessful.

	.globl tastimeout

tastimeout:
	link	a6,#-8
	moveml	#0x0100,a6@(-8) | save a0
	movl	a6@(12),d0	| fetch busycount
	movl	a6@(8),a0	| semaphore address
tryagain:
	tas	a0@		| test and maybe set it
	beq	gotlock

	subql	#1,d0
	bgt	tryagain
gotlock:			| return value already in d0
	moveml	a6@(-8),#0x0100 | restore a0
	unlk	a6
	rts

|
| Reset the system and jump to VRM or halt
|
	.globl reset

reset:   
	movw	#0x2700,sr      | Kernel mode, level 7
	movl    sp@(4),d0       | Arg 0=> reboot, 1=>halt
#ifdef WHITE
	movl	#0x810014,a0	| PROM pc
	movl	0,sp		| VRM stack pointer (guess)
#else WHITE
	movl	0x10004,a0      | VRM pc
	movl	0x10000,sp      | VRM stack pointer
#endif WHITE
	.word 0x4E70            | Reset instruction
	tstl    d0              | test argument
	bne     f1              | if nonzero halt
	jmp	a0@             | jump to VRM
f1:     stop    #0x2700         | stop processor, at level 7
	jra	f1

	.globl addupc
|addupc(pc,p,n)
|caddr_t *pc;
|struct {
|	caddr_t *base;	/* fwa of counter array */
|	long size;	/* number of bytes in counter array */
|	caddr_t offset;	/* ignore pc values less than this */
|	fix3216 scale;	/* 0,,f interpreted as 0.f */
|} *p;
|int n;

addupc:
	movl sp@(4),d0		|pc
	movl sp@(8),a0		|p
	subl a0@(8),d0		|pc-offset
	jmi aupc9		|pc is too low
	movl d0,d1		|need (a,,b)*0.f == a*f + b*f/65536
	swap d1
	mulu a0@(12+2),d0	|b*f
	mulu a0@(12+2),d1	|a*f
	clrw d0
	swap d0			|b*f/65536
	addl d1,d0
	bclr #0,d0		|2-byte counters
	cmpl a0@(4),d0
	jge aupc9		|pc is too high
	addl a0@,d0		|+base
	movl d0,sp@-		|save ->word
	movl d0,a0		|pseudo-argument to fuword
	.word 0x0E90,0x0000	|movesl a0@,d0	  (fuword)
	movl sp@+,a1		|recover ->word
	movl sp@(8),a0		|p
	addql #1,d0
	jeq aupc7		|user can't read the counter
	movw sp@(12+2),d1	|n
	addw d1,a1@		|assume user read implies user write
	jcc aupc9		|unsigned short was enough
	movw #-1,a1@		|set MAXUSHORT
aupc7:
	clrl a0@(12)		|and disable further profiling
aupc9:
	rts

	.data
	.globl PATCH
PATCH:	.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
