# MIPS program to stress-test simulators - version 4; tests 0-7 working.
# if all is well, $s0 = 0; $s1 = 1; $s2 = 2; $s3 = 3; $s4 = 4; $s5 = 5;
# $s6 = 6; $s7 = 7
#
# This version of torture.s is complete.
#
# This program tests all "required" instructions in the SPIM simulator
# project.  It does not test the syscall instruction.
#

	.data				# Begin data segment
var1:	.word 0				# first memory variable
var2:	.word 0				# second memory variable
var3:	.word 0,0			# make sure var3 holds two words
					#   consecutively
	.text				# Begin code segment
	.globl main			# first instr must be global

###################### BEGIN  main #########################################

main:	subu $sp,$sp,16			# set up main's stack frame:
					#   need room for two args, two 
					#   two callee save registers
	sw $ra,12($sp)			# save main's return address
	sw $fp,8($sp)			# save main's caller's frame pointer
	addu $fp,$sp,12			# establish main's frame pointer

# test 0: zero register; result should be 0 in the zero register; 
# $s0 = 0 if all is well at end of test

	addi $0,$0,1			# in this case, 0+1=0 if all is well!
	addi $s0,$0,0			# MOVE $0 TO $s0 ; should be 0
#	li $v0,4			# print string
#	la $a0,str0
#	syscall
#	li $v0,1			# print integer
#	move $a0,$0
#	syscall
#	jal NewLine			# print newline

# test 1: logical operations; 
# $s1 = 1 if all is well at end of test

	lui $t0,0x5555			# $t0 = 0x55555555
	ori $t0,$t0,0x5555
	lui $t1,0x0000			# $t1 = 0x00000000
	ori $t1,0x0000			
	nor $t0,$t1,$t0			# $t0 NOR $t1 = 0xAAAAAAAA
	lui $t2,0xCCCC			# $t2 = 0xCCCCCCCC
	ori $t2,$t2,0xCCCC
	or  $t0,$t2,$t0			# $t0 OR $t2  = 0xEEEEEEEE
	lui $t3,0x3333			# $t3 = 0x33333333
	ori $t3,$t3,0x3333
	and $t0,$t3,$t0			# $t0 AND $t3 = 0x22222222
	sll $t0,$t0,1			# $t0 = 0x44444444
	sra $t0,$t0,1			# $t0 = 0x22222222
	srl $t0,$t0,1			# $t0 = 0x11111111
	addi $t4,$0,3			# $t4 = 3
	sllv $t0,$t0,$t4		# $t0 = 0x88888888
	sra $t0,$t0,1			# $t0 = 0xC4444444
	lui $t5,0x8888			# $t5 = 0x88888888
	ori $t5,$t5,0x8888
	and $t0,$t5,$t0			# $t0 AND $t5 = 0x80000000
	lui $t6,0xFFFF			# $t6 = 0xFFFFFFFF
	ori $t6,$t6,0xFFFF
	xor $t0,$t6,$t0			# $t0 XOR $t6 = 0x7FFFFFFF

	addi $s1,$t0,0			# MOVE $t0 to $s1
	lui $t7,0x7FFF			# load expected answer into $t7
	ori $t7,0xFFFF
	bne $s1,$t0,wrong1		# check answer
	addi $s1,$0,1			#   if correct, set $s1 = 1
wrong1: add $0,$0,$0			# NOP: if incorrect, $s1 != 1

# test 2: load/store - simple lw/sw commands
# $s2 = 2 if all is well at end of test

# first store two numbers in memory
	lui $t0,0x7654			# $t0 = 0x76543210
	ori $t0,0x3210
	la $t1,var1			# $t1 = &var1 (pointer to var1)
	sw $t0,0($t1)			# var1 = $t0
	lui $t2,0x1234			# $t2 = 0x12345678
	xori $t2,0x5678
	la $t3,var2			# $t3 = &var2
	sw $t2,0($t3)			# var2 = $t3
# now retrieve the two numbers and add them
	lw $t4,0($t1)			# $t4 = var1
	lw $t5,0($t3)			# $t5 = var2
	addu $t6,$t4,$t5		# $t6 = $t4 + $t5
					# nb add would cause overflow above!
	addu $s2,$t6,0			# set up flag value in $s2
	lui $t7,0x8888			# $t7 = 0x88888888 (correct answer)
	ori $t7,0x8888
	bne $s2,$t7,wrong2		# check answer
	addi $s2,$0,2			#   if correct, set $s2 = 2
	addi $s2,$s2,131072		# 2^17, this is a pseudoinstruction
	andi $s2,$s2,0xffff		#   should set $s2 back to 2
wrong2: add $0,$0,$0			# NOP: if incorrect, $s2 != 2
		
