; EX12_3.asm
;
; Ex12_3.asm
;
; This program demonstrates different parameter passing methods.  
; It corresponds to the following (pseudo) Pascal code:
;
;
; program main;
; var	i:integer;
;	a:array[0..255] of integer;
;	b:array[0..255] of unsigned;
;
; function LTint(int1, int2:integer):boolean;
; begin
;	LTint := int1 < int2;
; end;
;
; procedure SwapInt(var int1, int2:integer);
; var temp:integer;
; begin
;	temp := int1;
;	int1 := int2;
;	int2 := temp;
; end;
;
; function LTunsigned(uns1, uns2:unsigned):boolean;
; begin
;	LTunsigned := uns1 < uns2;
; end;
;
; procedure SwapUnsigned(uns1, uns2:unsigned);
; var temp:unsigned;
; begin
;	temp := uns1;
;	uns1 := uns2;
;	uns2 := temp;
; end;
;
; (* The following is a simple Bubble sort that will sort arrays containing *)
; (* arbitrary data types.                                                  *)
;
; procedure sort(data:array; elements:integer; function LT:boolean; procedure swap);
; var i,j:integer;
; begin
;
;	for i := 0 to elements-1 do
;	    for j := i+1 to elements do
;		if (LT(data[j], data[i])) then swap(data[i], data[j]);
; end;
;
;
; begin
;
;	for i := 0 to 255 do A[i] := 128-i;
;	for i := 0 to 255 do B[i] := 33000-i;
;	sort(A, 256, LTint, SwapInt);
;	sort(B, 256, LTunsigned, SwapUnsigned);
;
;	for i := 0 to 255 do
;	begin
;		if (i mod 8) = 0 then writeln;
;		write(A[i]:7);
;	end;
;
;	for i := 0 to 255 do
;	begin
;		if (i mod 8) = 0 then writeln;
;		write(B[i]:7);
;	end;
;
; end;

		.xlist
		include 	stdlib.a
		includelib	stdlib.lib
		.list

		.386
		option		segment:use16

wp		textequ		<word ptr>


dseg		segment	para public 'data'
A		word	256 dup (?)
B		word	256 dup (?)
dseg		ends



cseg		segment	para public 'code'
		assume	cs:cseg, ds:dseg, ss:sseg


; function LTint(int1, int2:integer):boolean;
; begin
;	LTint := int1 < int2;
; end;
;
; LTint's activation record looks like this:
;
;	|----------------|
;	|      int1      |
;	|----------------|
;	|      int2      |
;	|----------------|
;	| return address |
;	|----------------|
;	|    old BP      |<- SP, BP
;	|----------------|

int1		textequ	<word ptr [bp+6]>
int2		textequ	<word ptr [bp+4]>

LTint		proc	near
		push	bp
		mov	bp, sp
		
		mov	ax, int1	;Compare the two parameters
		cmp	ax, int2	; and return true if int1<int2.
		setl	al		;Signed comparison here.
		mov	ah, 0		;Be sure to clear H.O. byte.

		pop	bp
		ret	4
LTint		endp


; Swap's activation record looks like this:
;
;	|----------------|
;	|     Address    |
;	|---    of    ---|
;	|      int1      |
;	|----------------|
;	|     Address    |
;	|---    of    ---|
;	|      int2      |
;	|----------------|
;	| return address |
;	|----------------|
;	|    old BP      |<- SP, BP
;	|----------------|
;
; The temporary variable is kept in a register.
;
; Note that swapping integers or unsigned integers can be done
; with the same code since the operations are identical for
; either type.
;
; procedure SwapInt(var int1, int2:integer);
; var temp:integer;
; begin
;	temp := int1;
;	int1 := int2;
;	int2 := temp;
; end;
;
; procedure SwapUnsigned(uns1, uns2:unsigned);
; var temp:unsigned;
; begin
;	temp := uns1;
;	uns1 := uns2;
;	uns2 := temp;
; end;
;

int1		textequ	<dword ptr [bp+8]>
int2		textequ	<dword ptr [bp+4]>

SwapInt		proc	near
		push	bp
		mov	bp, sp
		push	es
		push	bx

		les	bx, int1		;Get address of int1 variable.
		mov	ax, es:[bx]		;Get int1's value.
		les	bx, int2		;Get address of int2 variable.
		xchg	ax, es:[bx]		;Swap int1's value with int2's

		les	bx, int1		;Get the address of int1 and
		mov	es:[bx], ax		; store int2's value there.

		pop	bx
		pop	es
		pop	bp
		ret	8
SwapInt		endp



; LTunsigned's activation record looks like this:
;
;	|----------------|
;	|      uns1      |
;	|----------------|
;	|      uns2      |
;	|----------------|
;	| return address |
;	|----------------|
;	|    old BP      |<- SP, BP
;	|----------------|
;
; function LTunsigned(uns1, uns2:unsigned):boolean;
; begin
;	LTunsigned := uns1 < uns2;
; end;

uns1		textequ	<word ptr [bp+6]>
uns2		textequ	<word ptr [bp+4]>

LTunsigned	proc	near
		push	bp
		mov	bp, sp
		
		mov	ax, uns1	;Compare uns1 with uns2 and
		cmp	ax, uns2	; return true if uns1<uns2.
		setb	al		;Unsigned comparison.
		mov	ah, 0		;Return 16-bit boolean.

		pop	bp
		ret	4
