Plan 9 from Bell Labs’s /usr/web/sources/plan9/sys/src/9/rb/l.s

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 * mips 24k machine assist for routerboard rb450g
 */
#include "mem.h"
#include "mips.s"

#define SANITY 0x12345678

	NOSCHED

/*
 * Boot only processor
 */
TEXT	start(SB), $-4
	MOVW	$setR30(SB), R30

PUTC('9', R1, R2)
	DI(0)

	MOVW	sanity(SB), R1
	CONST(SANITY, R2)
	SUBU	R1, R2, R2
	BNE	R2, insane
	NOP

	MOVW	R0, M(COMPARE)
	EHB

	/* don't enable any interrupts nor FP, but leave BEV on. */
	MOVW	$BEV,R1
	MOVW	R1, M(STATUS)
	UBARRIERS(7, R7, stshb)		/* returns to kseg1 space */
	MOVW	R0, M(CAUSE)
	EHB

	/* silence the atheros watchdog */
	MOVW	$(KSEG1|0x18060008), R1
	MOVW	R0, (R1)			/* set no action */
	SYNC

	MOVW	$PE, R1
	MOVW	R1, M(CACHEECC)		/* aka ErrCtl */
	EHB
	JAL	cleancache(SB)
	NOP

	MOVW	$TLBROFF, R1
	MOVW	R1, M(WIRED)

	MOVW	R0, M(CONTEXT)
	EHB

	/* set KSEG0 cachability before trying LL/SC in lock code */
	MOVW	M(CONFIG), R1
	AND	$~CFG_K0, R1
	/* make kseg0 cachable, enable write-through merging */
	OR	$((PTECACHABILITY>>3)|CFG_MM), R1
	MOVW	R1, M(CONFIG)
	BARRIERS(7, R7, cfghb)			/* back to kseg0 space */

	MOVW	$setR30(SB), R30		/* again */

	/* initialize Mach, including stack */
	MOVW	$MACHADDR, R(MACH)
	ADDU	$(MACHSIZE-BY2V), R(MACH), SP
	MOVW	R(MACH), R1
clrmach:
	MOVW	R0, (R1)
	ADDU	$BY2WD, R1
	BNE	R1, SP, clrmach
	NOP
	MOVW	R0, 0(R(MACH))			/* m->machno = 0 */
	MOVW	R0, R(USER)			/* up = nil */

	/* zero bss, byte-by-byte */
	MOVW	$edata(SB), R1
	MOVW	$end(SB), R2
clrbss:
	MOVB	R0, (R1)
	ADDU	$1, R1
	BNE	R1, R2, clrbss
	NOP

	MOVW	$0x16, R16
	MOVW	$0x17, R17
	MOVW	$0x18, R18
	MOVW	$0x19, R19
	MOVW	$0x20, R20
	MOVW	$0x21, R21
	MOVW	$0x22, R22
	MOVW	$0x23, R23

	MOVW	R0, HI
	MOVW	R0, LO

PUTC('\r', R1, R2)
PUTC('\n', R1, R2)
	JAL	main(SB)
	NOP
	CONST(ROM, R1)
	JMP	(R1)			/* back to the rom */

#define PUT(c) PUTC(c, R1, R2)
#define DELAY(lab) \
	CONST(34000000, R3); \
lab:	SUBU	$1, R3; \
	BNE	R3, lab; \
	NOP

insane:
	/*
	 * data segment is misaligned; kernel needs vl -R4096 or -R16384,
	 * as appropriate, for reboot.
	 */
	PUT('?'); PUT('d'); PUT('a'); PUT('t'); PUT('a'); PUT(' '); DELAY(dl1)
	PUT('s'); PUT('e'); PUT('g'); PUT('m'); PUT('e'); PUT('n'); DELAY(dl2)
	PUT('t'); PUT(' '); PUT('m'); PUT('i'); PUT('s'); PUT('a'); DELAY(dl3)
	PUT('l'); PUT('i'); PUT('g'); PUT('n'); PUT('e'); PUT('d'); DELAY(dl4)
	PUT('\r'); PUT('\n'); DELAY(dl5)
	CONST(ROM, R1)
	JMP	(R1)			/* back to the rom */
	NOP

/* target for JALRHB in BARRIERS */
TEXT ret(SB), $-4
	JMP	(R22)
	NOP

/* print R1 in hex; clobbers R3—8 */
TEXT printhex(SB), $-4
	MOVW	$32, R5
	MOVW	$9, R7
