#
# concatenate this file with the file containing the bitblt function
# and use the result as input to xspim, e.g., run the commands
#
# % cat driver.asm bitblt.asm > all.asm
# % xspim -file all.asm
#
# to debug your bitblt.asm code.  to run it on test input, make sure that
# the WIDTH, HEIGHT, WIDTHPLUS2, etc constants have values that match the
# input file, then do
#
# % cat driver.asm bitblt.asm > all.asm
# % spim -file all.asm < test_data.txt
#
# nb: if you modify bitblt.asm, you have to re-create all.spm before xspim
# will see the modifications.
#

#
# because bitblt will appear at the end of all.asm after the contents of
# this file, the constants defined here may be used there.  you should
# be careful to avoid name conflicts.
#

SYS_PRINT_INT=1
SYS_PRINT_FLOAT=2
SYS_PRINT_DOUBLE=3
SYS_PRINT_STR=4
SYS_READ_INT=5
SYS_READ_FLOAT=6
SYS_READ_DOUBLE=7
SYS_READ_STR=8
SYS_SBRK=9
SYS_EXIT=10

#
# the following symbolic constants will be changed for timing on a
# full-sized screen, i.e.,
#
# WIDTH=800
# WIDTHPLUS2=802
# HEIGHT=600
# WORDS_PER_ROW=25	# (800+31)/32
#
# if you need other symbolic constants than these the values of which
# depends on WIDTH and HEIGHT, put them in a separate file consts.asm,
# and create all.asm by
#
# % cat consts.asm driver.asm bitblt.asm > all.asm
#

WIDTH=80
WIDTHPLUS2=82
HEIGHT=60
WORDS_PER_ROW=3		# (80+31)/32

VSCROLL_AMOUNT=6
HEIGHT_MINUS_SCROLL=54	# (HEIGHT-VSCROLL_AMOUNT)

#
# independent constants
#
PIXELS_PER_WORD=32
LOG_PPW=5		# 2^{LOG_PPW} = PIXELS_PER_WORD
PPW_MASK=0x1f		# PIXELS_PER_WORD-1

# offsets from the frame pointer (which has the original stack pointer
# value)
# arg0 a0
# arg1 a1
# arg2 a2
# arg3 a3
ARG4_OFF=4
ARG5_OFF=8
ARG6_OFF=12
ARG7_OFF=16

#
# int	get_bit_value(unsigned int	*gbuffer,
#                     unsigned int	row,
#                     unsigned int	col)
#
# LEAF
#

get_bit_value:		mul	$t0,$a1,WORDS_PER_ROW
			sll	$t0,$t0,2
			addu	$t0,$t0,$a0	# row_start
			srl	$t1,$a2,LOG_PPW
			sll	$t1,$t1,2
			addu	$t1,$t0,$t1	# row_start + col_word_offset
			lw	$t1,0($t1)	# w
			and	$t0,$a2,PPW_MASK# col_bit_offset
			srl	$t1,$t1,$t0
			and	$v0,$t1,1
			jr	$ra

#
# void set_bit_value(unsigned int	*gbuffer,
#                    unsigned int	row,
#                    unsigned int	col,
#                    int		val)
#
# LEAF

set_bit_value:		mul	$t0,$a1,WORDS_PER_ROW
			sll	$t0,$t0,2
			addu	$t0,$t0,$a0	# row_start
			srl	$t1,$a2,LOG_PPW
			sll	$t1,$t1,2
			addu	$t1,$t0,$t1	# wptr
			lw	$t2,0($t1)	# w
			andi	$t0,$a2,PPW_MASK# col_bit_offset
			li	$t3,1
			sll	$t0,$t3,$t0	# mask
			not	$t3,$t0
			and	$t2,$t2,$t3	# w = w & ~mask
			beq	$a3,$zero,sbv_clear
			or	$t2,$t2,$t0	# w = w | mask
sbv_clear:
			sw	$t2,0($t1)	# *wptr = w
			jr	$ra

			.data
			.align 2
prev_page:		.space 720 # 4 * 60 * 3
shown_page:		.space 720 # 4 * 60 * 3
next_page:		.space 720 # 4 * 60 * 3

			.text
			# WIDTH+2 = 82 -> 84
			# plus $s0/r, $s1/c, $gbuffer, ra, fp.
