CSC231 Homework 8 Solution Program 2010

From dftwiki3
Revision as of 19:40, 21 November 2010 by Thiebaut (talk | contribs)
Jump to: navigation, search

--D. Thiebaut 23:35, 21 November 2010 (UTC)




;;; ; File: hw8.asm
;;; ; Author: Tiffany Q. Liu
;;; ; Acct: 231a-ac
;;; ; Date: November 17, 2010
;;; ; Desc: Programs Conway's Game of Life in one dimension. Starts with a 
;;; ;       generation containing 70 cells. Each cell can either be dead (0 or 
;;; ;       '.') or alive (1 or '@'). The next generation of cells is determined
;;; ;       by a rule, which states that a cell is alive when it had one 
;;; ;       neighbor cell that was alive in the previous generation and a cell 
;;; ;       is dead when it either had two dead neighbor cells (underpopulation)
;;; ;       in the previous generation or two alive neighbor cells 
;;; ;       (overpopulation) in the previous generation. This program prints out
;;; ;       20 generations of 70 cells, one above the next, one line at a time.
;;; ;       The program utilizes the stack to pass parameters and return values
;;; ;       between functions.
;;; ;
;;; ; to assemble and run:
;;; ;
;;; ;     nasm -f elf -F  stabs hw8.asm
;;; ;     ld -melf_i386 -o hw8 hw8.o
;;; ;     ./hw8
;;; ; 
;;; ; Output:
;;; ; .@...@..@@@@..@@.@@@.@@....@@..@...@..@@@@..@@.@@@.@@....@@..@...@..@@
;;; ; @.@.@.@@@..@@@@@.@.@.@@@..@@@@@.@.@.@@@..@@@@@.@.@.@@@..@@@@@.@.@.@@@@
;;; ; ......@.@@@@...@.....@.@@@@...@.....@.@@@@...@.....@.@@@@...@.....@..@
;;; ; .....@..@..@@.@.@...@..@..@@.@.@...@..@..@@.@.@...@..@..@@.@.@...@.@@.
;;; ; ....@.@@.@@@@....@.@.@@.@@@@....@.@.@@.@@@@....@.@.@@.@@@@....@.@..@@@
;;; ; ...@..@@.@..@@..@....@@.@..@@..@....@@.@..@@..@....@@.@..@@..@...@@@.@
;;; ; ..@.@@@@..@@@@@@.@..@@@..@@@@@@.@..@@@..@@@@@@.@..@@@..@@@@@@.@.@@.@..
;;; ; .@..@..@@@@....@..@@@.@@@@....@..@@@.@@@@....@..@@@.@@@@....@...@@..@.
;;; ; @.@@.@@@..@@..@.@@@.@.@..@@..@.@@@.@.@..@@..@.@@@.@.@..@@..@.@.@@@@@.@
;;; ; ..@@.@.@@@@@@@..@.@....@@@@@@..@.@....@@@@@@..@.@....@@@@@@....@...@..
;;; ; .@@@...@.....@@@...@..@@....@@@...@..@@....@@@...@..@@....@@..@.@.@.@.
;;; ; @@.@@.@.@...@@.@@.@.@@@@@..@@.@@.@.@@@@@..@@.@@.@.@@@@@..@@@@@.......@
;;; ; @@.@@....@.@@@.@@...@...@@@@@.@@...@...@@@@@.@@...@...@@@@...@@.....@.
;;; ; @@.@@@..@..@.@.@@@.@.@.@@...@.@@@.@.@.@@...@.@@@.@.@.@@..@@.@@@@...@.@
;;; ; @@.@.@@@.@@....@.@.....@@@.@..@.@.....@@@.@..@.@.....@@@@@@.@..@@.@...
;;; ; @@...@.@.@@@..@...@...@@.@..@@...@...@@.@..@@...@...@@....@..@@@@..@..
;;; ; @@@.@....@.@@@.@.@.@.@@@..@@@@@.@.@.@@@..@@@@@.@.@.@@@@..@.@@@..@@@.@.
;;; ; @.@..@..@..@.@.......@.@@@@...@.....@.@@@@...@.....@..@@@..@.@@@@.@..@
;;; ; ...@@.@@.@@...@.....@..@..@@.@.@...@..@..@@.@.@...@.@@@.@@@..@..@..@@.
;;; ; ..@@@.@@.@@@.@.@...@.@@.@@@@....@.@.@@.@@@@....@.@..@.@.@.@@@.@@.@@@@@
;;; ; -------------------------------------------------------------------
		
	EXIT    equ             1
	WRITE   equ             4
	STDOUT  equ             1