prtop:
	SUB	$4, R5
	MOVW	R1, R6
	SRL	R5, R6
	AND	$0xf, R6
	SGTU	R6, R7, R8
	BEQ	R8, prdec		/* branch if R6 <= 9 */
	NOP
	ADD	$('a'-10), R6
	JMP	prchar
	NOP
prdec:
	ADD	$'0', R6
prchar:
	PUTC(R6, R3, R4)
	BNE	R5, prtop
	NOP
	RETURN

/*
 * Take first processor into user mode
 * 	- argument is stack pointer to user
 */
TEXT	touser(SB), $-4
	MOVW	R1, SP
	MOVW	$(UTZERO+32), R2	/* header appears in text */
	MOVW	R2, M(EPC)
	EHB
	MOVW	M(STATUS), R4
	AND	$(~KMODEMASK), R4
	OR	$(KUSER|IE|EXL), R4	/* switch to user mode, intrs on, exc */
	MOVW	R4, M(STATUS)		/* " */
	ERET				/* clears EXL */

/*
 * manipulate interrupts
 */

/* enable an interrupt; bit is in R1 */
TEXT	intron(SB), $0
	MOVW	M(STATUS), R2
	OR	R1, R2
	MOVW	R2, M(STATUS)
	EHB
	RETURN

/* disable an interrupt; bit is in R1 */
TEXT	introff(SB), $0
	MOVW	M(STATUS), R2
	XOR	$-1, R1
	AND	R1, R2
	MOVW	R2, M(STATUS)
	EHB
	RETURN

/* on our 24k, wait instructions are not interruptible, alas. */
TEXT	idle(SB), $-4
	EI(1)				/* old M(STATUS) into R1 */
	EHB
	/* fall through */

TEXT	wait(SB), $-4
	WAIT
	NOP

	MOVW	R1, M(STATUS)		/* interrupts restored */
	EHB
	RETURN

TEXT	splhi(SB), $0
	EHB
	MOVW	R31, 12(R(MACH))	/* save PC in m->splpc */
	DI(1)				/* old M(STATUS) into R1 */
	EHB
	RETURN

TEXT	splx(SB), $0
	EHB
	MOVW	R31, 12(R(MACH))	/* save PC in m->splpc */
	MOVW	M(STATUS), R2
	AND	$IE, R1
	AND	$~IE, R2
	OR	R2, R1
	MOVW	R1, M(STATUS)
	EHB
	RETURN

TEXT	spllo(SB), $0
	EHB
	EI(1)				/* old M(STATUS) into R1 */
	EHB
	RETURN

TEXT	spldone(SB), $0
	RETURN

TEXT	islo(SB), $0
	MOVW	M(STATUS), R1
	AND	$IE, R1
	RETURN

TEXT	coherence(SB), $-4
	BARRIERS(7, R7, cohhb)
	SYNC
	EHB
	RETURN

/*
 * process switching
 */

TEXT	setlabel(SB), $-4
	MOVW	R29, 0(R1)
	MOVW	R31, 4(R1)
	MOVW	R0, R1
	RETURN

TEXT	gotolabel(SB), $-4
	MOVW	0(R1), R29
	MOVW	4(R1), R31
	MOVW	$1, R1
	RETURN

/*
 * the tlb routines need to be called at splhi.
 */

TEXT	puttlb(SB), $0			/* puttlb(virt, phys0, phys1) */
	EHB
	MOVW	R1, M(TLBVIRT)
	EHB
	MOVW	4(FP), R2		/* phys0 */
	MOVW	8(FP), R3		/* phys1 */
	MOVW	R2, M(TLBPHYS0)
	EHB
	MOVW	$PGSZ, R1
	MOVW	R3, M(TLBPHYS1)
	EHB
	MOVW	R1, M(PAGEMASK)
	OR	R2, R3, R4		/* MTC0 delay slot */
	AND	$PTEVALID, R4		/* MTC0 delay slot */
	EHB
	TLBP				/* tlb probe */
	EHB
	MOVW	M(INDEX), R1
	BGEZ	R1, index		/* if tlb entry found, use it */
	NOP
	BEQ	R4, dont		/* not valid? cf. kunmap */
	NOP
	MOVW	M(RANDOM), R1		/* write random tlb entry */
	MOVW	R1, M(INDEX)
index:
	EHB
	TLBWI				/* write indexed tlb entry */
	JRHB(31)			/* return and clear all hazards */
dont:
	RETURN

TEXT	getwired(SB),$0
	MOVW	M(WIRED), R1
	RETURN

