Metropoli BBS
VIEWER: tim.s MODE: TEXT (ASCII)
**********************************************************************
* Name:		TIM
* Stack:	( ob --> ? time )
* Desc:		Execution time measurement
**********************************************************************
ASSEMBLE
	CON(1)	8
RPL
xNAME TIM
::
  CK1

  '
  ::
     SysTime ONE{}N >R		( Keep time variable in return stack )
     GARBAGE			( Avoid GC fluctuations              )

     CODE
TIMEPART1	GOSBVL	=SAVPTR

		GOSBVL	=DisableIntr

* Wait until no keys down

-		GOSBVL	=BITMAP
		GOSBVL	=Debounce
		?A#0	W
		GOYES	-
		GOSBVL	=adjkey

* Prepare timing and do a small delay to stabilize

		GOSBVL	=GetTimChk
		B=A	W
		C=0	W
		LCHEX	1C20000		1 hour
		B=B+C	W		B[W] = time + 1 hour
		D=C	W		D[W] = 1 hour

		A=0	W
		C=0	W
		D1=(2)	=TIMER2		Wait until boundary to avoid
		A=DAT1	B		tick boundary effects later on
-		C=DAT1	B
		?C=A	P
		GOYES	-

		LC(2)	128
		A=DAT1	8
		DAT1=C	8
		D1=(2)	=TIMERCTRL.1
		LC(2)	#50		[SRQ WKE INT TRUN] = [0 1 0 1]
		DAT1=C	B
		LCHEX	00000286
		B=B+C	W		B[W] = time + 1 hour + 646 ticks

* SHUTDN with display on is with TIMER2 -2
* SHUTDN with display off is with TIMER2 -514 (512+2)
* So 516 ticks for clock adjustment

		P=	7		Sign extend TIMER2
		C=A	P
		C=C+C	P
		GONC	+
		A=-A	W
		A=-A	WP
+		P=	0

		B=B-A	W
		A=B	W
		GOSBVL	PutNEXTIRQ

		GOSUB	D0->Time	Save start time
		C=B	W
		C=C-D	W
		DAT0=C	13

		SHUTDN			*STABILIZE*

		D1=(5)	=TIMER2		Second stabilization is a short one
		C=0	W
		LC(1)	2
		DAT1=C	8
		D1=(2)	=TIMERCTRL.1
		LC(2)	#50		[SRQ WKE INT TRUN] = [0 1 0 1]
		DAT1=C	B

		D0=(5)	=BITOFFSET	With a very fast display off/on toggle
		C=DAT0	1		This gives extra stability while
		CBIT=0	3		not being as annoying as the more
		DAT0=C	1		stable 128 tick display off method.
		CBIT=1	3		Experimentally this is the best place
		DAT0=C	1		to do the display blink.

		SHUTDN			*STABILIZE*

		D1=(2)	=TIMER2		Restore timers
		C=D	W
		DAT1=C	8
		D1=(2)	=TIMERCTRL.1
		LC(2)	#70		[SRQ WKE INT TRUN] = [0 1 1 1]
		DAT1=C	B
		GOSBVL	=AllowIntr
		GOSBVL	=GETPTR		Evaluate input object
		A=DAT1	A
		D1=D1+	5
		D=D+1	A
		PC=(A)

D0->Time	D0=(5)	=aRSKTOP	Help subroutine to recall the
		A=DAT0	A		time hex string pushed to
		D0=A			return stack
		A=DAT0	A
		D0=A
		D0=D0-	5
		A=DAT0	A
		D0=A
		D0=D0+	10
		RTN
      ENDCODE

      CODE
TIMEPART2	GOSBVL	=SAVPTR
		A=0	W		Prepare variables
		C=0	W
		B=0	A
		D1=(5)	=TIMER2

		D0=(5)	=IRAM@		Dispatch to SX/GX code
		A=DAT0	XS
		A=A+A	XS
		GONC	sxfinish
		GOTO	gxfinish

sxfinish	D0=(5)	=NEXTIRQ	Delay until tick changes to avoid
		A=DAT0	13		irregularities in C increments
		C=DAT1	8
		D=C	W
-		B=B+1	A		
		C=DAT1	A
		P=	0
		?D=C	P
		GOYES	-
		D0=(5)	=SAVE_C[A]	Increment C, the interrupt system
		C=0	W		will then save some value as the
		DAT1=C	8		timer goes negative
		C=C+1	X	 1
		C=C+1	B	 2
		C=C+1	X	 3	Dan: Low limit 3
		C=C+1	B	 4
		C=C+1	X	 5
		C=C+1	B	 6
		C=C+1	X	 7
		C=C+1	B	 8
		C=C+1	X	 9
		C=C+1	B       10
		C=C+1	X       11
		C=C+1	B       12
		C=C+1	X       13
		C=C+1	B       14
		C=C+1	X       15
		C=C+1	B       16
		C=C+1	X       17
		C=C+1	B       18
		C=C+1	X       19
		C=C+1	B       20
		C=C+1	X       21
		C=C+1	B       22
		C=C+1	X       23
		C=C+1	B       24	Dan: Hi limit 24
		C=C+1	X       25
		C=C+1	B       26
		C=C+1	X       27
		C=C+1	B       28
		C=C+1	X       29
		C=C+1	B       30
		C=C+1	X       31
		C=C+1	B       32
		C=C+1	X       33
		C=C+1	B       34
		C=C+1	X       35
		C=C+1	B       36
		C=C+1	X       37
		C=C+1	B       38
		C=C+1	X       39
		C=C+1	B       40
		C=C+1	X       41
		C=C+1	B       42
		C=C+1	X       43
		C=C+1	B       44
		C=C+1	X       45
		C=C+1	B       46
		C=C+1	X       47
		C=C+1	B       48
		C=C+1	X       49
		C=C+1	B	50

		C=DAT0	A		Scale the counters by 3 for SX
		RSTK=C
		C=B	A
		C=C+C	A
		C=C+B	A
		R1=C	A		3*loop count
		C=RSTK
		B=C	A
		C=C+C	A
		C=C+B	A
		R0=C	A		3*count
		GOTO	commonfin

