	.include "DS.S"
#-----------------------------------------------
#	A B S T R A C T  S T R U C T U R E S
#-----------------------------------------------
#-----------------------------------------------
#	S T A T I C   V A R I A B L E S
#-----------------------------------------------
	.data
D.t0:	.int	0				# initial timestamp in usecs
D.semP:	.int	0				# -->semaphore for debug output
	.globl	D.prgNameP
D.prgNameP:
	.int	0				# -->prog name
#-----------------------------------------------
#	D E B U G   I N I T
#-----------------------------------------------
# initialize static debug vars
	ARGS
 	DS	prgP				# -->program name
# returns:	nothing
	PROLOC
	EPILOC
#-----------------------------------------------
	.text
	.global D.init
D.init:
	PROLOG
	push	prgP(bp)
	call	strlen
	inc	a
	push	a
	call	malloc
	mov	a, D.prgNameP			# save -->prog name for debugging
	push	prgP(bp)
	push	a
	call	strcpy
	movl	$0, D.t0
	call	D.getTs				# get actual time - t0 = actual time
	mov	a, D.t0				# set t0 to actual time

	jmp	3f
	push	$0
	push	$t
	call	gettimeofday			# get initial timestamp t0
	cmp	$0, a
	jz	0f
	ERR	"gettimeofday"
0:	lea	t, b				# compute (1000000*secs+usecs)
	mov	secs(b), c
	mov	$1000000, a
	mul	c				# 1000000*secs
	add	usecs(b), a			# 1000000*secs+usecs
	movl	a, D.t0				# save low 32 bits of timestamp in t0
3:
	push	$0				# allocate semaphore for debug output
	push	$-1
	push	$0x21				# PROT_READ | PROT_WRITE
	push	$0x03				# MAP_SHARED | MAP_ANONYMOUS
	push	$16				# semaphore size
	push	$0
	call	mmap				# get shared storage for semaphore
	cmp	$-1, a
	jne	0f
	ERR	"mmap"
0:	mov	a, D.semP			# save -->semaphore

	push	$1				# initial semaphore value
	push	$1				# semaphore shared between processes
	pushl	D.semP
	call	sem_init			# initialize semaphore
	cmp	$0, a
	jz	0f
	ERR	"sem_init of debug semaphore"
0:
	EPILOG
#-----------------------------------------------
#	S E T   D E B U G   I D
#-----------------------------------------------
# sets debug ID according to format
	ARGS
 	DS	deP 				# -->Debug instance
	DS	argc				# # of values to be put into deb ID
	DS	formP				# -->format
#	...					# values
# returns:	nothing
	PROLOC
	EPILOC
#-----------------------------------------------
	.global D.setId
D.setId:
	PROLOG
# format debug ID
	mov	argc(bp), c			# no. of values
0:	mov	formP(bp,c,4), a		# push values and format
	push	a
	dec	c
	jns	0b				# iterate on values
	pushl	$D.idL				# max deb ID len
	mov	deP(bp), b			# -->Debug instance
	lea	D.id(b), a			# -->DebId
	push	a
	call	snprintf			# construct DebId
	cmp	$0, a
	jnl	0f
	ERR	"DEBID snprintf"
0:
	LOG	6, "debid '%s' set", 1
	EPILOG
#-----------------------------------------------
#	P R I N T   D E B U G   M S G
#-----------------------------------------------
# outputs to stderr the synchronized debug msg with time diff from program start
# 	on appripriate debug level, flushes stderr
	ARGS
	ac = 40
 	DS	deP 				# -->Debug instance
 	DS	level				# msg debug level
	DS	argc				# # of values to be used in msg
	DS	form				# -->format
#	...					# values
# returns:	nothing
	PROLOC
	ac = 0
	EPILOC
#-----------------------------------------------
	.global D.log
D.log:
	PROLOG

	mov	C.csP, c
	mov	level(bp), a			# msg debug level
	cmp	C.debMaxLev(c), a		# max debug level >= msg debug level ?
	jg	3f				# nothing to print, leave
	cmp	$7, C.debMaxLev(c)		# on max debug level = 7 print level 7 only
	jne	0f
	cmp	$7, a				# msg debug level = 7 ?
	jne	3f