TEXT	setwired(SB),$0
	MOVW	R1, M(WIRED)
	EHB
	RETURN

TEXT	getrandom(SB),$0
	MOVW	M(RANDOM), R1
	RETURN

TEXT	getpagemask(SB),$0
	MOVW	M(PAGEMASK), R1
	RETURN

TEXT	setpagemask(SB),$0
	EHB
	MOVW	R1, M(PAGEMASK)
	EHB
	MOVW	R0, R1			/* prevent accidents */
	RETURN

TEXT	puttlbx(SB), $0	/* puttlbx(index, virt, phys0, phys1, pagemask) */
	MOVW	4(FP), R2
	MOVW	8(FP), R3
	MOVW	12(FP), R4
	MOVW	16(FP), R5
	EHB
	MOVW	R2, M(TLBVIRT)
	EHB
	MOVW	R3, M(TLBPHYS0)
	MOVW	R4, M(TLBPHYS1)
	MOVW	R5, M(PAGEMASK)
	EHB
	MOVW	R1, M(INDEX)
	EHB
	TLBWI				/* write indexed tlb entry */
	JRHB(31)			/* return and clear all hazards */

TEXT	tlbvirt(SB), $0
	EHB
	MOVW	M(TLBVIRT), R1
	EHB
	RETURN

TEXT	gettlbx(SB), $0			/* gettlbx(index, &entry) */
	MOVW	4(FP), R5
	MOVW	M(TLBVIRT), R10		/* save our asid */
	EHB
	MOVW	R1, M(INDEX)
	EHB
	TLBR				/* read indexed tlb entry */
	EHB
	MOVW	M(TLBVIRT), R2
	MOVW	M(TLBPHYS0), R3
	MOVW	M(TLBPHYS1), R4
	MOVW	R2, 0(R5)
	MOVW	R3, 4(R5)
	MIPS24KNOP
	MOVW	R4, 8(R5)
	EHB
	MOVW	R10, M(TLBVIRT)		/* restore our asid */
	EHB
	RETURN

TEXT	gettlbp(SB), $0			/* gettlbp(tlbvirt, &entry) */
	MOVW	4(FP), R5
	MOVW	M(TLBVIRT), R10		/* save our asid */
	EHB
	MOVW	R1, M(TLBVIRT)
	EHB
	TLBP				/* probe tlb */
	EHB
	MOVW	M(INDEX), R1
	BLTZ	R1, gettlbp1		/* if no tlb entry found, return */
	NOP
	EHB
	TLBR				/* read indexed tlb entry */
	EHB
	MOVW	M(TLBVIRT), R2
	MOVW	M(TLBPHYS0), R3
	MOVW	M(TLBPHYS1), R4
	MOVW	M(PAGEMASK), R6
	MOVW	R2, 0(R5)
	MOVW	R3, 4(R5)
	MIPS24KNOP
	MOVW	R4, 8(R5)
	MOVW	R6, 12(R5)
gettlbp1:
	EHB
	MOVW	R10, M(TLBVIRT)		/* restore our asid */
	EHB
	RETURN

TEXT	gettlbvirt(SB), $0		/* gettlbvirt(index) */
	MOVW	M(TLBVIRT), R10		/* save our asid */
	EHB
	MOVW	R1, M(INDEX)
	EHB
	TLBR				/* read indexed tlb entry */
	EHB
	MOVW	M(TLBVIRT), R1
	EHB
	MOVW	R10, M(TLBVIRT)		/* restore our asid */
	EHB
	RETURN

/*
 * exceptions.
 * mips promises that there will be no current hazards upon entry
 * to exception handlers.
 */

TEXT	vector0(SB), $-4
	MOVW	$utlbmiss(SB), R26
	JMP	(R26)
	NOP

/*
 * compute stlb hash index.
 * must match index calculation in mmu.c/putstlb()
 *
 * M(TLBVIRT) [page & asid] in arg, result in arg.
 * stir in swizzled asid; we get best results with asid in both high & low bits.
 *
 * page = tlbvirt >> (PGSHIFT+1);	// ignoring even/odd bit
 * R27 = ((tlbvirt<<(STLBLOG-8) ^ (uchar)tlbvirt ^ page ^
 *	((page & (MASK(HIPFNBITS) << STLBLOG)) >> HIPFNBITS)) &
 *	(STLBSIZE-1)) * 12;
 */
