Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!rutgers!ames!ucbcad!ucbvax!decvax!decwrl!labrea!navajo!rokicki
From: rokicki@navajo.STANFORD.EDU (Tomas Rokicki)
Newsgroups: comp.sys.amiga
Subject: profiler (5/5) p2a.asm
Message-ID: <1249@navajo.STANFORD.EDU>
Date: Tue, 23-Dec-86 14:26:24 EST
Article-I.D.: navajo.1249
Posted: Tue Dec 23 14:26:24 1986
Date-Received: Wed, 24-Dec-86 00:00:41 EST
Organization: Stanford University
Lines: 270

---cut here---
;:ts=8
;
;   (C) 1986 Radical Eye Software.  This code may be used and distributed
;   freely, so long as this notice stays in it and the banner messages
;   are unchanged except for the version notices.  Written by Tomas Rokicki
;   on December 19 through December 21 1986.
;
;   This is the assembly language source for the second phase of the
;   profiler.  It contains a vertical retrace interrupt routine and a
;   trap routine.
;
	cseg
;
;   First, the interrupt routine which maintains the tick count.
;   All `$123456's are stuffed with absolute addresses within the
;   C routine.
;
	public	_int_rout
_int_rout
	add.l	#$100,$123456
	jmp	$fc108c
;
;   Now we have the trap routine; this can get entertaining.  First,
;   we save a bunch of registers, and then load the global vector.
;   It's format (from p2.c) is:
;
;          struct tstruct {
;             short running ;     0
;             char *tick_add ;    2
;             char *dat_add ;     6
;             char *stack ;       10
;             char *stack_top ;   14
;             char *stack_bot ;   18
;             short error ;       22
;             char *debug_ptr ;   24
;          } trap_glob ;          28
;
;   Error bits:
;      0   Stack underflow (increase memory!)
;      1   Unlink from different routine than linked
;
;   The dat_add array is organized as follows:
;          struct rout_stat {
;             short recursion_count ;  0
;             short data_offset ;      2
;             long invoke_count ;      4
;             long self ;              8
;             long children ;         12
;          } ;                        16
;
;   The stack we create will look like this:
;          struct stack_entry {
;             short routine_number ;   0
;             long start_time ;        2
;          } ;                         6
;
;   On every push (routine link), we push a new start_time and
;   routine_number, checking for recursion.  On every pop (routine
;   unlink), we check that the routine we are unlinking is the
;   proper one.  If it isn't, we complain for now.
;   Then, we calculate the elapsed time, add it to the 'child'
;   field and the 'self' field.  We then pop the stack, and subtract
;   the elapsed time from the exposed entry (if any.)  We have to
;   check the stack bounds at each step, and set the error flag if
;   something goes amiss.
;
	public	_trap_rout
_trap_rout
	movem.l	regs,-(sp)
	move.l	#$123456,a0
	move.l	2(a0),a1
;
;   Get and mask out the vpos
;
	move.l	$dff004,d1
	and.l	#$1ff00,d1
;
;   We loop around until we are sure the vpos didn't change
;   while we were busy.  This is necessary in case an interrupt
;   occurs during this piece of code; we can't mask the
;   interrupts since we are in user mode.
;
loop1
	move.l	(a1),d0
	move.l	$dff004,d2
	and.l	#$1ff00,d2
	cmp.l	d1,d2
	beq	okay1
	move.l	d2,d1
	bra	loop1
;
;   Now we check it against 5.  The values we use are
;   0..1 -> 254..255; 9..262 -> 0..253.  No other values
;   should be possible.
;
okay1
	lsr.l	#8,d1
	sub.w	#2,d1
	bcs	over3
over2
	sub.w	#7,d1
over3
	move.b	d1,d0
;
;   Now the time is in d0.  For now, we ignore it.  We
;   get the parameter following the trap instruction.
;
	move.l	2+regsize(sp),a1
	move.w	(a1)+,d1
;
;   Debug code; turn this off!
;
;	move.l	24(a0),a2
;	move.w	d1,(a2)+
;	move.l	a2,24(a0)
;	tst.w	d1
;
;   We now return you . . .
;
	bmi	unlink_rout
	bne	link_rout
;
;   The exit routine simply sets the done flag and then jumps into
;   the normal link routine.  What it should do, eventually, is
;   virtually unlink everything.  Especially since it will never
;   exit.  Yeah, that's what we do.  It gets a charge of zero.
;
exit_rout
	move.l	a1,2+regsize(sp)
	move.w	d1,(a0)
	lsl.w	#4,d1
	movem.l	d1/d4,-(sp)
	move.l	6(a0),a1
	move.l	10(a0),a2
	move.w	(a2),d1
;
;   Now we pop things, calculating the elapsed time.
;
unstack
	move.l	d0,d4
	sub.l	2(a2),d4
;
;   We add the elapsed time to both variables of the current procedure,
;   and subtract it from the self variable for the above procedure.
;
	add.l	d4,8(a1,d1.w)
	add.l	d4,12(a1,d1.w)
	move.w	6(a2),d1
;
;   This works because only if we've run off the end do we
;   have a zero here.
;
	beq	unstkd
	sub.l	d4,8(a1,d1.w)
	lea	6(a2),a2
	bra	unstack
unstkd
	lea	6(a2),a2
	move.l	a2,10(a0)
	movem.l	(sp)+,d1/d4
;
;   Finally, we do a link-style exit.
;
	move.w	2(a1,d1.w),d3
	movem.l	(sp)+,regs
	move.w	(sp)+,d2
	move.l	(sp)+,a1
	move	d2,sr
	move.l	a5,-(sp)
	move.l	a7,a5
	lea	(a7,d3.w),a7
	jmp	(a1)
;
;   This is the routine used for a link instruction.  We increment a
;   counter at the moment; that's all.
;
link_rout
	move.l	a1,2+regsize(sp)
	move.w	d1,(a0)
link_2
	lsl.w	#4,d1
	move.l	6(a0),a1
	add.l	#1,4(a1,d1.w)
;
;   Now we push a new entry onto the stack.
;
	move.l	10(a0),a2
	lea	-6(a2),a2
	cmp.l	18(a0),a2
	bcc	okay4
;
;   If there was an error, we simply overwrite
;   current entry.
;
	lea	6(a2),a2
	or.w	#1,22(a0)
okay4
	move.l	d0,2(a2)
	move.w	d1,(a2)
	move.l	a2,10(a0)
;
;   This is the exit code.
;
	move.w	2(a1,d1.w),d3
	movem.l	(sp)+,regs
	move.w	(sp)+,d2
	move.l	(sp)+,a1
	move	d2,sr
	move.l	a5,-(sp)
	move.l	a7,a5
	lea	(a7,d3.w),a7
	jmp	(a1)
;
;   An unlink puts us here.  For now, we simply exit; nothing fancy.
;   We skip over the return address from the interrupt and just return
;   directly to the calling routine.
;
unlink_rout
	move.l	a1,2+regsize(sp)
;
;   We get the stack pointer, and make sure we are unlinking from
;   the same routine we linked.
;
	lsl.w	#4,d1
	move.l	6(a0),a1
	move.l	10(a0),a2
	cmp.w	(a2),d1
	beq	okay5
;
;   If it's not okay, we pretend it is for now, but only after
;   setting the appropriate error bit.
;
	or.w	#2,22(a0)
okay5
;
;   Now we pop things, calculating the elapsed time.
;
	sub.l	2(a2),d0
	lea	6(a2),a2
	move.l	a2,10(a0)
;
;   We add the elapsed time to both variables of the current procedure,
;   and subtract it from the self variable for the above procedure.
;
	add.l	d0,8(a1,d1.w)
	add.l	d0,12(a1,d1.w)
	move.w	(a2),d1
;
;   If we are at the end, we don't do this.
;
	beq	over7
	sub.l	d0,8(a1,d1.w)
;
;   Exit code for unlink.
;
over7
	movem.l	(sp)+,regs
	move.w	(sp)+,d3
	move.l	(sp)+,a1
	move	d3,sr
	unlk	a5
	rts
;
;   Registers used.
;
regs	reg	a0-a2/d0-d1
regsize	equ	20
	end
---cut here---