# prepare output string of msg
0:	mov	argc(bp), c			# no. of values
0:	mov	form(bp,c,4), a			# copy values and format
	push	a
	dec	c
	jns	0b
	push	$D.msgL				# msg buffer len
	mov	deP(bp), b			# -->Debug instance
	lea	D.msg(b), a			# -->msg buffer
	push	a
	call	snprintf			# construct msg in buffer
	cmp	$0, a
	jnl	0f
	ERR	"LOG snprintf"
# synchronize with other tasks
0:	pushl	D.semP
	call	sem_wait			# synchronize
	cmp	$0, a
	jz	0f
	ERR	"LOG sem_wait"
# get timestamp
0:	call	D.getTs				# time from beg of program in usecs
# print debug msg
	mov	deP(bp), b			# -->Debug instance
	lea	D.msg(b), c			# -->msg text
	push	c
	lea	D.id(b), c			# -->instance debug ID
	push	c
	push	a				# tdiff in usecs
	push	$1f
	push	stderr
	call	fprintf
	jmp	2f
1:	.ascii	"%09u %s: %s\n\0"
# flush stderr
2:	push	stderr
	call	fflush				# flush stderr
# free semaphore
	pushl	D.semP
	call	sem_post			# free semaphore
	cmp	$0, a
	jz	3f
	ERR	"LOG sem_post"
3:
	EPILOG
#-----------------------------------------------
#	G E T   T I M E S T A M P   I N   U S E C S
#-----------------------------------------------
# returns timestamp in usecs from beg of program
# returns:	int value
	PROLOC
	DL	t, timevalL			# timestamp buffer
	EPILOC
#-----------------------------------------------
	.global D.getTs
D.getTs:
	PROLOG
	push	$0
	lea	t(bp), b			# -->timeval buffer
	push	b
	call	gettimeofday
# compute time delta from program start = t-t0 in usecs
# tdiff = (1000000*ts.secs+ts.usecs)-t0
	lea	t(bp), b			# actual timestamp
	mov	secs(b), c			# t.secs
	mov	$1000000, a
	mul	c				# 1000000*t.secs
	add	usecs(b), a			# 1000000*t.secs+t.usecs
	sub	D.t0, a				# 1000000*t.secs+t.usecs-t0
	EPILOG_R
#-----------------------------------------------
#	S U B R O U T I N E S   L I S T
#-----------------------------------------------
# print subroutines names and addresses
# localize address from env ADDR= in subroutine
	PROLOC
	DL	wAddr				# wanted addr
	EPILOC
#-----------------------------------------------
	.global	 D.subr
D.subr:
	PROLOG
	movl	$0, wAddr(bp)
	pushl	$0f
	call	getenv				# get env ADDR
	lea	4(sp), sp
	jmp	1f
0:	.ascii "ADDR\0"
1:	cmp	$0, a
	jz	0f				# no addr wanted
	pushl	$16
	pushl	$0
	push	a
	call	strtol				# convert str to hex
	lea	12(sp), sp
	mov	a, wAddr(bp)			# searched addr
0:
	pushl	$0				# end of list
	SUBRLIST				# print and push list of subroutines
	cmp	$0, wAddr(bp)			# address wanted ?
	je	D.subrR
	mov	wAddr(bp), d
	mov	sp, b				# -->beg of subr list
	xor	a, a
	jmp	1f
0:	lea	8(b), b
1:	cmpl	$0, (b)				# end of list ?
	je	2f				# yes
	cmp	4(b), d				# -->subr > wanted addr ?
	jb	0b				# yes, next
	cmp	4(b), a				# -->subr > last found ?
	jnb	0b				# no, next
	mov	(b), c				# get subr name
	mov	4(b), a				# get subr addr
	jmp	0b				# next
2:	test	a, a
	jnz	1f
	push	d
	push	$0f
	push	stderr
	call	fprintf
	jmp	D.subrR
0:	.ascii	"addr %p not found in subroutines\n\0"
1:	sub	a, d
	push	d				# offset in subr
	push	c				# subroutine name
	pushl	wAddr(bp)			# wanted addr
	push	$0f
	push	stderr
	call	fprintf
	jmp	D.subrR
0:	.ascii	"searched addr %p in subroutine %s at offset %x\n\0"
D.subrR:
	EPILOG
#-----------------------------------------------
	.end