#define STLBHASH(arg, tmp, tmp2) \
	MOVW	arg, tmp2; \
	SRL	$(PGSHIFT+1), arg;	/* move low page # bits to low bits */ \
	CONST	((MASK(HIPFNBITS) << STLBLOG), tmp); \
	AND	arg, tmp;		/* extract high page # bits */ \
	SRL	$HIPFNBITS, tmp;	/* position them */ \
	XOR	tmp, arg;		/* include them */ \
	MOVW	tmp2, tmp;		/* asid in low byte */ \
	SLL	$(STLBLOG-8), tmp;	/* move asid to high bits */ \
	XOR	tmp, arg;		/* include asid in high bits too */ \
	AND	$0xff, tmp2, tmp;	/* asid in low byte */ \
	XOR	tmp, arg;		/* include asid in low bits */ \
	CONST	(STLBSIZE-1, tmp); \
	AND	tmp, arg		/* chop to fit */

TEXT	utlbmiss(SB), $-4
	/*
	 * don't use R28 by using constants that span both word halves,
	 * it's unsaved so far.  avoid R24 (up in kernel) and R25 (m in kernel).
	 */
	/* update statistics */
	CONST	(MACHADDR, R26)		/* R26 = m-> */
	MOVW	16(R26), R27
	ADDU	$1, R27
	MOVW	R27, 16(R26)		/* m->tlbfault++ */

	MOVW	R23, M(DESAVE)		/* save R23 */

#ifdef	KUTLBSTATS
	MOVW	M(STATUS), R23
	AND	$KUSER, R23
	BEQ	R23, kmiss

	MOVW	24(R26), R27
	ADDU	$1, R27
	MOVW	R27, 24(R26)		/* m->utlbfault++ */
	JMP	either
kmiss:
	MOVW	20(R26), R27
	ADDU	$1, R27
	MOVW	R27, 20(R26)		/* m->ktlbfault++ */
either:
#endif

	/* compute stlb index */
	EHB
	MOVW	M(TLBVIRT), R27		/* asid in low byte */
	STLBHASH(R27, R26, R23)
	MOVW	M(DESAVE), R23		/* restore R23 */

	/* scale to a byte index (multiply by 12) */
	SLL	$1, R27, R26		/* × 2 */
	ADDU	R26, R27		/* × 3 */
	SLL	$2, R27			/* × 12 */

	CONST	(MACHADDR, R26)		/* R26 = m-> */
	MOVW	4(R26), R26		/* R26 = m->stb */
	ADDU	R26, R27		/* R27 = &m->stb[hash] */

	MOVW	M(BADVADDR), R26
	AND	$BY2PG, R26
	BNE	R26, utlbodd		/* odd page? */
	NOP

utlbeven:
	MOVW	4(R27), R26		/* R26 = m->stb[hash].phys0 */
	BEQ	R26, stlbm		/* nothing cached? do it the hard way */
	NOP
	MOVW	R26, M(TLBPHYS0)
	EHB
	MOVW	8(R27), R26		/* R26 = m->stb[hash].phys1 */
	JMP	utlbcom
	MOVW	R26, M(TLBPHYS1)	/* branch delay slot */

utlbodd:
	MOVW	8(R27), R26		/* R26 = m->stb[hash].phys1 */
	BEQ	R26, stlbm		/* nothing cached? do it the hard way */
	NOP
	MOVW	R26, M(TLBPHYS1)
	EHB
	MOVW	4(R27), R26		/* R26 = m->stb[hash].phys0 */
	MOVW	R26, M(TLBPHYS0)

utlbcom:
	EHB				/* MTC0/MFC0 hazard */
	MOVW	M(TLBVIRT), R26
	MOVW	(R27), R27		/* R27 = m->stb[hash].virt */
	BEQ	R27, stlbm		/* nothing cached? do it the hard way */
	NOP
	/* is the stlb entry for the right virtual address? */
	BNE	R26, R27, stlbm		/* M(TLBVIRT) != m->stb[hash].virt? */
	NOP

	/* if an entry exists, overwrite it, else write a random one */
	CONST	(PGSZ, R27)
	MOVW	R27, M(PAGEMASK)	/* select page size */
	EHB
	TLBP				/* probe tlb */
	EHB
	MOVW	M(INDEX), R26
	BGEZ	R26, utlindex		/* if tlb entry found, rewrite it */
	EHB				/* delay slot */
	TLBWR				/* else write random tlb entry */
	ERET
utlindex:
	TLBWI				/* write indexed tlb entry */
	ERET