# test 3: arithmetic
# $s3 = 3 if all is well at end of test

	add $t0,$0,$0			# clear $t0
	addi $t0,$t0,0xff		# $t0 = 255
	addi $t0,$t0,-240		# $t0 = 15
	addiu $t1,$0,15			# $t1 = 15 

# not required
#	mult $t1,$t0			# $t2 = $t1*$t0 = 225
#	mflo $t2			
#	mfhi $t6			# $t6 should be 0
# replace
	sll $t2,$t1,4
	sub $t2,$t2,$t1
	sub $t6,$t0,$t0
	
	addi $t2,$t2,2			# $t2 = 225 + 2 = 227
	ori $t3,$0,0xa			# $t3 = 10
	sub $t4,$t1,$t3			# $t4 = $t1-$t3 = 5

# not required
#	div $t2,$t4			# $t4 = $t2 / $t4 = 45 rem 2
#	mflo $t4
#	mfhi $t7			# $t7 is remainder; should be 2
#replace
	addi $t7,$t2,0x1d
	srl $t7,$t7,7
	addi $t4,$t4,0x28
			
	addu $t6,$t6,$t7		# $t6 = $t6 + $t7 = 2
	add $s3,$t7,$t4			# $s3 = 3 if all is well
	addi $s3,$s3,-44
		
# test 4: jumping
# $s4 = 4 if all is well at end of test

j_top:	add $s4,$0,$0			# clear $s4
	j j_skip1
j_bad1:	addi $s4,$s4,17			# should not happen!
j_skip1:addi $s4,$s4,1			# $s4 = 1 now if all is well
	la $t0,j_skip2			# $t0 is pointer to j_skip2
	jr $t0				# jump to j_skip2
j_bad2:	addi $s4,$s4,23			# should not happen!
j_skip2:addi $s4,$s4,1			# $s4 = 2 now if all is well
	jal inc_s4 			# $s4 = 3 now if all is well on return
#   jalr is not required  enable if you want to test jalr.
#	la $t1,inc_s4			# $t1 is pointer to inc_s4
#	jalr $t1			# $s4 = 4 now if all is well on return
#  instead
	jal inc_s4

# test 5: branching
# $s5 = 5 if all is well at end of test

b_top:	add $s5,$0,$0			# clear $s5
	beq $s5,$0,b_skip1		# if $s5 = 0 goto b_skip1
b_bad1:	addi $s5,$s5,7			# should not happen!
b_skip1:addi $s5,$s5,1			# $s5 = 1 now if all is well
	addi $t0,$0,-1			# $t0 = -1
	bgez $t0,b_skip2		# if $t0 >= 0 goto b_skip2 (it isn't!)
b_good1:addi $s5,$s5,-10		# should do this!
b_skip2:addi $s5,$s5,11			# $s5 = 2 now if all is well
	bltz $t0,b_skip3		# if $t0 < 0 goto b_skip 3 (it is!)
b_bad2:	addi $s5,$s5,13			# should not happen!
b_skip3:addi $s5,$s5,1			# $s5 = 3 now if all is well
#  disable this instruction 
#	bltzal $t0,inc_s5		# call inc_s5 if $t0 < 0 (it is!)
#       replace with
	bltz $t0,n_skip1		# call inc_s5 if $t0 < 0 (it is!)
	addi $s5,$s5,13			# should not happen!
n_skip1:jal inc_s5               	# call inc_s5 if $t0 < 0 (it is!)
#
#  disable this instruction
#	bgezal $t0,inc_s5		# call inc_s5 if $t0 >0 0 (it isn't!)
					# $s5 = 4 now if all is well
	add  $t1,$0,$0			# clear $t5
	blez $t1,b_skip4		# if $t1 <= 0 goto b_skip4 (it is!)
	addi $s5,$s5,17			# should not happen!
b_skip4:bgtz $t1,b_skip5		# if $t1 > 0 goto b_skip5 (it isn't!)
	addi $s5,$s5,-18		# should do this!
b_skip5:addi $s5,$s5,19			# $s5 = 5 now if all is well

# test 6: set instructions
# $s6 = 6 if all is well at end of test

	add $s6,$0,$0			# clear $s6
	addi $t0,$0,-10			# $t0 = -10 ( = 0xFFFFFFF6)
	addi $t1,$0,20			# $t1 = 20
	slt $t2,$t0,$t1			# $t2 = 1 if $t0 < $t1 (it is!)
	add $s6,$s6,$t2			# $s6 = 1 now if all is well
	sltu $t3,$t0,$t1		# $t3 = 1 if $t0 < $t1 unsigned (not!)
	add $s6,$s6,$t3			# $s6 = 1 still if all is well
	slti $t4,$t0,-5			# $t4 = 1 if $t0 < -5 (it is!)
	add $s6,$s6,$t4			# $s6 = 2 now if all is well