RP_FSZ=104
RP_FP=-100
RP_RA=-96
RP_GBUFFER=-92
RP_R=-88
RP_C=-84
RP_LINEBUFF=-80

read_page:
			subu	$sp,$sp,RP_FSZ
			sw	$fp,4($sp)
			addu	$fp,$sp,RP_FSZ
			sw	$ra,RP_RA($fp)
			sw	$s0,RP_R($fp)
			sw	$s1,RP_C($fp)
			sw	$a0,RP_GBUFFER($fp)

			li	$s0,0
			b	rp_rtest
rp_rloop:		la	$a0,RP_LINEBUFF($fp)
			li	$a1,WIDTHPLUS2
			li	$v0,SYS_READ_STR
			syscall
			li	$s1,0
			b	rp_ctest
rp_cloop:
			addu	$t1,$s1,$fp
			lb	$t0,RP_LINEBUFF($t1)
			bne	$t0,' ',rp_not_blank
			lw	$a0,RP_GBUFFER($fp)
			move	$a1,$s0
			move	$a2,$s1
			li	$a3,0
			jal	set_bit_value
			b	rp_cloop_cont
rp_not_blank:
			lw	$a0,RP_GBUFFER($fp)
			move	$a1,$s0
			move	$a2,$s1
			li	$a3,1
			jal	set_bit_value
rp_cloop_cont:
			addu	$s1,$s1,1
rp_ctest:		blt	$s1,WIDTH,rp_cloop
			addu	$s0,$s0,1
rp_rtest:		blt	$s0,HEIGHT,rp_rloop

			lw	$s1,RP_C($fp)
			lw	$s0,RP_R($fp)
			lw	$ra,RP_RA($fp)
			lw	$fp,RP_FP($fp)
			addu	$sp,$sp,RP_FSZ
			jr	$ra

#
# void print_page(unsigned int *gbuffer)
#
			.data
pp_not_set_str:		.asciiz " "
pp_is_set_str:		.asciiz "*"
pp_newline_str:		.asciiz "\n"

PP_FSZ=20
PP_FP=-16
PP_RA=-12
PP_S2=-8
PP_S1=-4
PP_S0=0
			.text
print_page:		subu	$sp,$sp,PP_FSZ
			sw	$fp,4($sp)
			addu	$fp,$sp,PP_FSZ
			sw	$ra,PP_RA($fp)
			sw	$s0,PP_S0($fp)
			sw	$s1,PP_S1($fp)
			sw	$s2,PP_S2($fp)

			move	$s0,$a0		# gbuffer
			li	$s1,0		# r
			b	pp_rtest
pp_rloop:		li	$s2,0		# c
			b	pp_ctest
pp_cloop:
			move	$a0,$s0
			move	$a1,$s1
			move	$a2,$s2
			jal	get_bit_value
			bnez	$v0,pp_bit_is_set
			la	$a0,pp_not_set_str
			li	$v0,SYS_PRINT_STR
			syscall
			b	pp_cloop_cont
pp_bit_is_set:		la	$a0,pp_is_set_str
			li	$v0,SYS_PRINT_STR
			syscall
pp_cloop_cont:
			addu	$s2,$s2,1	# c++
pp_ctest:		blt	$s2,WIDTH,pp_cloop
			la	$a0,pp_newline_str
			li	$v0,SYS_PRINT_STR
			syscall
			addu	$s1,$s1,1	# r++
pp_rtest:		blt	$s1,HEIGHT,pp_rloop

			lw	$s0,PP_S0($fp)
			lw	$s1,PP_S1($fp)
			lw	$s2,PP_S2($fp)
			lw	$ra,PP_RA($fp)
			lw	$fp,PP_FP($fp)
			addu	$sp,$sp,PP_FSZ
			jr	$ra

#
# void	render_page(unsigned int	*gbuffer)
#

render_page:		jal	$ra

			.data
main_str1:		.asciiz	"Before:\n"
main_str2:		.asciiz	"prev_page:\n"
main_str3:		.asciiz	"shown_page:\n"
main_str4:		.asciiz	"next_page:\n"
main_str5:		.asciiz	"after scroll:\n"
main_str6:		.asciiz	"after move:\n"
main_str7:		.asciiz	"after flip:\n"
			.text
MAIN_FSZ=4