/* not in the stlb either; make trap.c figure it out */
stlbm:
	MOVW	$exception(SB), R26
	JMP	(R26)
	NOP

TEXT	stlbhash(SB), $-4
	STLBHASH(R1, R2, R3)
	RETURN

TEXT	vector100(SB), $-4
	MOVW	$exception(SB), R26
	JMP	(R26)
	NOP

TEXT	vector180(SB), $-4
	MOVW	$exception(SB), R26
	JMP	(R26)
	NOP

TEXT	exception(SB), $-4
	MOVW	M(STATUS), R26
	AND	$KUSER, R26, R27
	BEQ	R27, waskernel
	MOVW	SP, R27			/* delay slot */

wasuser:
	CONST	(MACHADDR, SP)		/*  m-> */
	MOVW	8(SP), SP		/*  m->proc */
	MOVW	8(SP), SP		/*  m->proc->kstack */
	MOVW	M(STATUS), R26		/* redundant load */
	ADDU	$(KSTACK-UREGSIZE), SP
	MOVW	R31, Ureg_r31(SP)

	JAL	savereg1(SB)
	NOP

	MOVW	R30, Ureg_r30(SP)
	MOVW	R(MACH), Ureg_r25(SP)
	MIPS24KNOP
	MOVW	R(USER), Ureg_r24(SP)

	MOVW	$setR30(SB), R30
	CONST	(MACHADDR, R(MACH))		/* R(MACH) = m-> */
	MOVW	8(R(MACH)), R(USER)		/* up = m->proc */

	AND	$(EXCMASK<<2), R26, R1
	SUBU	$(CSYS<<2), R1
	BNE	R1, notsys
	NOP

	/* the carrera does this: */
//	ADDU	$8, SP, R1			/* first arg for syscall */

	MOVW	SP, R1				/* first arg for syscall */
	JAL	syscall(SB)
	SUBU	$Notuoffset, SP			/* delay slot */
sysrestore:
	JAL	restreg1(SB)
	ADDU	$Notuoffset, SP			/* delay slot */

	MOVW	Ureg_r31(SP), R31
	MOVW	Ureg_status(SP), R26
	MOVW	Ureg_r30(SP), R30
	MOVW	R26, M(STATUS)
	EHB
	MOVW	Ureg_pc(SP), R26		/* old pc */
	MOVW	Ureg_sp(SP), SP
	MOVW	R26, M(EPC)
	ERET

notsys:
	JAL	savereg2(SB)
	NOP

	/* the carrera does this: */
//	ADDU	$8, SP, R1			/* first arg for trap */

	MOVW	SP, R1				/* first arg for trap */
	JAL	trap(SB)
	SUBU	$Notuoffset, SP			/* delay slot */

	ADDU	$Notuoffset, SP

restore:
	JAL	restreg1(SB)
	NOP
	JAL	restreg2(SB)		/* restores R28, among others */
	NOP

	MOVW	Ureg_r30(SP), R30
	MOVW	Ureg_r31(SP), R31
	MOVW	Ureg_r25(SP), R(MACH)
	MOVW	Ureg_r24(SP), R(USER)
	MOVW	Ureg_sp(SP), SP
	MOVW	R26, M(EPC)
	ERET

waskernel:
	SUBU	$UREGSIZE, SP
	OR	$7, SP				/* conservative rounding */
	XOR	$7, SP
	MOVW	R31, Ureg_r31(SP)

	JAL	savereg1(SB)
	NOP
	JAL	savereg2(SB)
	NOP

	/* the carrera does this: */
//	ADDU	$8, SP, R1			/* first arg for trap */

	MOVW	SP, R1			/* first arg for trap */
	JAL	trap(SB)
	SUBU	$Notuoffset, SP			/* delay slot */

	ADDU	$Notuoffset, SP

	JAL	restreg1(SB)
	NOP

	/*
	 * if about to return to `wait', interrupt arrived just before
	 * executing wait, so move saved pc past it.
	 */
	MOVW	Ureg_pc(SP), R26
	MOVW	R26, R31
	MOVW	$wait(SB), R1
	SUBU	R1, R31
	BNE	R31, notwait
	NOP
	ADD	$BY2WD, R26		/* advance saved pc */
	MOVW	R26, Ureg_pc(SP)
notwait:
	JAL	restreg2(SB)		/* restores R28, among others */
	NOP

	MOVW	Ureg_r31(SP), R31
	MOVW	Ureg_sp(SP), SP
	MOVW	R26, M(EPC)
	ERET