;;;  ------------------------------------------------------------
;;;  data areas
;;;  ------------------------------------------------------------

	section	.data
lifeCh	db	' '			; character to print for a cell
saveCnt	dd	0			; used to save counter from ecx
lf	db	0x0a			; linefeed character
N	dd	70			; # of cells per generation
numGen	dd	20			; # of generations to compute & print
x	dd	53			; used for pseudo-random # generation
rule	db	'.', '@'		; array used to determine the character 
					; to print based on the value in the 
					; cell (0 - '.'dead, and 1 - '@' alive)
fate	db	0, 1, 0			; used to determine the fate of the cell
					; based on the # of neighbors it had in 
					; the previous generation (0 - 0, 1 - 0,
					;  0 - 0)

	section	.bss		
life	resb	70			; array holding current generation of 
					; life cells
	resb	1			; pad beginning with a dead cell
oldLife	resb	70			; temp array holding previous life cells 					; used to determine next generation
	resb	1			; pad end with a dead cell

;;;  ------------------------------------------------------------
;;;  code area
;;;  ------------------------------------------------------------

	section	.text
	global	_start

;;;  ---------------------------
;;;  main(): Initiates definition
;;;  of the first generation of 
;;;  cells and initiates printing 
;;;  and computing of 20 
;;;  generations.
;;;  ---------------------------
_start:
	push	dword[N]		; defFirstGen(N, *life): call to
	push	life			; function that defines the 
	call	defFirstGen		; 1st gen. of N cells in the array life

	push	dword[N]		; compPrintLife(N, *life, *oldLife, 
	push	life			;               numGen): call to 
	push	oldLife			; function that computes and prints N  
	push	dword[numGen]		; cells in array life for numGen of
	call	compPrintLife		; generations

;;;  exit()

	mov	eax, EXIT
	mov	ebx, 0
	int	0x80			; final system call

;;;  ---------------------------
;;;  defFirstGen(N, *life): 
;;;  Initializes the cells that 
;;;  are to be alive for the 1st 
;;;  generation in life with 1.
;;;  Life of a cell is determined
;;;  using pseudo-randomization. 
;;;  ---------------------------
defFirstGen:
	push	ebp			; save old ebp pointer
	mov	ebp, esp		; initialize new ebp pointer
	pushad				; push all registers

;;;  Macros: number of cells and pointer to the life array
%define dfg_numCell	dword[ebp + 12]
%define	dfg_life	dword[ebp + 8]

	mov	esi, dfg_life		; esi points to life array
	mov	ecx, dfg_numCell	; loop counter = number of cells

.for:
;;;  calculate pseudo-random
;;;  value x:
;;;     x = (x * 17) % 31
	xor	edx, edx	
	mov	eax, dword[x]
	mov	ebx, 17
	mul	ebx
	mov	ebx, 31
	div	ebx
	mov	dword[x], edx

;;;  convert pseudo-random 
;;;  number x to either 0 or 1
;;;  by taking the mod of 2
	xor	edx, edx	
	mov	eax, dword[x]
        and   al, 1
	mov	byte[esi], al
	inc	esi
	loop	.for

	popad				; restore registers
	pop	ebp			; restore old ebp pointer
	ret	2*4			; return with 2 paramemters popped from 
					; stack

