jal
如何覆盖我的$s0
注册。我不太明白它是如何可能的。我在代码中添加了注释,以便您可以看到循环发生的位置。2
.data # data segment for variables and strings
# These are all the strings that will need to be outputted to the console
title: .asciiz "Tic-Tac-Toe!\n\n"
oprompt: .asciiz "O player: Please enter row/col, one per line:\n\n"
xprompt: .asciiz "X player: Please enter row/col, one per line:\n\n"
invposstr: .asciiz " is an invalid position. Try again.\n\n"
owinstr: .asciiz "O won the game,\n\n exiting. . ."
xwinstr: .asciiz "X won the game,\n\n exiting. . ."
catstr: .asciiz "CAT game,\n\n exiting. . ."
border: .asciiz "\n\n _ _ _ \n"
# Initialze the board with 9 bytes
board: .byte 'X','X','X','X','X','_','X','_','_'
.text # text segment for instructions
main: # begin the main func
li $v0, 4 #set v0 to print string
la $a0, title #set string to print (in $a0) as title
syscall #execute
li $s1, 0 #use s1 as the game counter (up to 9 turns)
playerx: #player x will always go first
li $v0, 4 #prepare to print string
la $a0, xprompt #load the get move prompt
syscall
jal get_valid_move #go get a valid move address
# I am having trouble returning here
li $t0, 'X' #load asciiz code for X
sb $t0, ($v0) #store the X into the board address
addi $s1, 1 #increment the game counter to next turn
jal print_board #after getting the move, print the board status
# And here
playero: #player o will always go second
li $v0, 4 #prepare to print string
la $a0, oprompt #load the get move prompt
syscall
jal get_valid_move #go get a valid move address
# And here
li $t0, 'O' #load asciiz code for O
sb $t0, ($v0) #store the O into the board address
addi $s1, 1 #increment the game counter to next turn
jal print_board #after getting the move, print the board status
# And here
j playerx #go back to player x turn
# I store the current return address below (first time)
print_board: #function to print the status of the board
move $s0, $ra #save the recent return address
la $t1, board #load the board address
li $v0, 4 #set v0 to print string
la $a0, border #set string to print (in $a0) as prompt
syscall #execute
li $t0, 0 #use as counter for loop
loop: #use loop to print 1 row at a time
li $v0, 11 #prepare to print char
li $a0, 124 #asciiz code for |
syscall
lb $a0, ($t1) #load next byte from board
li $v0, 11 #prepare to print char
syscall
addi $t1, $t1, 1 #increment address of board to next byte/char
addi $t0, $t0, 1 #increment loop counter
beq $t0, 3, rowend #go print special stuff at end of row
beq $t0, 6, rowend #go print special stuff at end of row
beq $t0, 9, rowend #go print special stuff at end of row
j loop #go back to top
rowend:
li $a0, 124 #asciiz for |
li $v0, 11 #prepare to print char
syscall
li $a0, 10 #ascizz for newline
li $v0, 11 #prepare to print char
syscall
blt $t0, 9, loop #unless at the last row, loop
li $a0, 10 #ascizz for newline
li $v0, 11 #prepare to print char
syscall
jr $ra #return to the gameplay in main
entry_address: #function to transform user input (row, col) into board address
move $t0, $a1 #make a copy of row for use
move $t1, $a2 #make a copy of col for use
addi $t0, $t0, -1 #use n-1 for accessing storage address
addi $t1, $t1, -1 #use n-1
mul $t0, $t0, 3 #mul the row by 3
la $v0, board #load base address of the board
add $v0, $v0, $t0 #add the row offset
add $v0, $v0, $t1 #add the col offset
#v0 now holds the correct board position address
jr $ra #now go back to check if valid move
valid_position:
li $v0, 1 #assume valid
blt $a1, 1, inv #if row is less than 1
bgt $a1, 3, inv # or if row is greater than 3
blt $a2, 1, inv # or if col is less than 1
bgt $a2, 3, inv # or if col is greater than 3 change validity
jr $ra #go back to get_valid_move at last instruction
inv:
li $v0, 0 #since branched, change to inv
jr $ra #go back to get_valid_move at last instruction
# I store the current return address into s0 below (the 2nd time)
get_valid_move:
move $s0, $ra #save the recent return address
li $v0, 5 #prepare to read row int
syscall
move $a1, $v0 #copy the read int into argument to be passed
li $v0, 5 #prepare to read col int
syscall
move $a2, $v0 #copy the read int into argument to be passed
jal valid_position #go make sure pos is valid
beq $v0, 0, invalid #go tell user if valid_position returned false
jal entry_address #position was good so go get entry_address
# THE JR STATEMENT BELOW IS LOOPING BACK HERE
# I need to return to the last instruction in main which I thought I stored in $s0
li $t0, '_' #use underscore for comparison
lb $t1, ($v0) #load the byte from the entry_address
bne $t0, $t1, invalid #if entry is taken, get another move
jr $s0 #since move was valid go back to gameplay in main
invalid:
li $v0, 1 #prepare to print int
move $a0, $a1 #load row numb
syscall
li $v0, 11 #prepare to print char
li $a0, 44 #load comma asciiz
syscall
li $v0, 1 #prepare to print int
move $a0, $a2 #load col numb
syscall
li $v0, 4 #prepare to print string
la $a0, invposstr #load invalid pos message
syscall
j get_valid_move #repeat the user input loop
check_all_match:
print_winner_and_exit:
row_winner:
col_winner:
diag_winner:
check_for_win:
# After printing all the results, we can exit the program
exit:
li $v0, 10 # set v0 to exit
syscall # execute exit