CSC231 Homework 10 Solution

From dftwiki3
Revision as of 12:29, 10 December 2008 by Thiebaut (talk | contribs) (New page: --~~~~ ---- <code><pre> ;;; hw10.asm ;;; John M. Schanck <jms07@hampshire.edu> ;;; Edited (commented) by D. Thiebaut ;;; ;;; Performs a binary search on an array of times and events ...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

--D. Thiebaut 17:29, 10 December 2008 (UTC)


;;;  hw10.asm
;;;  John M. Schanck <jms07@hampshire.edu> 
;;;  Edited (commented) by D. Thiebaut
;;;
;;;  Performs a binary search on an array of times and events
;;;  using the current time as the key, and prints the result.
;;;  The execution is limited to 20 seconds, after which the program  
;;;  stops.
;;;
;;;  The array of time events is stored at address "dates" in the data
;;;  section.
;;;
;;;  to assemble and run:
;;;      nasm -f elf -F stabs hw10.asm
;;;      ld -o hw10 hw10.o
;;;      ./hw10
;;;  ===========================================================

%assign SYS_EXIT   1
%assign SYS_WRITE  4
%assign SYS_TIME   78
%assign SYS_SLEEP  162

%assign STDIN      0
%assign STDOUT     1

    section .data
dates       dd      0
            db      'a'
esize       equ     $-dates ;; Size of each element
            dd      1
            db      'b'
            dd      2
            db      'r'
            dd      3
            db      'a'
            dd      4
            db      'c'
            dd      5
            db      'a'
            dd      6
            db      'd'
            dd      7
            db      'a'
            dd      8
            db      'b'
            dd      9
            db      'r'
            dd      10
            db      'a'
            dd      11
            db      '!'
            dd      12
            db      '1'
            dd      13
            db      '2'
            dd      14
            db      '3'
            dd      15
            db      '4'

arraylen    equ ($-dates)/esize  ;; arraylen = byte size of array / element size
key         dd  0   ;; The search key
tvsec       dd  0, 0
tvsec2      dd  0, 0
sleeptime   dd  0, 500000000   ;; .5 second
endl        db  10


    section .text
    global _start
_start:
    mov     ecx, 20     ;run for 20 seconds

.getEvent:
    push    ecx ;; Store loop counter
    mov     eax, tvsec
    push    eax     ;; push pointer to tvsec onto stack
    call    getTime ;; and store the current time in it
    mov     eax, dword[tvsec]
    and     eax, 0x0000000f ;; We're only interested in the time % 16
    mov     dword[key], eax ;; Store index in "key"

    ;; Perform the search
    xor     eax, eax
    push    eax ; dword on stack for return value
    push    0   ; Left bound
    mov     eax, arraylen - 1
    push    eax ; Right bound
    mov     eax, dword[key]
    push    eax ; Search key
    call    binary_search
    
    pop     ebx         ; Binary search returns a dword on the stack 
    test    ebx, ebx
    js      .exit       ; Exit if returned value is -1
    
    ;; Print the event corresponding to the returned value
    imul    ebx, esize  ; multiply returned index by element size ( 5 bytes )
    add     ebx, 4      ; Character we want to print is the 5th byte in the element
    add     ebx, dates  ; Add in offset of data array
    push    ebx
    call    printChar

    mov     ebx, endl
    push    ebx
    call    printChar

.wait:

    call    sleep
    ;; The sleep duration is set to .5 seconds,
    ;; to be absolutely sure we only print each event
    ;; once, make sure the clock has advanced.

    mov     eax, tvsec2
    push    eax
    call    getTime     ;; Get current time in tvsec2
    mov     eax, dword[tvsec2]
    cmp     dword[tvsec], eax   ;; keep looping if the time is the same.
    je      .wait

    pop     ecx
    loop    .getEvent

.exit:
    mov     eax, SYS_EXIT
    int     0x80

;;---------------------------------------------------
;;binary_search: Given a left and right bound, and a
;;              key to search for, binary_search will
;;              try to find the index of the key within
;;              the "dates" array.
;;      
;;Python example
;;array = [1,5,6,7,8,10,22]
;;def binary_search(left, right, key):
;;  if left > right:
;;      # Exhausted search without finding key
;;      return -1
;;  mid = (left+right)/2 
;;  if array[mid] == key:
;;      # Found the index
;;      return mid
;;  elif key > array[mid]:
;;      # Search values greater than array[mid]
;;      return binary_search(mid+1, right, key)
;;  # Search values less than array[mid]
;;  return binary_search(left, mid-1, key)
;;---------------------------------------------------
binary_search:
    push    ebp
    mov     ebp, esp

%define f_ret   dword[ebp+20]
%define f_left  dword[ebp+16]
%define f_right dword[ebp+12]
%define f_key   dword[ebp+8]

    mov     eax, f_left
    cmp     eax, f_right
    jle     .test
    mov     f_ret, -1
    jmp     .return

.test:
    mov     eax, f_left
    add     eax, f_right
    shr     eax, 1      ; eax = middle value = (left + right) / 2
    mov     ebx, f_key
    push    eax
    imul    eax, esize
    mov     edx, dword[dates + eax]
    pop     eax
    cmp     ebx, edx    ; Compare middle value to key
    jl      .less
    jg      .greater
    mov     f_ret, eax
    jmp     .return

.less:
    push    eax ;; dword for return value
    push    f_left
    dec     eax
    push    eax
    push    f_key
    jmp     .recurse ;; binary_search(left, mid-1, key)

.greater:
    push    eax ;; dword for return value
    inc     eax
    push    eax
    push    f_right
    push    f_key
    jmp     .recurse ;; binary_search(mid+1, right, key)

.recurse:
    call    binary_search
    pop     eax
    mov     f_ret, eax

.return:
    pop     ebp
    ret     12 

;;--------------------------------------------------
;;getTime: Takes a dword address on the stack and
;;         stores the system time at the address
;;         referenced.
;;--------------------------------------------------
getTime:
    push    ebp
    mov     ebp, esp

%define t_ptr dword[ebp+8]

    push    eax
    mov     eax, SYS_TIME
    mov     ebx, t_ptr
    mov     ecx, 0
    int     0x80
    pop     eax
    pop     ebp
    ret     4

;;--------------------------------------------------
;;printChar: prints a byte from the address on the stack 
;;--------------------------------------------------
printChar:
    push    ebp
    mov     ebp, esp

%define char dword[ebp+8]

    mov     eax, SYS_WRITE 
    mov     ebx, STDOUT
    mov     ecx, char
    mov     edx, 1
    int     0x80
    pop     ebp
    ret     4

;;--------------------------------------------------
;;sleep: Sleep for length of time defined in sleeptime
;;--------------------------------------------------
sleep:
    mov     eax, SYS_SLEEP
    mov     ebx, sleeptime
    mov     ecx, 0
    int     0x80
    ret