;;;  ---------------------------
;;;  compPrintLife(N, *life, 
;;;                *oldLife, 
;;;                numGen): 
;;;  Computes and print numGen
;;;  of generation with N cells
;;;  per generation. The current
;;;  generation to compute and 
;;;  print is stored in the life
;;;  array and the previous 
;;;  generation is stored 
;;;  temporarily in oldLife to
;;;  compute the current 
;;;  generation.
;;;  ---------------------------
compPrintLife:
	push	ebp			; save old ebp pointer
	mov	ebp, esp		; initialize new ebp pointer
	pushad				; push all registers

;;;  Macros: number of cells, pointer to life array, pointer to oldLife array,
;;;          and number of generations
%define	cpl_numCell	dword[ebp + 20]
%define	cpl_life	dword[ebp + 16]
%define	cpl_oldLife	dword[ebp + 12]
%define	cpl_numGen	dword[ebp + 8]

	mov	ecx, cpl_numGen		; loop counter = # of generations	
	mov	esi, cpl_life		; esi points to life array
	mov	edi, cpl_oldLife	; edi points to oldLife array
	mov	eax, cpl_numCell	; eax <- number of cells
.for:	
	push	eax			; printGen(N, *life): calls function to
	push	esi			; print current generation of N cells in
	call	printGen		; life array

	push	eax			; compNextGen(N, *life, *oldLife): call
	push	esi			; function to compute next generation of
	push	edi			; N cells in life array
	call	compNextGen
	loop	.for
	
	popad				; restore registers
	pop	ebp			; restore old ebp pointer
	ret	4*4			; return with 4 parameters popped from 
					; stack

;;;  ---------------------------
;;;  printGen(N, *life): 
;;;  Prints the current generation
;;;  of N cells in the life array 
;;;  by converting the number in
;;;  each cell with its 
;;;  corresponding character 
;;;  defined by the rule array.
;;;  ---------------------------
printGen:
	push	ebp			; save old ebp pointer
	mov	ebp, esp		; intialize new ebp pointer
	pushad				; push all registers

;;;  Macros: number of cells and pointer to life array
%define pg_numCell	dword[ebp + 12]
%define	pg_life		dword[ebp + 8]

	mov	ecx, pg_numCell		; loop counter = number of cells
	mov	esi, pg_life		; edi points to life array
.for:
	mov	dword[saveCnt], ecx	; save loop counter to saveCnt
	mov	eax, WRITE		; prepare to print
	xor	ebx, ebx		; clear out ebx
	xor	edx, edx		; clear out edx
	mov	bl, byte[esi]		; bl <- value from life array (0 or 1)
	mov	dl, byte[rule + ebx]	; dl <- converted character ('.' or '@')
	mov	byte[lifeCh], dl	; lifeCh <- character
	mov	ebx, STDOUT		; prepare to print
	mov	ecx, lifeCh		; ecx <- pointer to lifeCh
	mov	edx, 1			; length of string to print = 1 char
	int 	0x80			; print character
	inc	esi			; esi points to next item in life array
	mov	ecx, dword[saveCnt]	; restore loop counter to ecx
	loop	.for

	mov	eax, WRITE		; print linefeed character at the end of
	mov	ebx, STDOUT		; each generation of cells
	mov	ecx, lf
	mov	edx, 1
	int	0x80

	popad				; restore registers
	pop	ebp			; restore old ebp pointer
	ret	2*4			; return with 2 parameters popped from
					; stack

;;;  ---------------------------
;;;  compNextGen(N, *life, *oldLife): 
;;;  Computes the next generation
;;;  of N cells. First saves the
;;;  previous generation in 
;;;  oldLife. Then uses oldLife 
;;;  to compute number of live 
;;;  neighbor cells in previous 
;;;  generation. Then each cell
;;;  is either going to be dead
;;;  or alive in the current 
;;;  generation based on the 
;;;  number of neighbors it had
;;;  in the previous generation 
;;;  and the fate array.
;;;  ---------------------------
compNextGen:
	push	ebp			; save old ebp pointer
	mov	ebp, esp		; intialize new ebp pointer
	pushad				; push registers

