CSC231 Homework 8 Solution 2012

From dftwiki3
Revision as of 12:28, 13 November 2012 by Thiebaut (talk | contribs) (Problem #2)
Jump to: navigation, search

--D. Thiebaut 12:15, 13 November 2012 (EST)


Problem #1, Version 1

This version contains the complete code. Version 2 below separates the dumpRegs functions and main program into two files.

;;; ---------------------------------------------------------
;;; hw8aSol.asm
;;; D. Thiebaut
;;; 11/13/12
;;; This program supports several functions that allow the user
;;; to dump the contents of the main 6 registers (eax, ebx, ecx,
;;; edx, esi and edi) to the screen.  Great for debugging without
;;; a debugger.
;;;
;;; Typical output:
;;; 	+-----------------+
;;; 	| eax = 1234 5678 |
;;; 	| ebx = 55FF 55FF |
;;; 	| ecx = FEDC BA98 |
;;; 	| edx = 0000 0000 |
;;; 	| esi = 1111 2222 |
;;; 	| edi = 2222 3333 |
;;; 	+-----------------+
;;; 	+-----------------+
;;; 	| eax = 1234 5678 |
;;; 	| ebx = 55FF 55FF |
;;; 	| ecx = FEDC BA98 |
;;; 	| edx = 0000 0000 |
;;; 	| esi = 1111 2222 |
;;; 	| edi = 2222 3333 |
;;; 	+-----------------+
;;;
;;; To assemble, link and run:
;;;   nasm -f elf hw8aSol.asm
;;;   ld -melf_i386 hw8aSol.o -o hw8aSol
;;;   ./hw8aSol
;;; ---------------------------------------------------------

		section	.data
hex		db	"0123456789ABCDEF"
regs		db	"axbxcxdxsidi"
line		db	"+-----------------+", 10
string		db	"| exx = .... .... |", 10
lineLen 	equ	$-string
reg		equ	string+3
word1		equ	string+8

		section	.text
		global	_start

_start:

;;; Initialize the registers
		mov	eax, 0x12345678
		mov	ebx, 0x55FF55FF
		mov	ecx, 0xFEDCBA98
		mov	edx, 0x00000000
		mov	esi, 0x11112222
		mov	edi, 0x22223333

;;; dump them twice to verify that no registers gets modified...
	        call    dumpRegs
		call	dumpRegs


;;; exit back to OS
		mov	ebx, 0
		mov	eax, 1
		int	0x80

;;; ---------------------------------------------------------
;;; dumpRegs: dumps the contents of the 6 main registers (eax
;;; ebx, ecx, edx, esi and edi) in a box on the screen.
;;; the screen.  Does not modify any register
;;; ---------------------------------------------------------
dumpRegs:	pushad

;;; put all the registers to print in the stack.  The loop
;;; will pop each one, one at a time, once per loop.
	
		push	edi
		push	esi
		push	edx
		push	ecx
		push	ebx
		push	eax

;;; print top bar
		call	printBar
	
;;; prepare to loop 6 times (6 registers )
		mov	ecx, 6
		mov	esi, 0

.for		pop	ebx			;get value of register to convert from stack
		push	ecx			;save loop counter
		lea	eax, [regs + esi*2]	;get address of string representing register
	
		mov	ax, word [eax] 		;ax gets "ax" or "bx" or "cx" or ... "di"
		mov	word[reg], ax		;modify string with name of register
	
		mov	edx, word1 		;edx points to buffer where to store hex digits
						;ebx contains register to convert
		call 	storeDWord		;store hex equivalent of ebx in string
	
		mov	ecx, string 		;print the whole string
		mov	edx, lineLen
		call	printInt80
		inc	esi			;index into register names incremented
		pop	ecx			;get loop counter back
		loop	.for

;;; print bottom bar
		call 	printBar
	
		popad
		ret

;;; ---------------------------------------------------------
;;; storeDWord: gets
;;; 	ebx: register to convert
;;; 	edx: address where to put information
;;; ---------------------------------------------------------
		
storeDWord:	rol	ebx, 16			;bring most sig word in least sig word
		call	storeWord
	
		inc	edx			;make edx skip space in string
	
		rol	ebx, 16			;get lower byte back in least sig pos
		call	storeWord
		
		ret

;;; ---------------------------------------------------------
;;; storeWord: gets
;;;     bx: word to convert
;;; 	edx: address where to put information. edx incremented by 4
;;; ---------------------------------------------------------
storeWord:	rol	bx, 8			;put most sig byte of bx in lower position
		call	storeByte		;and convert it.  Store it in where edx 
						;points to. 
		rol	bx, 8			;same with lower nybble
		call	storeByte
		ret
	
;;; ---------------------------------------------------------
;;; storeByte: gets
;;;     bl: byte to convert
;;; 	edx: address where to store information.  edx incremented by 2 automatically
;;; ---------------------------------------------------------
storeByte:	push	ebx
		push	eax
	
		rol	bl, 4			;get upper nybble in lower position (LSB)
		mov	al, bl			;play with al now
		and	eax, 0x0000000F		;clear all but the least significant nybble
		add	eax, hex		;get ascii in hex array equivalentn to nybble
		mov	al, [eax] 		;hex digit now in bl
		mov	byte [edx], al		;store ascii in string
		inc	edx

		rol	bl, 4			;get lower nybble back
		mov	al, bl			;play with al
		and	eax, 0x0000000F
		add	eax, hex
		mov	al, [eax]
		mov	byte [edx], al
		inc	edx
	
		pop	eax
		pop	ebx
		ret
		
;;; ---------------------------------------------------------
;;; printInt80: prints on the screen the string whose address
;;; is in ecx and length in edx.
;;; does not modify registers
;;; ---------------------------------------------------------
printInt80:	push	eax
		push	ebx
	
		mov	eax, 4
		mov	ebx, 1
		int	0x80
	
		pop	ebx
		pop	eax
		ret
	
;;; ---------------------------------------------------------
;;; printBar: prints the horizontal bar
;;; does not modify registers
;;; ---------------------------------------------------------
printBar:	push	ecx
		push	edx
	
		mov	ecx, line
		mov	edx, lineLen
		call	printInt80
	
		pop	edx
		pop	ecx
		ret


Problem #1, Version 2

Main Program


;;; ---------------------------------------------------------
;;; hw8aSol2.asm
;;; D. Thiebaut
;;; 11/13/12
;;; This program uses the library dumpRegs.asm to dump 
;;; the contents of the main 6 registers (eax, ebx, ecx,
;;; edx, esi and edi) to the screen.  Great for debugging without
;;; a debugger.
;;;
;;; Typical output:
;;; 	+-----------------+
;;; 	| eax = 1234 5678 |
;;; 	| ebx = 55FF 55FF |
;;; 	| ecx = FEDC BA98 |
;;; 	| edx = 0000 0000 |
;;; 	| esi = 1111 2222 |
;;; 	| edi = 2222 3333 |
;;; 	+-----------------+
;;; 	+-----------------+
;;; 	| eax = 1234 5678 |
;;; 	| ebx = 55FF 55FF |
;;; 	| ecx = FEDC BA98 |
;;; 	| edx = 0000 0000 |
;;; 	| esi = 1111 2222 |
;;; 	| edi = 2222 3333 |
;;; 	+-----------------+
;;;
;;; To assemble, link and run:
;;;   nasm -f elf hw8aSol.asm
;;;   ld -melf_i386 hw8aSol.o -o hw8aSol
;;;   ./hw8aSol
;;; ---------------------------------------------------------

%include "dumpRegs.asm"
	
		section	.text
		global	_start

_start:

;;; Initialize the registers
		mov	eax, 0x12345678
		mov	ebx, 0x55FF55FF
		mov	ecx, 0xFEDCBA98
		mov	edx, 0x00000000
		mov	esi, 0x11112222
		mov	edi, 0x22223333

;;; dump them twice to verify that no registers gets modified...
	        call    dumpRegs
		call	dumpRegs


;;; exit back to OS
		mov	ebx, 0
		mov	eax, 1
		int	0x80


Library


;;; ---------------------------------------------------------
;;; dumpRegs.asm
;;; D. Thiebaut
;;; 11/13/12
;;; This libary supports several functions that allow the user
;;; to dump the contents of the main 6 registers (eax, ebx, ecx,
;;; edx, esi and edi) to the screen.  Great for debugging without
;;; a debugger.
;;;
;;; Typical output:
;;; 	+-----------------+
;;; 	| eax = 1234 5678 |
;;; 	| ebx = 55FF 55FF |
;;; 	| ecx = FEDC BA98 |
;;; 	| edx = 0000 0000 |
;;; 	| esi = 1111 2222 |
;;; 	| edi = 2222 3333 |
;;; 	+-----------------+
;;; Include in program as follows:
;;; 
;;; 
;;; %include "dumpRegs.asm"
;;; ---------------------------------------------------------

		section	.data
hex		db	"0123456789ABCDEF"
regs		db	"axbxcxdxsidi"
line		db	"+-----------------+", 10
string		db	"| exx = .... .... |", 10
lineLen 	equ	$-string
reg		equ	string+3
word1		equ	string+8

		section	.text

;;; ---------------------------------------------------------
;;; dumpRegs: dumps the contents of the 6 main registers (eax
;;; ebx, ecx, edx, esi and edi) in a box on the screen.
;;; the screen.  Does not modify any register
;;; ---------------------------------------------------------
dumpRegs:	pushad

;;; put all the registers to print in the stack.  The loop
;;; will pop each one, one at a time, once per loop.
	
		push	edi
		push	esi
		push	edx
		push	ecx
		push	ebx
		push	eax

;;; print top bar
		call	printBar
	
;;; prepare to loop 6 times (6 registers )
		mov	ecx, 6
		mov	esi, 0

.for		pop	ebx			;get value of register to convert from stack
		push	ecx			;save loop counter
		lea	eax, [regs + esi*2]	;get address of string representing register
	
		mov	ax, word [eax] 		;ax gets "ax" or "bx" or "cx" or ... "di"
		mov	word[reg], ax		;modify string with name of register
	
		mov	edx, word1 		;edx points to buffer where to store hex digits
						;ebx contains register to convert
		call 	storeDWord		;store hex equivalent of ebx in string
	
		mov	ecx, string 		;print the whole string
		mov	edx, lineLen
		call	printInt80
		inc	esi			;index into register names incremented
		pop	ecx			;get loop counter back
		loop	.for

;;; print bottom bar
		call 	printBar
	
		popad
		ret

;;; ---------------------------------------------------------
;;; storeDWord: gets
;;; 	ebx: register to convert
;;; 	edx: address where to put information
;;; ---------------------------------------------------------
		
storeDWord:	rol	ebx, 16			;bring most sig word in least sig word
		call	storeWord
	
		inc	edx			;make edx skip space in string
	
		rol	ebx, 16			;get lower byte back in least sig pos
		call	storeWord
		
		ret

;;; ---------------------------------------------------------
;;; storeWord: gets
;;;     bx: word to convert
;;; 	edx: address where to put information. edx incremented by 4
;;; ---------------------------------------------------------
storeWord:	rol	bx, 8			;put most sig byte of bx in lower position
		call	storeByte		;and convert it.  Store it in where edx 
						;points to. 
		rol	bx, 8			;same with lower nybble
		call	storeByte
		ret
	
;;; ---------------------------------------------------------
;;; storeByte: gets
;;;     bl: byte to convert
;;; 	edx: address where to store information.  edx incremented by 2 automatically
;;; ---------------------------------------------------------
storeByte:	push	ebx
		push	eax
	
		rol	bl, 4			;get upper nybble in lower position (LSB)
		mov	al, bl			;play with al now
		and	eax, 0x0000000F		;clear all but the least significant nybble
		add	eax, hex		;get ascii in hex array equivalentn to nybble
		mov	al, [eax] 		;hex digit now in bl
		mov	byte [edx], al		;store ascii in string
		inc	edx

		rol	bl, 4			;get lower nybble back
		mov	al, bl			;play with al
		and	eax, 0x0000000F
		add	eax, hex
		mov	al, [eax]
		mov	byte [edx], al
		inc	edx
	
		pop	eax
		pop	ebx
		ret
		
;;; ---------------------------------------------------------
;;; printInt80: prints on the screen the string whose address
;;; is in ecx and length in edx.
;;; does not modify registers
;;; ---------------------------------------------------------
printInt80:	push	eax
		push	ebx
	
		mov	eax, 4
		mov	ebx, 1
		int	0x80
	
		pop	ebx
		pop	eax
		ret
	
;;; ---------------------------------------------------------
;;; printBar: prints the horizontal bar
;;; does not modify registers
;;; ---------------------------------------------------------
printBar:	push	ecx
		push	edx
	
		mov	ecx, line
		mov	edx, lineLen
		call	printInt80
	
		pop	edx
		pop	ecx
		ret


Problem #2


;;; File: hw8b.asm
;;; Name: Emma Gould (edited by D. Thiebaut)
;;; Account: 231a-ap
;;; Due: 11/7/12
;;; Description: This program computes and displays the first 10 rows of Pascal's triangle.
;;; 01 00 00 00 00 00 00 00 00 00 
;;; 01 01 00 00 00 00 00 00 00 00 
;;; 01 02 01 00 00 00 00 00 00 00 
;;; 01 03 03 01 00 00 00 00 00 00 
;;; 01 04 06 04 01 00 00 00 00 00 
;;; 01 05 0A 0A 05 01 00 00 00 00 
;;; 01 06 0F 14 0F 06 01 00 00 00 
;;; 01 07 15 23 23 15 07 01 00 00 
;;; 01 08 1C 38 46 38 1C 08 01 00 
;;; 01 09 24 54 7E 7E 54 24 09 01 
;;;
;;; To assemble, link, and run: nasm -f elf -F stabs hw8b.asm ; ld -melf_i386  -o hw8b hw8b.o ; ./hw8b


;; -------------------------------
;; Data Section
;; -------------------------------
		section	.data
Pascal		db	0,0,0,0,0,0,0,0,0,0 	; Pascal array of 10 bytes

hexChars	db	"0123456789ABCDEF"	; list of hex characters
hexCharLen	equ	1			; length of a single character

space		db	"   "			; to space the characters of the array
spaceLen	equ	$-space			; length of space

newLine		db	10			; hex characters for new line
newLineLen	equ	$-newLine		; length of newLine

;; -------------------------------
;; Code Section
;; -------------------------------
		section	.text
		global	_start

;; -------------------------------
;; main program
;; -------------------------------
_start:
		mov	ebx, Pascal		; pass address of array in ebx
		call	init			; store 0 in Pascal array
						; and 1 in first cell

		mov	ecx, 10
for:		mov	ebx, Pascal		; pass address of array in ebx
		call	printArray		; print Pascal array

		mov	ebx, Pascal		; pass address of array
		call	nextLine		; compute next line of triangle

		loop	for

;;; exit
		mov	eax, 1
		mov	ebx, 0
		int	0x80

;; -------------------------------
;; function init takes the address
;; in ebx and puts one in the first byte
;; at that address and zero in the other nine
;; bytes that follow
;; -------------------------------
init:
		mov     byte[ebx], 1 		; move 1 into the first cell
		mov	edi, 1			; edi <- index = 1
		mov	ecx, 9			; ecx <- n = 9
for1:		mov	byte[ebx+edi], 0	; Fib[n] <- 0
		inc	edi			; index <- index + 1
		loop	for1			; n <- n - 1
		ret

;; -------------------------------
;; function printArray takes the address
;; in ebx and prints it a byte at a time
;; in hexadecimal (by passing it to printByte)
;; between the string "0x" and three spaces
;; with a new line at the very beginning and end
;; -------------------------------
printArray:
		push	ecx			; save ecx from main program
		call	printNewLine

		mov	ecx, 10			; n = 10
for3:
 		push	ecx			; save n
 		push	ebx			; save address of Pascal array

		pop	ebx 			; ebx <- address of Pascal array (from stack)
		pop	ecx			; ecx <- n (from stack)
		mov	edi, 10			; edi <- 10
		sub	edi, ecx		; edi <- 10 - n
		mov     eax, 0			; eax <- 0 (initialize)
		mov	al, byte[ebx+edi]	; al <- Pascal[10 - n]
		push	ecx			; save n
		push	ebx			; save address of Pascal array
		call	printByte		; print the byte in al in hexadecimal

		mov	ecx, space 		; ecx <- address of tab
		mov	edx, spaceLen		; edx <- length of tab
		mov	eax, 4			; print "	"
		mov	ebx, 1
		int	0x80

		pop	ebx			; ebx <- return address of Pascal array (from stack)
		pop	ecx			; ecx <- n (returned from stack)
		loop	for3			; n <- n - 1

		call	printNewLine

		pop	ecx			; ecx <- restore value from main program

		ret
;; -------------------------------
;; function printNewLine takes no
;; parameters and simply prints a new line
;; -------------------------------
printNewLine:
		push	ebx
		push	ecx
		mov	eax, 4
		mov	ebx, 1
		mov	ecx, newLine
		mov	edx, newLineLen
		int	0x80
		pop	ecx
		pop	ebx
		ret

;; -------------------------------
;; function printByte takes the value
;; stored in eax and print the two nybbles
;; (most significant first) in al
;; -------------------------------
printByte:
		rol	al, 4			; move most significant nybble to least
		push	eax			; save eax in stack
		and	eax, 0x0000000F		; get rid of upper nybble

		mov	ecx, hexChars	 	; ecx <- address of hexChars
		add	ecx, eax		; ecx <- address of hexChars + value of nybble
		mov	edx, hexCharLen		; edx <- length of a single character

		mov	eax, 4			; print the character
		mov	ebx, 1
		int	0x80

		pop	eax			; eax <- full hex value (from stack)
		rol	al, 4			; move lower nybble back to least significant
		and	eax, 0x0000000F		; get rid of upper nybble

		mov	ecx, hexChars	 	; ecx <- address of hexChars
		add	ecx, eax		; ecx <- address of hexChars + value of nybble
		mov	edx, hexCharLen		; edx <- length of a single character

		mov	eax, 4			; print the character
		mov	ebx, 1
		int	0x80

		ret

;; -------------------------------
;; function nextLine uses the address stored in ebx
;; to compute the next row of pascal's triangle
;; and stores it in the Pascal array
;; -------------------------------
nextLine:	push	ecx
		mov	ecx, 9			; ecx <- m = 9 (length of array - 1)
		mov	edi, 9			; edi <- n = 9 (length of array - 1)

for4:		mov	al, byte[ebx+edi] 	; al <- Pascal[n] (starting at the rightmost
						; number and working left)
		add	al, byte[ebx+edi-1]	; al <- Pascal[n-1]
		mov	byte[ebx+edi], al	; Fib[n] <- al
		dec	edi			; n = n - 1
		loop	for4			; m = m - 1

		pop	ecx
		ret