main:			subu	$sp,$sp,MAIN_FSZ
			sw	$ra,4($sp)

			la	$a0,prev_page
			jal	read_page
			la	$a0,shown_page
			jal	read_page
			la	$a0,next_page
			jal	read_page

			la	$a0,main_str1		# before
			li	$v0,SYS_PRINT_STR
			syscall

			la	$a0,main_str2		# prev_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,prev_page
			jal	print_page
			la	$a0,main_str3		# shown_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,shown_page
			jal	print_page
			la	$a0,main_str4		# next_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,next_page
			jal	print_page

			subu	$sp,$sp,16
			li	$t0,WIDTH
			li	$t1,HEIGHT_MINUS_SCROLL
			li	$t3,VSCROLL_AMOUNT
			sw	$t0,ARG7_OFF($sp)
			sw	$t1,ARG6_OFF($sp)
			sw	$zero,ARG5_OFF($sp)
			sw	$t3,ARG4_OFF($sp)
			la	$a3,shown_page
			li	$a2,0
			li	$a1,0
			move	$a0,$a3
			jal	bitblt
#			addu	$sp,$sp,16

#			subu	$sp,$sp,16
			li	$t0,WIDTH
			li	$t1,VSCROLL_AMOUNT
			sw	$t0,ARG7_OFF($sp)
			sw	$t1,ARG6_OFF($sp)
			sw	$zero,ARG5_OFF($sp)
			sw	$zero,ARG4_OFF($sp)

			la	$a3,next_page
			li	$a2,0
			li	$a1,HEIGHT_MINUS_SCROLL
			la	$a0,shown_page
			jal	bitblt
			addu	$sp,$sp,16

			la	$a0,main_str5		# after scroll
			li	$v0,SYS_PRINT_STR
			syscall

			la	$a0,main_str2		# prev_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,prev_page
			jal	print_page
			la	$a0,main_str3		# shown_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,shown_page
			jal	print_page
			la	$a0,main_str4		# next_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,next_page
			jal	print_page

			subu	$sp,$sp,16
			li	$t0,30
			li	$t1,25
			sw	$t0,ARG7_OFF($sp)
			sw	$t0,ARG6_OFF($sp)
			sw	$t1,ARG5_OFF($sp)
			sw	$t1,ARG4_OFF($sp)

			la	$a3,shown_page
			li	$a2,10
			li	$a1,10
			la	$a0,shown_page
			jal	bitblt
			addu	$sp,$sp,16

			la	$a0,main_str6		# after move
			li	$v0,SYS_PRINT_STR
			syscall

			la	$a0,main_str2		# prev_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,prev_page
			jal	print_page
			la	$a0,main_str3		# shown_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,shown_page
			jal	print_page
			la	$a0,main_str4		# next_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,next_page
			jal	print_page

			subu	$sp,$sp,16
			li	$t0,WIDTH
			li	$t1,HEIGHT
			sw	$t0,ARG7_OFF($sp)
			sw	$t1,ARG6_OFF($sp)
			sw	$zero,ARG5_OFF($sp)
			sw	$zero,ARG4_OFF($sp)

			la	$a3,shown_page
			li	$a2,0
			li	$a1,0
			la	$a0,prev_page
			jal	bitblt
#			addu	$sp,$sp,16

#			subu	$sp,$sp,16
			li	$t0,WIDTH
			li	$t1,HEIGHT
			sw	$t0,ARG7_OFF($sp)
			sw	$t1,ARG6_OFF($sp)
			sw	$zero,ARG5_OFF($sp)
			sw	$zero,ARG4_OFF($sp)

			la	$a3,next_page
			li	$a2,0
			li	$a1,0
			la	$a0,shown_page
			jal	bitblt
			addu	$sp,$sp,16

			la	$a0,next_page
			jal	render_page

			la	$a0,main_str7		# after flip
			li	$v0,SYS_PRINT_STR
			syscall

			la	$a0,main_str2		# prev_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,prev_page
			jal	print_page
			la	$a0,main_str3		# shown_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,shown_page
			jal	print_page
			la	$a0,main_str4		# next_page
			li	$v0,SYS_PRINT_STR
			syscall
			la	$a0,next_page
			jal	print_page

			li	$v0,0

			lw	$ra,4($sp)
			addu	$sp,$sp,MAIN_FSZ
			jr	$ra
