|
Due Date and Submission Method
On or before Thursday, April 02, 2026 and upload the source code (no documentation needed) to the section of “COVID-19 Exams, Homeworks, & Programming Exercises” of Blackboard. Objective Design and implement a MIPS assembly program, which has the user play a 6×6 SOS game against the computer. The final program is less than 300 lines without counting the declarations of data structures. The purpose of this exercise is to make students practice assembly language programming including various control instructions, functions, and the runtime stack. |
|
| The object of the game is for each player to attempt to create the straight sequence S-O-S among connected squares (either diagonally, horizontally, or vertically), and to create as many such sequences as they can. If a player succeeds in creating an SOS, that player immediately takes another turn, and continues to do so until no SOS can be created on their turn. Otherwise turns alternate between players after each move. Keeping track of who made which SOSs can be done by, e.g., one player circling their SOSs and the other player drawing a line through theirs. Once the grid has been filled up, the winner is the player who made the most SOSs. If the grid is filled up and the number of SOSs for each player is the same, then the game is a draw. |
syscall of MARS to randomly pick either one of the two players, System or User, to start the game.
. . . . . . ⇒ 0 1 2 3 4 5
. . . . . . ⇒ 6 7 8 9 a b
. . . . . . ⇒ c d e f g h
. . . . . . ⇒ i j k l m n
. . . . . . ⇒ o p q r s t
. . . . . . ⇒ u v w x y z
k, the board is displayed as follows:
. . . . . . ⇒ 0 1 2 3 4 5
. . . . . . ⇒ 6 7 8 9 a b
. . . . . . ⇒ c d e f g h
. . . . . . ⇒ i j k l m n
. . . . . . ⇒ o p q r s t
. . . . . . ⇒ u v w x y z
⇓ S at k
. . . . . . ⇒ 0 1 2 3 4 5
. . . . . . ⇒ 6 7 8 9 a b
. . . . . . ⇒ c d e f g h
. . S . . . ⇒ i j k l m n
. . . . . . ⇒ o p q r s t
. . . . . . ⇒ u v w x y z
. . . . . . ⇒ 0 1 2 3 4 5
. . O S . . ⇒ 6 7 8 9 a b
. . S O . . ⇒ c d e f g h
. . O S O . ⇒ i j k l m n
. . S O S . ⇒ o p q r s t
. . . . . . ⇒ u v w x y z
is the piece ‘S’ at the index g since it will create two SOSs as follows:
. . . . . . ⇒ 0 1 2 3 4 5
. . O S . . ⇒ 6 7 8 9 a b
. . S O S . ⇒ c d e f g h
. . O S O . ⇒ i j k l m n
. . S O S . ⇒ o p q r s t
. . . . . . ⇒ u v w x y z
Other moves create at most one SOS each.
. . . . . . ⇒ 0 1 2 3 4 5
. . . . . . ⇒ 6 7 8 9 a b
. . . . . . ⇒ c d e f g h
. . . . . . ⇒ i j k l m n
. . . . . . ⇒ o p q r s t
. . . . . . ⇒ u v w x y z
the instructor uses the following string:
board: .ascii "\n\n . . . . . . 0 1 2 3 4 5"
.ascii "\n . . . . . . 6 7 8 9 a b"
.ascii "\n . . . . . . c d e f g h"
.ascii "\n . . . . . . i j k l m n"
.ascii "\n . . . . . . o p q r s t"
.asciiz "\n . . . . . . u v w x y z\n"
Also, the instructor uses the following command to represent the offsets:
offset: .half 6, 8, 10, 12, 14, 16
.half 39, 41, 43, 45, 47, 49
.half 72, 74, 76, 78, 80, 82
.half 105, 107, 109, 111, 113, 115
.half 138, 140, 142, 144, 146, 148
.half 171, 173, 175, 177, 179, 181
where
$t0, the following code then puts the piece ‘S’ at that location:
mul $t0, $t0, 2 # Each offset is two-byte long.
lh $t1, offset($t0) # Load $t1 with the offset of the index $t0.
li $t2, 'S' # Put the piece ‘S’ in $t2.
sb $t2, board($t1) # Put the piece at the location, board+offset.
board(n) = 'S'
board(t) = 'O'
board(z) = 'S'
‡Note that the instructor has tried his best to make the list complete, but could not 100% guarantee its correctness or completeness.
syscall of MARS such as:
xor $a0, $a0, $a0 # Set a seed number.
li $a1, 36 # random number 0 to 35
li $v0, 42 # random number generator
syscall
routine1 is given as follows:
jal routine1 # Jump and link to routine1
next:
...
where the label next is not required.
The following command in the subroutine routine1 will return the control back to the next, the next command after the jal routine1”: routine1:
...
jr $ra # Jump to the contents of $ra
where the return address is saved in the register $31 or $ra
$31 or $ra, has to be saved before making the call‡.
The return address is restored after the called subroutine returns.
The instructor uses the runtime stack to save the return addresses, so deep subroutine calls are supported.
Use the following two commands to push the $ra to the runtime stack:
subu $sp, $sp, 4 # Decrement the $sp to make space for $ra.
sw $ra, ($sp) # Push the return address, $ra.
and use the following two commands to pop up the $ra from the runtime stack:
lw $ra, ($sp) # Pop the return address, $ra.
addu $sp, $sp, 4 # Increment the $sp.
|
|
#
# Finding the next move by using a one-step lookahead method
#
.data
p1: .asciiz "\n\nA one-step lookahead method for the next move:"
p2: .asciiz "\nThe next move: "
p3: .asciiz "\nNumber of total SOSs: "
p4: .asciiz "\nNumber of added SOSs: "
maxMov: .byte 0 # the move [0..z] having the max SOS #
maxSOS: .byte 0 # max SOS #
board: .ascii "\n\n . S . S O S 0 1 2 3 4 5"
.ascii "\n S O S . . . 6 7 8 9 a b"
.ascii "\n . S O S . . c d e f g h"
.ascii "\n . . . . . . i j k l m n"
.ascii "\n . . . . . . o p q r s t"
.asciiz "\n . . . . . . u v w x y z\n"
offset: .half 6, 8, 10, 12, 14, 16
.half 39, 41, 43, 45, 47, 49
.half 72, 74, 76, 78, 80, 82
.half 105, 107, 109, 111, 113, 115
.half 138, 140, 142, 144, 146, 148
.half 171, 173, 175, 177, 179, 181
SOS: .ascii "012" # 0
.ascii "07e" # 1
.ascii "06c" # 2
.ascii "123" # 3
.ascii "18f" # 4
.ascii "17d" # 5
.ascii "234" # 6
.ascii "29g" # 7
.ascii "28e" # 8
.ascii "27c" # 9
.ascii "345" # 10
.ascii "3ah" # 11
.ascii "39f" # 12
.ascii "38d" # 13
.ascii "4ag" # 14
.ascii "49e" # 15
.ascii "5bh" # 16
.ascii "5af" # 17
.ascii "678" # 18
.ascii "6dk" # 19
.ascii "6ci" # 20
.ascii "789" # 21
.ascii "7el" # 22
.ascii "7dj" # 23
.ascii "89a" # 24
.ascii "8fm" # 25
.ascii "8ek" # 26
.ascii "8di" # 27
.ascii "9ab" # 28
.ascii "9gn" # 29
.ascii "9fl" # 30
.ascii "9ej" # 31
.ascii "agm" # 32
.ascii "afk" # 33
.ascii "bhn" # 34
.ascii "bgl" # 35
.ascii "cde" # 36
.ascii "cjq" # 37
.ascii "cio" # 38
.ascii "def" # 39
.ascii "dkr" # 40
.ascii "djp" # 41
.ascii "efg" # 42
.ascii "els" # 43
.ascii "ekq" # 44
.ascii "ejo" # 45
.ascii "fgh" # 46
.ascii "fmt" # 47
.ascii "flr" # 48
.ascii "fkp" # 49
.ascii "gms" # 50
.ascii "glq" # 51
.ascii "hnt" # 52
.ascii "hmr" # 53
.ascii "ijk" # 54
.ascii "ipw" # 55
.ascii "iou" # 56
.ascii "jkl" # 57
.ascii "jqx" # 58
.ascii "jpv" # 59
.ascii "klm" # 60
.ascii "kry" # 61
.ascii "kqw" # 62
.ascii "kpu" # 63
.ascii "lmn" # 64
.ascii "lsz" # 65
.ascii "lrx" # 66
.ascii "lqv" # 67
.ascii "msy" # 68
.ascii "mrw" # 69
.ascii "ntz" # 70
.ascii "nsx" # 71
.ascii "opq" # 72
.ascii "pqr" # 73
.ascii "qrs" # 74
.ascii "rst" # 75
.ascii "uvw" # 76
.ascii "vwx" # 77
.ascii "wxy" # 78
.ascii "xyz" # 79
.text
.globl main
#
########################## Main Program #######################
#
main:
# Print the Prompt p1, greeting.
la $a0, p1
li $v0, 4
syscall
# Print the board.
la $a0, board
li $v0, 4
syscall
# Declarations
move $t0, $0 # $t0: SOS index [0..239] where 239 = 3*80 - 1
move $t1, $0 # $t1: SOS range [0..79]
move $t2, $0 # $t2: previous total SOS #
move $t3, $0 # $t3: current total SOS #
move $t4, $0 # $t4: current board index [0..35]
# Checking next SOS
L1: jal CheckSOS
beqz $v0, L2
add $t2, $t2, 1
L2: add $t0, $t0, 1
add $t1, $t1, 1
ble $t1, 79, L1
move $t4, $0
L3: mul $t5, $t4, 2 # Each offset is two-byte long.
lh $t5, offset($t5) # Load $t1 with the offset of the index $t0.
lb $t6, board($t5)
beq $t6, '.', L4
add $t4, $t4, 1 # The board at index is not empty.
j L3
L4: li $t6, 'S' # Put the piece ‘S’ in $t2.
sb $t6, board($t5) # Put the piece at the location, board+offset.
# Reset
move $t0, $0 # $t0: SOS index [0..239] where 239 = 3*80 - 1
move $t1, $0 # $t1: SOS range [0..79]
move $t3, $0 # $t3: current total SOS #
# Checking next SOS
L5: jal CheckSOS
beqz $v0, L6
add $t3, $t3, 1
L6: add $t0, $t0, 1
add $t1, $t1, 1
ble $t1, 79, L5
lb $t6, maxSOS
ble $t3, $t6, L7
sb $t3, maxSOS
sb $t4, maxMov
# Reset the board.
L7: mul $t6, $t4, 2 # Each offset is two-byte long.
lh $t7, offset($t6) # Load $t1 with the offset of the index $t0.
li $t8, '.' # Put the piece ‘.’ in $t2.
sb $t8, board($t7) # Put the piece at the location, board+offset.
add $t4, $t4, 1
ble $t4, 35, L3
lb $t5, maxMov
# Mark the board.
mul $t6, $t5, 2 # Each offset is two-byte long.
lh $t7, offset($t6) # Load $t1 with the offset of the index $t0.
li $t8, 'S' # Put the piece ‘S’ in $t2.
sb $t8, board($t7) # Put the piece at the location, board+offset.
la $a0, p2
li $v0, 4
syscall
move $a0, $t5 # Print the max move.
jal I2C
li $v0, 11
syscall
la $a0, p3
li $v0, 4
syscall
lb $a0, maxSOS # Print the max SOS #.
li $v0, 1
syscall
la $a0, p4
li $v0, 4
syscall
lb $t3, maxSOS
sub $a0, $t3, $t2 # Print the added SOS #.
li $v0, 1
syscall
la $a0, board
li $v0, 4
syscall
# End of program
End: li $v0, 10
syscall
#
############## Check whether 'SOS' exists. ##################
#
# Input: $t0 (integer [0..239], SOS index)
# Output: $v0 (1: SOS found, 0: SOS not found)
#
CheckSOS:
subu $sp, $sp, 4 # Decrement the $sp to make space for $ra.
sw $ra, ($sp) # Push the return address, $ra.
subu $sp, $sp, 4 # Decrement the $sp to make space for $t1.
sw $t1, ($sp) # Push the $t1.
li $v0, 0
# Checking 'S'
lb $a0, SOS($t0)
jal C2I
mul $t1, $a0, 2
lh $t1, offset($t1)
lb $t1, board($t1)
beq $t1, 'S', L11
add $t0, $t0, 2
j L13
# Checking 'O'
L11: add $t0, $t0, 1
lb $a0, SOS($t0)
jal C2I
mul $t1, $a0, 2
lh $t1, offset($t1)
lb $t1, board($t1)
beq $t1, 'O', L12
add $t0, $t0, 1
j L13
# Checking 'S'
L12: add $t0, $t0, 1
lb $a0, SOS($t0)
jal C2I
mul $t1, $a0, 2
lh $t1, offset($t1)
lb $t1, board($t1)
bne $t1, 'S', L13
li $v0, 1 # An SOS found
L13: lw $t1, ($sp) # Pop $t1.
addu $sp, $sp, 4 # Increment the $sp.
lw $ra, ($sp) # Pop the return address, $ra.
addu $sp, $sp, 4 # Increment the $sp.
jr $ra # Return.
#
############## Convert character [0..z] to integer [0..35]. ##################
#
# Input: $a0 (character [0..z])
# Output: $a0 (integer [0..35])
#
C2I: blt $a0, '0', L20
bgt $a0, '9', L20
sub $a0, $a0, '0'
j L21
L20: sub $a0, $a0, 'a'
add $a0, $a0, 10
L21: jr $ra # Return.
#
############## Convert integer [0..35] to character [0..z]. ##################
#
# Input: $a0 (integer [0..35])
# Output: $a0 (character [0..z])
#
I2C: bgt $a0, 9, L30
add $a0, $a0, '0'
j L31
L30: sub $a0, $a0, 10
add $a0, $a0, 'a'
L31: jr $ra # Return.
|
|
|
|
|
|
|
|
| No. | Directive | Description | |
|---|---|---|---|
| 1 | .ascii "string" |
Allocating space for string | |
| 2 | .asciiz "string" |
Allocating space for string, NULL terminated | |
| 3 | .byte |
Allocating space for a byte | |
| 4 | .data |
Beginning of data section | |
| 5 | .globl name |
Making the following name be a global symbol | |
| 6 | .half |
Allocating space for a half word (two bytes) | |
| 7 | .space n |
Allocating n bytes of space |
|
| 8 | .text |
Beginning of text section | |
| No. | Instruction | Operation | Description | 1 | add rd, rs, rt |
rd = rs + rt |
Add;rd: destination register, rs: first source register, and rt: second source register or immediate value.Check MIPS Registers and Usage Convention. |
| 2 | addu rd, rs, rt |
rd = rs + rt (no overflow) |
Add unsigned |
| 3 | beq rs, rt, label |
if rs==rt then goto label |
Branch if equal to |
| 4 | beqz rs, label |
if rs==0 then goto label |
Branch if equal to zero |
| 5 | bgez rs label |
if rs≥0 then goto label |
Branch if greater than or equal to zero |
| 6 | bgt rs, rt, label |
if rs>rt then goto label |
Branch if greater than |
| 7 | ble rs, rt, label |
if rs≤rt then goto label |
Branch if less than or equal to |
| 8 | blt rs, rt, label |
if rs<rt then goto label |
Branch if less than |
| 9 | bne rs, rt, label |
if rs≠rt then goto label |
Branch if not equal to |
| 10 | bnez rs, label |
if rs≠0 then goto label |
Branch if not equal to zero |
| 11 | j label |
jump to label |
Jump |
| 12 | jal label |
jump to label and save the return address in $31 or $ra |
Jump and link |
| 13 | jr rs |
jump to [rs]; [ ]: contents of |
Jump and link |
| 14 | la rd, mem |
rd = address( mem ) |
Load address |
| 15 | lb rd, mem |
rd = mem |
Load byte |
| 16 | lh rd, mem |
rd = mem |
Load half word |
| 17 | li rd, imm |
rd = imm |
Load immediate |
| 18 | lw rd, mem |
rd = mem |
Load word |
| 19 | move rd, rs |
rd = rs |
Move register |
| 20 | mul rd, rs, rt |
rd = rs × rt |
Multiply |
| 21 | sb rs, mem |
mem = rs |
Store byte |
| 22 | sub rd, rs, rt |
rd = rs - rt |
Subtract |
| 23 | subu rd, rs, rt |
rd = rs - rt (no overflow) |
Subtract unsigned |
| 24 | sw rs, mem |
mem = rs |
Store word |
| 25 | syscall |
|
System call; check System Services. |
| 26 | xor rd, rs, rt |
rd = rs xor rt |
Bitwise exclusive or |
| Service | Code in $v0 |
Arguments | Result |
|---|---|---|---|
| print_int | 1 | $a0 = integer to be printed |
|
| print_float | 2 | $f12 = float to be printed |
|
| print_double | 3 | $f12 = double to be printed |
|
| print_string | 4 | $a0 = address of string in memory |
|
| read_int | 5 | integer returned in $v0 |
|
| read_float | 6 | float returned in $v0 |
|
| read_double | 7 | double returned in $v0 |
|
| read_string | 8 | $a0 = address of string input buffer$a1 = length of string buffer (n) |
|
| malloc | 9 | $a0 = amount |
address in $v0 |
| exit | 10 | ||
| print character | 11 | $a0 = character to be printed |
|
| read character | 12 | character returned in $v0 |
|
| random int range | 42 | $a0 = i.d. of pseudorandom number generator (any int).$a1 = upper bound of range of returned values. |
$a0 contains pseudorandom, uniformly distributed int value
in the range 0 ≤ [int] < [upper bound], drawn from this random number generator’s sequence. |