# not required
#	multu $s6,$s6			# should be 2 x 2 = 4
#	mflo $s6			# $s6 = 4 now if all is well
# replace
	add $s6, $s6, $s6
	
	sltiu $t5,$t0,-5		# $t5 = 1 if $t0 < -5 unsigned (yes!)
					# sltiu sign-extends but then compares
					# as unsigned; 0xFF..F6 is < 0xFF..FB
	add $s6,$s6,$t5			# $s6 = 5 still if all is well
# test a few stray instructions while we're here
# not required
#	mthi $s6			# put $s6 in hi for fun
#	mtlo $t0			# put -10 in LO
#	mflo $s6			# put -10 in $s6
#	mfhi $t6			# put 5 in $t6
	# simulate the prev instructions
	addi $t6, $s6, 0
	addi $s6, $t0, 0
	
	subu $s6,$s6,$t6		# $s6 = -10 - 5 = -15 (even unsigned)

# not required
#	divu $s6,$t6			# 0xff..f1 / 5 = 0x33333330 rem 1
#	mflo $s6			# $s6 = 0x33333330
#	mfhi $t7			# $t7 = 1
# replace
	andi $s6,$s6,0x33333332
	andi $t7,$t6,1
		
	srav $s6,$s6,$t1		# right shift $s6 20 places;
					# $s6 = 0x00000333
	addi $t1,$t1,-12		# $t1 = 20 - 12 = 8
	srlv $s6,$s6,$t1		# right shift $s6 8 places;
					# $s6 = 0x00000003
	add $s6,$s6,$t7			# $s6 = 4 if all is well
	add $s6,$s6,2			# $s6 = 6 if all is well

# test 7: nonaligned load/store instructions
# $s7 = 7 if all is well at end of test
# this test is not required
#	lui $t0,0x1234			# $t0 = 0x12345678
#	ori $t0,0x5678
#	lui $t1,0x9abc			# $t1 = 0x9abcdef0
#	ori $t1,0xdef0
#
#	la $t2,var3			# $t2 = &var3 (pointer to var3)
#					# var3 was declared as an array
#					#   two words long
#	sw $t0,0($t2)			# var3[0] = $t0
#	sw $t1,4($t2)			# var3[1] = $t1
#
#	lb $t3,0($t2)			# $t3 = 0x00000012
#	lb $t4,1($t2)			# $t4 = 0x00000034
#	lb $t5,4($t2)			# $t5 = 0xffffff9a (nb sign extends)
#	lbu $t6,5($t2)			# $t6 = 0x000000bc (doesn't sign extend)
#	lwl $t7,1($t2)			# $t7 = 0x345678XX
#	lwr $t7,4($t2)			# $t7 = 0x3456789a
#	lhu $t8,2($t2)			# $t8 = 0x00005678
#	lh $t9,4($t2)			# $t9 = 0xffff9abc (nb sign extends)
#
#	subu $s7,$t5,$t9		# $s7 = 0x000064de
#	subu $s7,$s7,$t3		# $s7 = 0x000064cc
#	subu $s7,$s7,$t4		# $s7 = 0x00006498
#	subu $s7,$s7,$t8		# $s7 = 0x00000e20
#	addu $s7,$s7,$t8		# $s7 = 0x00006498
#	addu $s7,$s7,$t6		# $s7 = 0x00006554
#	add $s7,$s7,-0x6554		# $s7 = 0
#	addu $s7,$s7,$t7		# $s7 = 0x3456789a
#
#	sb $s7,1($t2)			# var3[1] = 0x129a5678
#	sh $s7,2($t2)			# var3[1] = 0x129a789a
#	swl $s7,3($t2)			# var3[1] = 0x129a7834
#	swr $s7,0($t2)			# var3[1] = 0x9a9a7834
#	lw $s7,0($t2)			# $s7 = 0x9a9a7834 if all is well
#	lui $t0,0x9a9a			# $t0 = 0x9a9a782d
#	ori $t0,0x782d
#	sub $s7,$s7,$t0			# $s7 = 7 if all is well
#instead
	addi $s7,$0,0x7
	
# prepare to exit program

        lw $ra,12($sp)                  # restore return address
        lw $fp,8($sp)                   # restore frame pointer address
        addu $sp,$sp,16			# pop main's stack frame
	li $v0, 10			# setup for exit syscall
	syscall				# exec syscall

##################### END MAIN ###########################################

# inc_s4: Leaf procedure, called from jump test to verify call/return
# behavior.  Increments $s4 once.

inc_s4: addi $s4,$s4,1
	jr $ra

# inc_s5: Leaf procedure, called from branch test to verify bltzal etc.
# Increments $s5 once.

inc_s5: addi $s5,$s5,1
	jr $ra