LTunsigned	endp



; Sort's activation record looks like this:
;
;	|----------------|
;	|     Data's     |
;	|---          ---|
;	|    Address     |
;	|----------------|
;	|   Elements     |
;	|----------------|
;	|      LT's      |
;	|---          ---|
;	|    Address     |
;	|----------------|
;	|     Swap's     |
;	|---          ---|
;	|    Address     |
;	|----------------|
;	| return address |
;	|----------------|
;	|    old BP      |<- SP, BP
;	|----------------|
;
; procedure sort(data:array; elements:integer; function LT:boolean; procedure swap);
; var i,j:integer;
; begin
;
;	for i := 0 to elements-1 do
;	    for j := i+1 to elements do
;		if (LT(data[j], data[i])) then swap(data[i], data[j]);
; end;


data		textequ	<dword ptr [bp+10]>
elements	textequ	<word ptr [bp+8]>
funcLT		textequ	<word ptr [bp+6]>
procSwap	textequ	<word ptr [bp+4]>

i		textequ	<word ptr [bp-2]>
j		textequ	<word ptr [bp-4]>

sort		proc	near
		push	bp
		mov	bp, sp
		sub	sp, 4
		push	es
		push	bx

		mov	i, 0
ForILp:		mov	ax, i			;Compare with elements-1.
		inc	ax			;Do this by incrementing I
		cmp	ax, Elements		; and comparing with Elements.
		jae	IDone

		mov	j, ax			;Put i+1 into J.
ForJLp:		mov	ax, j
		cmp	ax, Elements
		jae	JDone

		les	bx, data		;Push the value of
		mov	si, j			; data[j] onto the
		add	si, si			; stack.
		push	es:[bx+si]

		les	bx, data		;Push the value of
		mov	si, i			; data[i] onto the
		add	si, si			; stack.
		push	es:[bx+si]

		call	FuncLT			;See if data[i] < data[j]
		cmp	ax, 0			;Test boolean result.
		je	NextJ

		push	wp data+2		;Pass data[i] by reference.
		mov	ax, i
		add	ax, ax
		add	ax, wp data
		push	ax

		push	wp data+2		;Pass data[j] by reference.
		mov	ax, j
		add	ax, ax
		add	ax, wp data
		push	ax

		call	ProcSwap

NextJ:		inc	j
		jmp	ForJLp

JDone:		inc	i
		jmp	ForILp

IDone:		pop	bx
		pop	es
		mov	sp, bp
		pop	bp
		ret	10
sort		endp




		
; Main's activation record looks like this:
;
;	| return address |<- SP, BP
;	|----------------|
;
; begin
;
;	for i := 0 to 255 do A[i] := 128-i;
;	for i := 0 to 255 do B[i] := 33000-i;
;	sort(A, 256, LTint, SwapInt);
;	sort(B, 256, LTunsigned, SwapUnsigned);
;
;	for i := 0 to 255 do
;	begin
;		if (i mod 8) = 0 then writeln;
;		write(A[i]:7);
;	end;
;
;	for i := 0 to 255 do
;	begin
;		if (i mod 8) = 0 then writeln;
;		write(B[i]:7);
;	end;
;
; end;

Main		proc
		mov	ax, dseg	;Initialize the segment registers.
		mov	ds, ax
		mov	es, ax

; Note that the following code merges the two initialization for loops
; into a single loop.

		mov	ax, 128
		mov	bx, 0
		mov	cx, 33000
ForILp:		mov	A[bx], ax
		mov	B[bx], cx
		add	bx, 2
		dec	ax
		dec	cx
		cmp	bx, 256*2
		jb	ForILp

		push	ds			;Seg address of A
		push	offset A		;Offset of A
		push	256			;# of elements in A
		push	offset LTint		;Address of compare routine
		push	offset SwapInt		;Address of swap routine
		call	Sort


		push	ds			;Seg address of B
		push	offset B		;Offset of B
		push	256			;# of elements in A
		push	offset LTunsigned	;Address of compare routine
		push	offset SwapInt		;Address of swap routine
		call	Sort

; Print the values in A.

		mov	bx, 0
ForILp2:	test	bx, 0Fh			;See if (I mod 8) = 0
		jnz	NotMod			; note: BX mod 16 = I mod 8.
		putcr
NotMod:		mov	ax, A[bx]
		mov	cx, 7
		putisize
		add	bx, 2
		cmp	bx, 256*2
		jb	ForILp2

; Print the values in B.

		putcr

		mov	bx, 0
ForILp3:	test	bx, 0Fh			;See if (I mod 8) = 0
		jnz	NotMod2			; note: BX mod 16 = I mod 8.
		putcr
NotMod2:	mov	ax, B[bx]
		mov	cx, 7
		putusize
		add	bx, 2
		cmp	bx, 256*2
		jb	ForILp3

Quit:		ExitPgm			;DOS macro to quit program.
Main		endp



cseg            ends


sseg		segment	para stack 'stack'
stk		word	256 dup (0)
sseg		ends

zzzzzzseg	segment	para public 'zzzzzz'
LastBytes	db	16 dup (?)
zzzzzzseg	ends
		end	Main