TEXT	forkret(SB), $0
	JMP	sysrestore
	MOVW	R0, R1			/* delay slot; child returns 0 */

/*
 * save mandatory registers.
 * called with old M(STATUS) in R26.
 * called with old SP in R27
 * returns with M(CAUSE) in R26
 */
TEXT	savereg1(SB), $-4
	MOVW	R1, Ureg_r1(SP)

	MOVW	$(~KMODEMASK),R1	/* don't use R28, it's unsaved so far */
	AND	R26, R1
	MOVW	R1, M(STATUS)
	EHB

	MOVW	R26, Ureg_status(SP)	/* status */
	MOVW	R27, Ureg_sp(SP)	/* user SP */

	MOVW	M(EPC), R1
	MOVW	M(CAUSE), R26

	MOVW	R23, Ureg_r23(SP)
	MOVW	R22, Ureg_r22(SP)
	MIPS24KNOP
	MOVW	R21, Ureg_r21(SP)
	MOVW	R20, Ureg_r20(SP)
	MIPS24KNOP
	MOVW	R19, Ureg_r19(SP)
	MOVW	R1, Ureg_pc(SP)
	RETURN

/*
 * all other registers.
 * called with M(CAUSE) in R26
 */
TEXT	savereg2(SB), $-4
	MOVW	R2, Ureg_r2(SP)

	MOVW	M(BADVADDR), R2
	MOVW	R26, Ureg_cause(SP)
	MOVW	M(TLBVIRT), R1
	MOVW	R2, Ureg_badvaddr(SP)
	MOVW	R1, Ureg_tlbvirt(SP)
	MOVW	HI, R1
	MOVW	LO, R2
	MOVW	R1, Ureg_hi(SP)
	MOVW	R2, Ureg_lo(SP)
	MIPS24KNOP
					/* LINK,SB,SP missing */
	MOVW	R28, Ureg_r28(SP)
					/* R27, R26 not saved */
					/* R25, R24 missing */
					/* R23- R19 saved in save1 */
	MOVW	R18, Ureg_r18(SP)
	MIPS24KNOP
	MOVW	R17, Ureg_r17(SP)
	MOVW	R16, Ureg_r16(SP)
	MIPS24KNOP
	MOVW	R15, Ureg_r15(SP)
	MOVW	R14, Ureg_r14(SP)
	MIPS24KNOP
	MOVW	R13, Ureg_r13(SP)
	MOVW	R12, Ureg_r12(SP)
	MIPS24KNOP
	MOVW	R11, Ureg_r11(SP)
	MOVW	R10, Ureg_r10(SP)
	MIPS24KNOP
	MOVW	R9, Ureg_r9(SP)
	MOVW	R8, Ureg_r8(SP)
	MIPS24KNOP
	MOVW	R7, Ureg_r7(SP)
	MOVW	R6, Ureg_r6(SP)
	MIPS24KNOP
	MOVW	R5, Ureg_r5(SP)
	MOVW	R4, Ureg_r4(SP)
	MIPS24KNOP
	MOVW	R3, Ureg_r3(SP)
	RETURN

TEXT	restreg1(SB), $-4
	MOVW	Ureg_r23(SP), R23
	MOVW	Ureg_r22(SP), R22
	MOVW	Ureg_r21(SP), R21
	MOVW	Ureg_r20(SP), R20
	MOVW	Ureg_r19(SP), R19
	RETURN

TEXT	restreg2(SB), $-4
					/* LINK,SB,SP missing */
	MOVW	Ureg_r28(SP), R28
					/* R27, R26 not saved */
					/* R25, R24 missing */
					/* R19- R23 restored in rest1 */
	MOVW	Ureg_r18(SP), R18
	MOVW	Ureg_r17(SP), R17
	MOVW	Ureg_r16(SP), R16
	MOVW	Ureg_r15(SP), R15
	MOVW	Ureg_r14(SP), R14
	MOVW	Ureg_r13(SP), R13
	MOVW	Ureg_r12(SP), R12
	MOVW	Ureg_r11(SP), R11
	MOVW	Ureg_r10(SP), R10
	MOVW	Ureg_r9(SP), R9
	MOVW	Ureg_r8(SP), R8
	MOVW	Ureg_r7(SP), R7
	MOVW	Ureg_r6(SP), R6
	MOVW	Ureg_r5(SP), R5
	MOVW	Ureg_r4(SP), R4
	MOVW	Ureg_r3(SP), R3
	MOVW	Ureg_lo(SP), R2
	MOVW	Ureg_hi(SP), R1
	MOVW	R2, LO
	MOVW	R1, HI

	MOVW	Ureg_status(SP), R1
	MOVW	Ureg_r2(SP), R2
	MOVW	R1, M(STATUS)		/* could change interruptibility */
	EHB
	MOVW	Ureg_r1(SP), R1	/* BOTCH */
	MOVW	Ureg_pc(SP), R26
	RETURN

