# ---------------------------------------------------------------
# doFir.s
#	Calculate and store a Finite Impulse Response averaging
#	for a list of integers.
# Takes 4 arguments: address of input int array, address of output
# int array, integer size of array, integer number of discrete
# values per window. Returns 0 indicating normal operation,
# or non-zero suggesting attention. (Examples: window size greater
# than list size, in which case the window size will be truncated
# to equal the list size, the response will be calculated as
# usual, and a non-zero value returned. This behavior is preceded
# by similar behavior applying to input list size greater than
# MAX_SIZE.)
# Caller is responsible for allocating 2 equally sized int arrays.
# "Input" array contains caller's data. "Output" array will be
# filled by the function. Unused "Output" array positions will
# acquire the value zero. "Input" array positions exceeding 
# the common size provided, will be ignored.
# ...............................................................
# calling sequence:
#	push integer window size
#	push integer number of list elements (common to both lists)
#	push base_address of output integer array
#	push base_address of input integer array
#	call	doFir
#	add 16 to stack pointer
# ...............................................................
# author: David Bozarth - 1 May 2004
# modified 1 May 2004
# ---------------------------------------------------------------
MAXSZ = 10
WORD = -4
TRUE = -1
FALSE = 0

# Stack frame
stkTop = intFirVal		# top-of-stack marker
intFirVal = intDxFir + WORD	# build a new output sum here
intDxFir = intDxData + WORD	# index of FIR (output) array
intDxData = blnAttn + WORD	# index of data (input) array 
blnAttn = basePtr + WORD	# abnormal condition -> return TRUE
basePtr = 0
rtnAddr = basePtr - WORD
intInPtr = rtnAddr - WORD	# input array base_address
intOutPtr = intInPtr - WORD	# output array base_address
intSize = intOutPtr - WORD	# common list size
intWin = intSize - WORD		# window size

	.text
	.align	4
	.globl	doFir
	
doFir:
	pushl	%ebp			# save caller's base pointer
	movl	%esp, %ebp		# establish our base pointer
	addl	$stkTop, %esp		# allocate local variable
	pushl	%ebx			# save registers
	pushl	%ecx
	pushl	%edx

	# initialize
	movl	$FALSE, blnAttn(%ebp)	# normal condition
	movl	intOutPtr(%ebp), %ebx	# clear output array
	movl	$0, %eax
clearLoop:
	cmpl	$MAXSZ, %eax
	jae	doneClear

	movl	$0, (%ebx, %eax, 4)
	incl	%eax
	jmp	clearLoop

doneClear:
	# range check
	cmpl	$MAXSZ, intSize(%ebp)	# if array too large,
	jbe	doneSize		# .. then truncate

	movl	$TRUE, blnAttn(%ebp)	# .. & set abnormal condition
	movl	$MAXSZ, intSize(%ebp)
doneSize:
	movl	intSize(%ebp), %eax
	cmpl	intWin(%ebp), %eax	# if window too large,
	jae	doneWin			# .. then truncate

	movl	$TRUE, blnAttn(%ebp)	# .. & set abnormal condition
	movl	%eax, intWin(%ebp)
		
	# process the signal data
doneWin:	
	movl	$0, %ecx		# FIR array index
firLoop:
	cmpl	intSize(%ebp), %ecx
	jae	doneFir			# for each FIR position

	movl	$0, intFirVal(%ebp)	# initialize its value to zero
	# inner loop setup
	movl	intInPtr(%ebp), %ebx	# data array base_address
	movl	$0, %edx		# zero -> data index register
dataLoop:
	cmpl	intWin(%ebp), %edx
	jae	doneData		# for each data position

	movl	%ecx, %eax		# FIR index
	addl	%edx, %eax		# add the 2 indexes
	cmpl	intSize(%ebp), %eax	# if (i+j) < intSize,
	jae	doneAdd			# .. then there is a data value
	
	movl	(%ebx, %eax, 4), %eax	# .. that contributes data[i+j]
	addl	%eax, intFirVal(%ebp)	# .. to current FIR value
doneAdd:
	incl	%edx			# point to next data cell
	jmp	dataLoop
	
doneData:
	pushl	intWin(%ebp)		# divide window size
	movl	intFirVal(%ebp), %eax	# check for negative FIR sum
	movl	$0x80000000, %edx
	andl	%eax, %edx
	cmpl	$0, %edx		# if sum is negative
	je	notNeg			# .. then extend the sign

	negl	%eax
	pushl	%eax			# lo word
	pushl	$-1			# hi word
	jmp	doneNeg
	
notNeg:	
	pushl	%eax			# lo word
	pushl	$0			# hi word
doneNeg:
	call	divInt			# quotient -> eax
	addl	$12, %esp
	movl	intOutPtr(%ebp), %ebx	# FIR array base_address	
	movl	%eax, (%ebx, %ecx, 4)	# store averaged value in FIR cell
	incl	%ecx			# point to next FIR cell
	jmp	firLoop

doneFir:
				
allDone:
	movl	blnAttn(%ebp), %eax	# return status flag		
	popl	%edx			# restore registers
	popl	%ecx
	popl	%ebx
	movl	%ebp, %esp		# restore stack pointer
	popl	%ebp			# restore caller's base pointer
	ret
