From:	SMTP%"MACRO32@WKUVX1.WKU.EDU" 15-JAN-1994 09:56:47.17
To:	EVERHART
CC:	
Subj:	Light diddlers for uVAX II

X-Listname: "VMS Internals, MACRO, & BLISS Discussions" <MACRO32@WKUVX1.WKU.EDU>
Warnings-To: <>
Errors-To: MacroMan@WKUVX1.WKU.EDU
Sender: MacroMan@WKUVX1.WKU.EDU
Date: Sat, 15 Jan 94 16:15:32 +1300
Message-Id: <0097894A369DB740.0000008E@toyvax.zl2tnm.gen.nz>
From: "Don Stokes" <don@toyvax.zl2tnm.gen.nz>
Reply-To: MACRO32@WKUVX1.WKU.EDU
Subject: Light diddlers for uVAX II
To: MACRO32@WKUVX1.WKU.EDU
X-Vms-Mail-To: MACRO32@WKUVX1.WKU.EDU
X-Vms-Mail-Cc: DON

Here's the third version of the uVAX II LED diddler.  This does what the 
previous one did, ie display idle time on the LED at 1 sec intevals, but 
this one doesn't occupy a process slot.  Rather, it runs as a system 
subroutine using a repeating TQE, mapping the page directly instead of 
using $CRMPSC.  Enjoy.

Don Stokes, Network Manager, Victoria University of Wellington, New Zealand.
don@zl2tnm.gen.nz(home) don@vuw.ac.nz(work) +64 4 495-5052 Fax+64 4 471-5386  

	.title IDLE_LED		Display idle time on uVAX II rear panel

;
; This little ditty displays the idle time on the KA630 panel insert LED
; display by diddling the Boot & Diagnostic Register located at physical
; address ^x20080000.  This is done from nonpaged pool using a repeating
; system subroutine TQE to run it at one second intervals.  The program
; does not require a process slot after loading the into pool.
;
; Accessing the BDR is done by requesting a system page table entry and
; mapping it onto the BDR page.  
;
; This has only been tested on the KA630 (MicroVAX II).  It may work with
; other KA6xx processors if they use the same BDR format.  On the other
; hand, it may crash other processors.  It also does kernel stuff.  You've
; been warned.  I'd like to hear of mods to make it work on other systems.
;
; Privileges required: CMKRNL.  
;
; Don Stokes <don@zl2tnm.gen.nz>, 15 January 1994.
; This program is in the public domain.  No warranties expressed or implied.
;

		.library "SYS$LIBRARY:LIB.MLB"
		.link "SYS$SYSTEM:SYS.STB"/selective_search
		.library "MACROS"

		$PRTDEF
		$PTEDEF
		$TQEDEF
		$IPLDEF
		$IRPDEF
		$CPUDEF

PHY_BDR		= ^x20080000		; Phy address of Boot & Diagnostic Reg
BDR_PTE		= PTE$M_VALID!<PRT$C_KW@PTE$V_PROT>!PTE$M_WINDOW!<PHY_BDR@-9>
					; PTE to map BDR, valid, window, KW

	.psect IDLE_LED_RE, long,exe,shr,nowrt
	.entry idle_led, ^M<>
		$CMKRNL_S routin=install_krnl	; Who needs user-mode code?
		ret

	.entry install_krnl, ^M<R2,R3,R4,R5,R6,R7>
;
; Map page onto BDR
;
		movl #1, R2			; R2=PTE count
		jsb g^LDR$ALLOC_PT		; Get PTE
		blbc R0, 99$			; OK?
		movl #BDR_PTE, (R1)		; Map page, R1=PTE adr, R2=count
		subl3 g^LDR$GL_SPTBASE, R1, R7	; R7=PTE number*4
		ashl #7, R7, R7			; R7=offset to VA
		bisl #^x80000000, R7		; R7=abs VA of page
;
; Allocate some nonpaged pool and put code into it
;
		movl #krnl_size+12, R1
		jsb g^EXE$ALONONPAGED		; Allocate some nonpaged pool
		blbc R0, 99$			; R2=pool address, R1=len
		movzwl R1, IRP$W_SIZE(R2)	; save length of pool packet
		movab 12(R2), R6		; R6=pool code entry address
		movc3 #krnl_size, krnl_base, (R6); Copy code into pool
;
; Allocate a TQE and set it up
;
		jsb g^EXE$ALLOCTQE		; R2=TQE address
		blbs R0, 98$
		movab -12(R6), R1
		jsb g^EXE$DEANONPAGED
99$:		ret
98$:		movl R2, R5			; EXE$INSTIMQ wants TQE in R5
		movb #TQE$C_SSREPT, TQE$B_RQTYPE(R5) ; repeated TQE...
		movq #10000000, TQE$Q_DELTA(R5) ; ... at 1sec intervals
		movl R6, TQE$L_FPC(R5)		; AST routine addr
		movl R7, TQE$L_FR3(R5)		; Use BDR addr as R3 in TQE
		clrl TQE$L_FR4(R5)		; R4 is last timer
;
; Now queue the TQE.  This is done at IPL$_TIMER to protect against accidents.
; Note that this uses poor man's lockdown; this isn't intended for SMP systems!
;
		dsbint ipl=10$, environ=uniprocessor ; Shields up!
		movq g^EXE$GQ_SYSTIME, R0	; TQE will fire on next tick
		jsb g^EXE$INSTIMQ		; insert it into queue
		enbint				; Shields down.
		movl #SS$_NORMAL, R0
		ret
10$:		.long IPL$_TIMER


;
; Code to get idle time and place in LED display, run from TQE in nonpaged
; pool at IPL$_TIMER at one second intervals.
; This is aggressively non-SMP code and only measures idle time on CPU 0.
; Idle time is converted to a busy time fingure in the range 0..9.  
; On entry:	R3		VA of mapped BDR		(from TQE$L_FR3)
;		R4		Last value of CPU$L_NULLCPU	(from TQE$L_FR4)
;		R5		address of TQE 
; On exit:	TQE$L_FR4	Current value of CPU$L_NULLCPU
;		R5		Must contain address of TQE
;		R0		Trashed
;
krnl_base:	movl g^SMP$GL_CPU_DATA, R0 ; R0=address of CPU 0's counters
		movl CPU$L_NULLCPU(R0), R0 ; R0=absolute idle time on CPU 0
		movl R0, TQE$L_FR4(R5)	; save absolute idle time
		subl R4, R0		; R0=delta idle time in 10ms ticks
		divl #10, R0		; R0=idle time in 100ms ticks
		subl3 R0, #9, R0	; R0=busy time, 0..9
		bgeq 1$			; Underflow?
		clrl R0			; Correct underflow (timer slew etc)
1$:		movw R0, (R3)		; Place in BDR
		rsb
krnl_size 	= . - krnl_base

		.end idle_led