#ifdef OLD_MIPS_EXAMPLE
/* this appears to be a dreg from the distant past */
TEXT	rfnote(SB), $0
	MOVW	R1, R26			/* 1st arg is &uregpointer */
	JMP	restore
	SUBU	$(BY2WD), R26, SP	/* delay slot: pc hole */
#endif

/*
 * degenerate floating-point stuff
 */

TEXT	clrfpintr(SB), $0
	RETURN

TEXT	savefpregs(SB), $0
	RETURN

TEXT	restfpregs(SB), $0
	RETURN

TEXT	fcr31(SB), $0			/* fp csr */
	MOVW	R0, R1
	RETURN

/*
 * Emulate 68020 test and set: load linked / store conditional
 */

TEXT	tas(SB), $0
	MOVW	R1, R2		/* address of key */
tas1:
	MOVW	$1, R3
	LL(2, 1)
	NOP
	SC(2, 3)
	NOP
	BEQ	R3, tas1
	NOP
	RETURN

TEXT	_xinc(SB), $0
	MOVW	R1, R2		/* address of counter */
loop:
	MOVW	$1, R3
	LL(2, 1)
	NOP
	ADDU	R1, R3
	MOVW	R3, R1		/* return new value */
	SC(2, 3)
	NOP
	BEQ	R3, loop
	NOP
	RETURN

TEXT	_xdec(SB), $0
	SYNC
	MOVW	R1, R2		/* address of counter */
loop1:
	MOVW	$-1, R3
	LL(2, 1)
	NOP
	ADDU	R1, R3
	MOVW	R3, R1		/* return new value */
	SC(2, 3)
	NOP
	BEQ	R3, loop1
	NOP
	RETURN

/* used by the semaphore implementation */
TEXT cmpswap(SB), $0
	MOVW	R1, R2		/* address of key */
	MOVW	old+4(FP), R3	/* old value */
	MOVW	new+8(FP), R4	/* new value */
	LL(2, 1)		/* R1 = (R2) */
	NOP
	BNE	R1, R3, fail
	NOP
	MOVW	R4, R1
	SC(2, 1)	/* (R2) = R1 if (R2) hasn't changed; R1 = success */
	NOP
	RETURN
fail:
	MOVW	R0, R1
	RETURN

/*
 *  cache manipulation
 */

/*
 *  we avoided using R4, R5, R6, and R7 so gotopc can call us without saving
 *  them, but gotopc is now gone.
 */
TEXT	icflush(SB), $-4			/* icflush(virtaddr, count) */
	MOVW	4(FP), R9
	DI(10)				/* intrs off, old status -> R10 */
	UBARRIERS(7, R7, ichb);		/* return to kseg1 (uncached) */
	ADDU	R1, R9			/* R9 = last address */
	MOVW	$(~(CACHELINESZ-1)), R8
	AND	R1, R8			/* R8 = first address, rounded down */
	ADDU	$(CACHELINESZ-1), R9
	AND	$(~(CACHELINESZ-1)), R9	/* round last address up */
	SUBU	R8, R9			/* R9 = revised count */
icflush1:
//	CACHE	PD+HWB, (R8)		/* flush D to ram */
	CACHE	PI+HINV, (R8)		/* invalidate in I */
	SUBU	$CACHELINESZ, R9
	BGTZ	R9, icflush1
	ADDU	$CACHELINESZ, R8	/* delay slot */

	BARRIERS(7, R7, ic2hb);		/* return to kseg0 (cached) */
	MOVW	R10, M(STATUS)
	JRHB(31)			/* return and clear all hazards */

TEXT	dcflush(SB), $-4			/* dcflush(virtaddr, count) */
	MOVW	4(FP), R9
	DI(10)				/* intrs off, old status -> R10 */
	SYNC
	EHB
	ADDU	R1, R9			/* R9 = last address */
	MOVW	$(~(CACHELINESZ-1)), R8
	AND	R1, R8			/* R8 = first address, rounded down */
	ADDU	$(CACHELINESZ-1), R9
	AND	$(~(CACHELINESZ-1)), R9	/* round last address up */
	SUBU	R8, R9			/* R9 = revised count */