gxfinish	D0=(5)	=G_NEXTIRQ	Delay until tick changes to avoid
		A=DAT0	13		irregularities in C increments
		C=DAT1	8
		D=C	W
-		B=B+1	A
		C=DAT1	A
		P=	0
		?D=C	X
		GOYES	-
		D0=(5)	=G_SAVE_C[A]	Let interrupt system save the counter
		C=0	W		when timer goes negative
		DAT1=C	8
		LC(2)	1
		LC(2)	2
		LC(2)	3
		LC(2)	4
		LC(2)	5
		LC(2)	6
		LC(2)	7
		LC(2)	8
		LC(2)	9
		LC(2)	10
		LC(2)	11
		LC(2)	12
		LC(2)	13
		LC(2)	14
		LC(2)	15
		LC(2)	16
		LC(2)	17
		LC(2)	18	Dan: Lo limit 18 (?)
		LC(2)	19
		LC(2)	20
		LC(2)	21
		LC(2)	22
		LC(2)	23
		LC(2)	24
		LC(2)	25
		LC(2)	26
		LC(2)	27
		LC(2)	28
		LC(2)	29
		LC(2)	30
		LC(2)	31
		LC(2)	32
		LC(2)	33
		LC(2)	34
		LC(2)	35
		LC(2)	36
		LC(2)	37
		LC(2)	38	Dan: Hi limit 38 (?)
		LC(2)	39
		LC(2)	40
		LC(2)	41
		LC(2)	42
		LC(2)	43
		LC(2)	44
		LC(2)	45
		LC(2)	46
		LC(2)	47
		LC(2)	48
		LC(2)	49
		LC(2)	50

		C=DAT0	A	Scale the counters for GX
		C=C+C	A
		R0=C.F	A	2*count
		C=B	A
		C=C+C	A
		R1=C.F	A	2*loop count

* Finish up

commonfin	GOSBVL	=DisableIntr
		C=D	W
		GOSBVL	=GetTimeEnd	Calculate ending time

		GOSUB	D0->Time	Calculate running time
		A=DAT0	13
		C=C-A	W
		DAT0=C	13

		C=D	W		Fix time to correct value
		R3=C	W
		GOSBVL	=GetTimChk
		C=R3	W
		C=C-1	W
		A=A-C	W
		GOSBVL	PutNEXTIRQ

		GOSBVL	=AllowIntr	Return counters
		GOVLNG	=Push2#Loop
      ENDCODE

* Calculate the total running time

      RDUP 'RRDROP HXS>%		( #counter #loops %ticks )
      UNROT SEVEN #* #+ UNCOERCE	( %ticks %7*loops+counter )
      % 0.01 %* %-			( %time )

* Now measure NOP execution time to get calculator (not just version!)
* independant overhead time.			

      'NOP
      CODE
	 	GOTO	TIMEPART1
      ENDCODE
      CODE
		GOTO	TIMEPART2
      ENDCODE

      'RRDROP HXS>%			( %time #counter #loops %ticks )
      UNROT SEVEN #* #+ UNCOERCE	( %time %ticks %7*loops+counter )
      % .01 %* %-			( %time %time2 )

* Substract the offset (including NOP execution time)

      %-				( %time' )

* Add NOP execution time back in, it is not an overhead
* Actually we add slightly more since above doesn't seem to
* get the overhead exactly right, we use values such that
* we get correct execution times for NOP whose execution time
* can be accurately measured for example by timing 1000 sequential
* NOP's and dividing by 1000.

      GX? ITE % 0.31 % 0.45 %+		( %time'' )

* Format result for output

      DUP % 8.192 %/ %2 RNDXY
      DUP %100 %>= ITE
      ::
         % 1000 %/
         UNIT %1 tok_s umEND ;
      ;
      UNIT %1 CHR m tok_s umP umEND ;
      UM>U
      SWAP DECOMP$ >TAG
  ;

* Copy above subroutine to even address

  CHR_X TOTEMPOB
  CODE
	A=DAT1	A
	?ABIT=1	0
	GOYES	+
+	GOVLNG	=PushT/FLoop
  ENDCODE
  IT TOTEMPOB DROP

* And evaluate it from there

  COLA_EVAL
;
**********************************************************************
[ RETURN TO DIRECTORY ]