;;;  Macros: number of cells, pointer to life array, pointer to oldLife array,
;;;          number of neighbors for a current cell
%define	cng_numCell	dword[ebp + 16]
%define	cng_life	dword[ebp + 12]
%define	cng_oldLife	dword[ebp + 8]
%define	cng_numNeigh	dword[ebp - 36]
	
	mov	ecx, cng_numCell	; loop counter = number of cells
	mov	esi, cng_life		; esi points to life array
	mov	edi, cng_oldLife	; edi points to oldLife array
	
	push	ecx			; savePastLife(N, *life, *oldLife):
	push	esi			; calls function to save values of N
	push	edi			; cells in life array to oldLife array
	call	savePastLife
	
	push 	eax			; push dummy variable to stack to store
					; number of neighbors
.for:
	push	edi			; compNumNeighbors(*oldLife): calls
	call	compNumNeighbors	; function to compute number of 
					; neighbors the current cells had in 
					; previous generation

	mov	ebx, cng_numNeigh	; ebx <- number of neighbors
	mov	al, byte[fate + ebx]	; determine whether cell is dead or 
	mov	byte[esi], al		; alive in next generation using 
					; numNeigh and fate array
	inc	esi			; esi points to next cell in life 
	inc	edi			; edi points to next cell in oldLife
	loop	.for

	pop	eax			; pop numNeigh variable from stack
	popad				; restore registers
	pop	ebp			; restore old ebp pointer
	ret	3*4			; return with 3 parameters popped from
					; stack

;;;  ---------------------------
;;;  savePastLife(N, *life, *oldLife): 
;;;  Saves the cells from the   
;;;  previous generation by  
;;;  copying the values in the  
;;;  N cells of life to the N 
;;;  cells of oldLife.
;;;  ---------------------------
savePastLife:
	push	ebp			; save old ebp pointer
	mov	ebp, esp		; initialize new ebp pointer
	pushad				; push registers

;;;  Macros: number of cells, pointer to life array, pointer to oldLife array
%define	spl_numCell	dword[ebp + 16]
%define	spl_life	dword[ebp + 12]
%define spl_oldLife	dword[ebp + 8]
	
	mov	ecx, spl_numCell	; loop counter = number of cells
	mov	esi, spl_life		; esi points to life array
	mov	edi, spl_oldLife	; edi points to oldLife array

;;;  Copy every value in life array to oldLife array one cell at a time
.for:
	mov	al, byte[esi]
	mov	byte[edi], al 
	inc	esi
	inc	edi
	loop	.for	

	popad				; restore registers
	pop ebp				; restore old ebp pointer
	ret	3*4			; return with 3 parameters popped from
					; stack

;;;  ---------------------------
;;;  compNumNeighbors(
;;;        *currCellOfOldLife): 
;;;  Computes the number of 
;;;  neighbors to the current  
;;;  cell of oldLife by adding
;;;  the values in the cells to 
;;;  the left and right of the 
;;;  current cell. numNeigh
;;;  returned from function via
;;;  stack.
;;;  ---------------------------
compNumNeighbors:
	push	ebp			; save old ebp pointer
	mov	ebp, esp		; initialize new ebp pointer
	pushad				; push registers

;;;  Macros: number of neighbors, pointer to oldLife array
%define	cnn_numNeigh	dword[ebp + 12]
%define	cnn_oldLife	dword[ebp + 8]

	mov	esi, cnn_oldLife	; esi points to current cell in oldLife
	xor	eax, eax		; clear out eax
	mov	al, byte[esi - 1]	; al <- value of left neighbor
	add	al, byte[esi + 1]	; al <- al + value of right neighbor
	mov	cnn_numNeigh, eax	; numNeigh <- left neigh + right neigh

	popad				; restore registers
	pop	ebp			; restore old ebp pointer
	ret	1*4			; return with 1 parameter popped from 
					; stack