dcflush1:
//	CACHE	PI+HINV, (R8)		/* invalidate in I */
	CACHE	PD+HWBI, (R8)		/* flush & invalidate in D */
	SUBU	$CACHELINESZ, R9
	BGTZ	R9, dcflush1
	ADDU	$CACHELINESZ, R8	/* delay slot */
	SYNC
	EHB
	MOVW	R10, M(STATUS)
	JRHB(31)			/* return and clear all hazards */

/* the i and d caches may be different sizes, so clean them separately */
TEXT	cleancache(SB), $-4
	DI(10)				/* intrs off, old status -> R10 */

	UBARRIERS(7, R7, cchb);		/* return to kseg1 (uncached) */
	MOVW	R0, R1			/* index, not address */
	MOVW	$ICACHESIZE, R9
iccache:
	CACHE	PI+IWBI, (R1)		/* flush & invalidate I by index */
	SUBU	$CACHELINESZ, R9
	BGTZ	R9, iccache
	ADDU	$CACHELINESZ, R1	/* delay slot */

	BARRIERS(7, R7, cc2hb);		/* return to kseg0 (cached) */

	MOVW	R0, R1			/* index, not address */
	MOVW	$DCACHESIZE, R9
dccache:
	CACHE	PD+IWBI, (R1)		/* flush & invalidate D by index */
	SUBU	$CACHELINESZ, R9
	BGTZ	R9, dccache
	ADDU	$CACHELINESZ, R1	/* delay slot */

	SYNC
	MOVW	R10, M(STATUS)
	JRHB(31)			/* return and clear all hazards */

/*
 * access to CP0 registers
 */

TEXT	prid(SB), $0
	MOVW	M(PRID), R1
	RETURN

TEXT	rdcount(SB), $0
	MOVW	M(COUNT), R1
	RETURN

TEXT	wrcount(SB), $0
	MOVW	R1, M(COUNT)
	EHB
	RETURN

TEXT	wrcompare(SB), $0
	MOVW	R1, M(COMPARE)
	EHB
	RETURN

TEXT	rdcompare(SB), $0
	MOVW	M(COMPARE), R1
	RETURN

TEXT	getconfig(SB), $-4
	MOVW	M(CONFIG), R1
	RETURN

TEXT	getconfig1(SB), $-4
	MFC0(CONFIG, 1, 1)
	RETURN

TEXT	getconfig2(SB), $-4
	MFC0(CONFIG, 2, 1)
	RETURN

TEXT	getconfig3(SB), $-4
	MFC0(CONFIG, 3, 1)
	RETURN

TEXT	getconfig4(SB), $-4
	MFC0(CONFIG, 4, 1)
	RETURN

TEXT	getconfig7(SB), $-4
	MFC0(CONFIG, 7, 1)
	RETURN

TEXT	gethwreg3(SB), $-4
	RDHWR(3, 1)
	RETURN

TEXT	getcause(SB), $-4
	MOVW	M(CAUSE), R1
	RETURN

TEXT	C_fcr0(SB), $-4		/* fp implementation */
	MOVW	$0x500, R1	/* claim to be an r4k, thus have ll/sc */
	RETURN

TEXT	getstatus(SB), $0
	MOVW	M(STATUS), R1
	RETURN

TEXT	setstatus(SB), $0
	MOVW	R1, M(STATUS)
	EHB
	RETURN

TEXT	setwatchhi0(SB), $0
	MOVW	R1, M(WATCHHI)
	EHB
	RETURN

/*
 * beware that the register takes a double-word address, so it's not
 * precise to the individual instruction.
 */
TEXT	setwatchlo0(SB), $0
	MOVW	R1, M(WATCHLO)
	EHB
	RETURN

TEXT	setsp(SB), $-4
	MOVW	R1, SP
	RETURN

TEXT	getintctl(SB), $-4
	MFC0(STATUS, 1, 1)
	RETURN

TEXT	getsrsctl(SB), $-4
	MFC0(STATUS, 2, 1)
	RETURN

TEXT	getsrsmap(SB), $-4
	MFC0(STATUS, 3, 1)
	RETURN

TEXT	getperfctl0(SB), $-4
	MFC0(PERFCOUNT, 0, 1)
	RETURN

TEXT	getperfctl1(SB), $-4
	MFC0(PERFCOUNT, 2, 1)
	RETURN

	GLOBL	sanity(SB), $4
	DATA	sanity(SB)/4, $SANITY

	SCHED

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.