# mp1.S - missile-command version
.data
# Constants for accessing the fields of a struct missile,
# struct missile is defined in rtc.h and mp1.h
NEXT = 0
X = 4
Y = 8
VX = 12
VY = 16
DEST_X = 20
DEST_Y = 24
EXPLODED = 28
C = 32
# Character to draw for an explosion - '@'
EXPLOSION = 64
# Data shared between this file and rtc.c helper functions
# This '.globl' directive makes these symbols visible externally
.globl mp1_missile_list, base_alive, mp1_score
mp1_missile_list: .long 0x0 # Head of list pointer
base_alive: .long 0x0 # Array of 3 bytes, plus a padding byte
mp1_score: .long 0x0 # Player's current score
# Data private to this file
base_pic: .string "/^^^\\" # Picture of a live base
dead_base_pic: .string "xxxxx" # Picture of a dead base
crosshairs_x: .long 0x0 # X-position of the crosshairs
crosshairs_y: .long 0x0 # Y-position of the crosshairs
.text
# void mp1_poke(void);
# You can use this function to write to video memory.
#
# Interface: Register-based arguments (not C-style)
# Inputs: %cl - The byte you wish to write
# %eax - Offset from the start of video memory that you wish
# to write to
# Outputs: Text-mode video screen is written to at location %eax with
# the byte in %cl
# Registers: Clobbers EDX
mp1_poke:
movl vmem_base_addr(,1),%edx
movb %cl,(%edx,%eax,1)
ret
# ----------------- Exported functions ---------------------
# void mp1_rtc_tasklet(unsigned long garbage);
# Performs three tasks:
# (1) updates the list of missiles (implement this in update_missiles,
# below, and call it from here).
# (2) Redraw the bases - they may have been overwritten with missiles
# (3) Redraw the crosshairs - it may have been overwritten with missiles
# Inputs : none
# Outputs : none
# Registers: Standard C calling convention
.globl mp1_rtc_tasklet
mp1_rtc_tasklet:
# callee save
pushl %ebp
movl %esp, %ebp
# make the three calls
pushl %edx
call update_missiles
popl %edx
pushl %edx
call mp1_rtc_tasklet_redraw_bases
popl %edx
pushl %edx
call mp1_rtc_tasklet_redraw_xhair
popl %edx
# callee teardown
leave
ret
mp1_rtc_tasklet_redraw_bases:
# ESI - Counter for outer loop = 3
# EDI - Counter for inner loop = 5
# EBX - Hold ptr to base
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
# redraw bases
# initialize variables for the 2 loops
movl $3876, %eax
movl $5, %edi
movl $3, %esi
movl $base_alive, %edx
# loop to print 5 characters
mp1_rtc_tasklet_redraw_bases_outter:
cmpl $0, %esi
jle mp1_rtc_tasklet_redraw_bases_outter_exit
cmpb $0, (%edx)
je mp1_rtc_tasklet_redraw_bases_dead
movl $base_pic, %ebx
jmp mp1_rtc_tasklet_redraw_bases_inner
mp1_rtc_tasklet_redraw_bases_dead:
movl $dead_base_pic, %ebx
mp1_rtc_tasklet_redraw_bases_inner:
cmpl $0, %edi
jle mp1_rtc_tasklet_redraw_bases_inner_exit
movb (%ebx), %cl
pushl %edx
call mp1_poke
popl %edx
addl $1, %ebx
addl $2, %eax
decl %edi
jmp mp1_rtc_tasklet_redraw_bases_inner
mp1_rtc_tasklet_redraw_bases_inner_exit:
addl $30, %eax
# movl $base_pic, %ebx
movl $5, %edi
decl %esi
addl $1, %edx
jmp mp1_rtc_tasklet_redraw_bases_outter
mp1_rtc_tasklet_redraw_bases_outter_exit:
# callee teardown
popl %edi
popl %esi
popl %ebx
leave
ret
mp1_rtc_tasklet_redraw_xhair:
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
# redraw xhair
movl crosshairs_y, %eax
imull $160, %eax # 80 x 2
movl crosshairs_x, %ebx
imull $2, %ebx
addl %ebx, %eax
movb $88, %cl
call mp1_poke
# callee teardown
popl %edi
popl %esi
popl %ebx
leave
ret
# int mp1_ioctl(unsigned long arg, unsigned int cmd)
# The dispatch function for the MP1 ioctls - should use the cmd argument
# and a jumptable to execute one of the specific ioctls implemented below.
# Inputs : unsigned long arg - parameter to the mp1_ioctl_....
# : unsigned int cmd - specifies which mp1_ioctl_... function
# : to execute
# Outputs : Returns an integer - depends on which ioctl() function is called
# Registers: Standard C calling convention
.globl mp1_ioctl
mp1_ioctl:
# get cmd in eax
movl 8(%esp), %eax
# compare agar > 4
cmpl $4, %eax
jg mp1_ioctl_invalid
# compare agar < 0
cmpl $0, %eax
jl mp1_ioctl_invalid
# then jump to jump table
jmp *jump_table(, %eax, 4)
# agar invalid
mp1_ioctl_invalid:
movl $-1, %eax
ret
# ----------------- Functions private to this file -------------------
update_missiles:
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
# render the missiles
# ebx is current_head
movl mp1_missile_list, %ebx
update_missiles_loop:
cmpl $0, %ebx
je update_missiles_loop_end
movl %ebx, %edi # temp gets curr
movl (%edi), %edi # temp gets temp next
# start render
cmpl $0, EXPLODED(%ebx)
# NOT EXPLODING
je update_missiles_not_exploding
# EXPLODING
pushl %edi
pushl %ebx
call update_missiles_exploding
popl %ebx
popl %edi
update_missiles_not_exploding_return:
movl %edi, %ebx # curr gets temp
jmp update_missiles_loop
update_missiles_loop_end:
# callee teardown
popl %edi
popl %esi
popl %ebx
leave
ret
update_missiles_not_exploding:
pushl %edi
pushl %ebx
pushl %esi
# call draw with ' ' and struct ptr
pushl $32
pushl %ebx
call update_missiles_draw
popl %ebx
addl $4, %esp
# add delta
movl X(%ebx), %edi
movl Y(%ebx), %esi
addl VX(%ebx), %edi
addl VY(%ebx), %esi
movl %edi, X(%ebx)
movl %esi, Y(%ebx)
# get high 16 bits
shrl $16, %edi
shrl $16, %esi
# check agar inside screen
cmpl $79, %edi
jg update_missiles_not_exploding_outside_screen
cmpl $0, %edi
jl update_missiles_not_exploding_outside_screen
cmpl $24, %esi
jg update_missiles_not_exploding_outside_screen
cmpl $0, %esi
jl update_missiles_not_exploding_outside_screen
jmp update_missiles_not_exploding_inside_screen
update_missiles_not_exploding_internal_return:
popl %esi
popl %ebx
popl %edi
jmp update_missiles_not_exploding_return
update_missiles_not_exploding_inside_screen:
# is at destination?
cmpl DEST_X(%ebx), %edi
jne update_missiles_not_exploding_inside_screen_not_at_dest
cmpl DEST_Y(%ebx), %esi
jne update_missiles_not_exploding_inside_screen_not_at_dest
pushl %ebx
call update_missiles_exploding
popl %ebx
jmp update_missiles_not_exploding_internal_return
update_missiles_not_exploding_inside_screen_not_at_dest:
pushl C(%ebx)
pushl %ebx
call update_missiles_draw
popl %ebx
addl $4, %esp
jmp update_missiles_not_exploding_internal_return
update_missiles_not_exploding_outside_screen:
# delete from list
pushl %ebx
call update_missiles_delete
popl %ebx
jmp update_missiles_not_exploding_internal_return
update_missiles_exploding:
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
# ebx gets current ptr - ask
movl 8(%ebp), %ebx
# call missile_explode - ask
pushl %ebx
call missile_explode
popl %ebx
# call user notifyy
cmpl $0, %eax
jne call_notify_user
return_from_call_notify_user:
# decrement EXPLODED
decl EXPLODED(%ebx)
# check if 0 (just 0)
cmpl $0, EXPLODED(%ebx)
je update_missiles_exploding_e_0
jmp update_missiles_exploding_e_not_0
update_missiles_exploding_e_0:
# call draw with ' ' and struct ptr
pushl $32
pushl %ebx
call update_missiles_draw
popl %ebx
addl $4, %esp
# call delete with struct ptr
pushl %ebx
call update_missiles_delete
popl %ebx
jmp update_missiles_exploding_end
update_missiles_exploding_e_not_0:
# call draw with @ and struct ptr
pushl $EXPLOSION
pushl %ebx
call update_missiles_draw
popl %ebx
addl $4, %esp
update_missiles_exploding_end:
popl %edi
popl %esi
popl %ebx
leave
ret
call_notify_user:
call mp1_notify_user
jmp return_from_call_notify_user
update_missiles_draw:
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
movl 8(%ebp), %ebx # ebx gets ptr
movl X(%ebx), %esi # esi gets X
movl Y(%ebx), %edi # edi gets Y
shrl $16, %esi # get high 16 bits from X and Y
shrl $16, %edi
imull $160, %edi, %eax # 80 x 2
imull $2, %esi # X = X x 2
addl %esi, %eax # eax = 160 * Y + X * 2
movb 12(%ebp), %cl # cl gets char
pushl %edx
call mp1_poke
popl %edx
popl %edi
popl %esi
popl %ebx
leave
ret
update_missiles_delete:
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
# get the ptr to delete
movl 8(%ebp), %ebx
# get the head ptr
movl mp1_missile_list, %esi
# see if head == ptr
cmpl %ebx, %esi
je update_missiles_delete_change_head
update_missiles_delete_loop:
cmpl $0, %esi
je update_missiles_delete_end
cmpl (%esi), %ebx
je update_missiles_delete_remove
movl (%esi), %esi
jmp update_missiles_delete_loop
update_missiles_delete_end:
popl %edi
popl %esi
popl %ebx
leave
ret
update_missiles_delete_remove:
movl (%ebx), %edi
movl %edi, (%esi)
pushl %ebx
call mp1_free
popl %ebx
movl %edi, %eax
jmp update_missiles_delete_end
update_missiles_delete_change_head:
movl (%esi), %esi
movl %esi, mp1_missile_list
pushl %ebx
call mp1_free
popl %ebx
movl %esi, %eax
jmp update_missiles_delete_end
mp1_ioctl_startgame:
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
# movl $0, mp1_missile_list
movl $0, mp1_score
movl $40, crosshairs_x
movl $12, crosshairs_y
movb $1, base_alive
movb $1, base_alive + 1
movb $1, base_alive + 2
popl %edi
popl %esi
popl %ebx
leave
ret
mp1_ioctl_addmissile:
# eax - return value
# ebx - ptr to user space struct
# edi - ptr to alloted memory for the struct in kernel
# esi - temp var to help add to linked list
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
# dynamic memory allocation malloc(36) - 36 bytes (size of struct)
pushl $36
call mp1_malloc
addl $4, %esp
# check for malloc error
cmpl $0, %eax
je mp1_ioctl_addmissile_malloc_error
movl %eax, %edi
# get user space ptr to ebx and check validity
movl 8(%ebp), %ebx # getting argument
cmpl $0, %ebx
je mp1_ioctl_addmissile_copy_error
# copy to kernel
pushl $36
pushl %ebx
pushl %edi
call mp1_copy_from_user
popl %edi
popl %ebx
addl $4, %esp
# check for copy error
cmpl $0, %eax
jne mp1_ioctl_addmissile_copy_error
# add to the linked list
movl mp1_missile_list, %esi # temp gets head
movl %esi, (%edi)
movl %edi, mp1_missile_list # head gets new ptr
jmp mp1_ioctl_addmissile_tear_down
# free if copy error
mp1_ioctl_addmissile_copy_error:
pushl %edi
call mp1_free
addl $4, %esp
# return -1
mp1_ioctl_addmissile_malloc_error:
movl $-1, %eax
jmp mp1_ioctl_addmissile_tear_down_with_fail
# callee teardown
mp1_ioctl_addmissile_tear_down:
movl $0, %eax
mp1_ioctl_addmissile_tear_down_with_fail:
popl %edi
popl %esi
popl %ebx
leave
ret
mp1_ioctl_movexhairs:
# crosshairs_x
# crosshairs_y
# ebx - new x position
# edx - new y positon
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
# check agar delta is 0
cmpl $0, 8(%ebp)
je mp1_ioctl_movexhairs_return_0
# remove from current position
movl crosshairs_y, %eax
imull $160, %eax # 80 x 2
movl crosshairs_x, %ebx
imull $2, %ebx
addl %ebx, %eax
movb $32, %cl
call mp1_poke
# caculate correct new position
movl $0, %ebx
movl $0, %edx
addl crosshairs_x, %ebx
addw 8(%ebp), %bx
addl crosshairs_y, %edx
addw 10(%ebp), %dx
cmpl $79, %ebx
jbe mp1_ioctl_movexhairs_x_up_is_ok
subw 8(%ebp), %bx
mp1_ioctl_movexhairs_x_up_is_ok:
cmpl $0, %ebx
jae mp1_ioctl_movexhairs_x_down_is_ok
subw 8(%ebp), %bx
mp1_ioctl_movexhairs_x_down_is_ok:
cmpl $24, %edx
jbe mp1_ioctl_movexhairs_y_up_is_ok
subw 10(%ebp), %dx
mp1_ioctl_movexhairs_y_up_is_ok:
cmpl $0, %edx
jae mp1_ioctl_movexhairs_y_down_is_ok
subw 10(%ebp), %dx
mp1_ioctl_movexhairs_y_down_is_ok:
jmp mp1_ioctl_movexhairs_update_current_xhair
mp1_ioctl_movexhairs_update_current_xhair:
movl %ebx, crosshairs_x
movl %edx, crosshairs_y
mp1_ioctl_movexhairs_return_0:
movl $0, %eax
# callee teardown
popl %edi
popl %esi
popl %ebx
leave
ret
mp1_ioctl_getstatus:
# esi - get param (the ptr to user space int)
# edi - get my local int ptr
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
movl 8(%ebp), %esi
movl $0, %ebx
movw mp1_score, %bx
cmpb $0, base_alive
jne mp1_ioctl_getstatus_set_base1_to_alive
mp1_ioctl_getstatus_base1_done:
cmpb $0, base_alive + 1
jne mp1_ioctl_getstatus_set_base2_to_alive
mp1_ioctl_getstatus_base2_done:
cmpb $0, base_alive + 2
jne mp1_ioctl_getstatus_set_base3_to_alive
jmp mp1_ioctl_getstatus_base3_done
mp1_ioctl_getstatus_set_base1_to_alive:
orl $0x00010000, %ebx
jmp mp1_ioctl_getstatus_base1_done
mp1_ioctl_getstatus_set_base2_to_alive:
orl $0x00020000, %ebx
jmp mp1_ioctl_getstatus_base2_done
mp1_ioctl_getstatus_set_base3_to_alive:
orl $0x00040000, %ebx
mp1_ioctl_getstatus_base3_done:
pushl %ebx
movl %esp, %edi # edi is ptr to int
# copy to user
pushl $4
pushl %edi
pushl %esi
call mp1_copy_to_user
popl %esi
popl %edi
addl $4, %esp
# check for copy error
cmpl $0, %eax
jne mp1_ioctl_getstatus_failed
# callee teardown
popl %ebx
popl %edi
popl %esi
popl %ebx
movl $0, %eax
leave
ret
# callee teardown failed
mp1_ioctl_getstatus_failed:
popl %ebx
popl %edi
popl %esi
popl %ebx
movl $-1, %eax
leave
ret
mp1_ioctl_endgame:
# ebx is temp
# callee save
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %esi
pushl %edi
mp1_ioctl_endgame_loop:
cmpl $0, mp1_missile_list
je mp1_ioctl_endgame_loop_end
movl mp1_missile_list, %ebx # temp gets head
movl mp1_missile_list, %esi
movl (%esi), %esi # head gets head next
movl %esi, mp1_missile_list
pushl %ebx
call mp1_free
addl $4, %esp
jmp mp1_ioctl_endgame_loop
mp1_ioctl_endgame_loop_end:
# callee teardown
popl %edi
popl %esi
popl %ebx
leave
ret
jump_table:
.long mp1_ioctl_startgame, mp1_ioctl_addmissile, mp1_ioctl_movexhairs, mp1_ioctl_getstatus, mp1_ioctl_endgame
Menu