課題1(メモリアクセス・大域配列)
キーボードから読み込んだ複数の整数値をメモリー上に一時保存し、読み込みが完了してから総和の計算を行ないたい。これを実現するための以下の2つのサブルーチンを作成せよ。実行して正しく機能することを示すこと.
その1:サブルーチンsum
【機能】引数$a0で指定されたアドレスから始まるメモリーに、引数$a1で指定された個数の32ビット整数値が格納されているとし、これらの総和を求めて、その値を$v0で返す。データ数を示す$a1は1以上の整数と仮定してよい。
sumへ渡す2つの引数は、C言語で言うと配列の先頭のポインタと配列の要素数に当たる。総和を求める対象は配列の要素に当たり、$a0 で渡されたアドレスを1ワードずつ (4バイトずつ) 増加させることで、その要素に順にアクセスすることが可能になる。C言語における、ポインタ変数 p を増加させながら値を参照する*p++ の振舞いと同等である。
sumの機能を確かめるために、下記のテスト用メインルーチンを使用しても良い。ただし、sumはこのテスト用メインルーチンに特化した実装を行なってはならない。あくまでも、上記【機能】を満たす汎用のサブルーチンである。
sumの機能を確かめるプログラムは testsum.s とする.
# サブルーチン sum のテスト
.data
list: .word 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
.text
.globl main
main: addi $sp, $sp, -4 # スタックに1ワードの領域を確保
sw $ra, 0($sp) # 戻り先アドレスの退避
la $a0, list # 第1引数=データ領域listのアドレス
li $a1, 10 # 第2引数=10 (データ数)
jal sum # サブルーチンsumの呼び出し
move $a0, $v0 # システムコールの引数=sumの戻り値$v0 (総和)
li $v0, 1 # print_integerの指定
syscall # 総和の出力
lw $ra, 0($sp) # 戻り先アドレスの復元
addi $sp, $sp, 4 # スタックに確保した領域の開放
jr $ra
# ここから sum の定義を書く
その2:サブルーチンread
【機能】引数$a0で指定されたアドレスから始まるメモリ領域に対し、引数$a1で指定された個数の32ビット整数をキーボードから読み込み順次格納する。C言語で言う配列に整数値を順次読み込む機能と考えてよい。データ数を示す$a1は1以上の整数と仮定してよい。
サブルーチンreadでは整数値の読み込みのためにシステムコールが必要になる。また引数として受け取った$a0、$a1もシステムコールで値が変更される可能性があるため、そのまま継続して利用するのは不適切である。
readとsum を組み合わせたの時の動作を確かめるために、下記のメインルーチンを使用してもよい。ただし、readとsumはこのテスト用メインルーチンに特化した実装を行なってはならない。あくまでも、上記【機能】を満たす汎用のサブルーチンである。
readとsumの機能を確かめる以下のプログラムは testreadsum.s とする.
# サブルーチン read, sum のテスト
# スタック上に5ワード分の読み込み用バッファ領域を確保して、
# 5つの値の読み込みと総和の計算を実行する。
.text
.globl main
main: addi $sp, $sp, -24 # スタックに 6 ワードの領域を確保
# 0($sp)は$raの待避用
# 4($sp)から5ワード分は配列変数として利用する
sw $ra, 0($sp) # 戻り先アドレスの退避
addi $a0, $sp, 4 # 第1引数 配列変数用領域のアドレス ($sp + 4)
li $a1, 5 # 第2引数=5 (データ数)
jal read # サブルーチン read の呼び出し
# → 配列変数にデータが読み込まれる
addi $a0, $sp, 4 # 第1引数=配列変数用領域のアドレス ($sp + 4)
li $a1, 5 # 第2引数=5 (データ数)
jal sum # サブルーチン sum の呼び出し
# → $v0に総和が入る
move $a0, $v0 # システムコールの引数 = sumの戻り値$v0 (総和)
li $v0, 1 # print_integerの指定
syscall # 総和の出力
lw $ra, 0($sp) # 戻り先アドレスの復元
addi $sp, $sp, 24 # スタックに確保した領域の開放
jr $ra
# ここから sum と read の定義を書く
課題2(サブルーチンの入れ子)「互いに素であることの判定」
2つの自然数aとbの最大公約数を計算するサブルーチン"gcd"を作成し、これを用いてaとbが互いに素であるかどうか判定するプログラム"coprime.s"を作成せよ。最大公約数の算法としてはユークリッドの互除法が有名である。サブルーチンgcdは再起呼び出しでないアルゴリズムで実装すること。
(spim) load "coprime.s"
(spim) run
a= 24
b= 12
not coprime
(spim) run
a= 24
b= 23
coprime
(spim)
サブルーチンgcdの機能を確かめるためのmainプログラムは次のものを使って良い。gcdは2つの整数を$a0と$a1で受け取り、その最大公約数を計算して$v0で返す。
#--------------------------------------------------------------------------
#
# gcd: 入力された2整数の最大公約数を計算する(2整数は0以上であると仮定)
# 非再帰的アルゴリズム
#
# 情報領域演習第二C演習第4回課題2(2026年6月26日)
#
#
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# データセグメント
#--------------------------------------------------------------------------
.data
prmpta: .asciiz "a= " # aの入力プロンプト
prmptb: .asciiz "b= " # bの入力プロンプト
ans: .asciiz "gcd(a,b)= " # aとbの最大公約数
newln: .asciiz "\n" # 改行
#--------------------------------------------------------------------------
# テキストセグメント
#--------------------------------------------------------------------------
.text
.globl main
main: sub $sp, $sp, 4 # スタックに1ワードの領域を確保
sw $ra, 0($sp) # 戻り先アドレスの退避
li $v0, 4 # print the prompt "a = "
la $a0, prmpta
syscall
li $v0, 5 # read integer from the keyboard
syscall
move $t0, $v0 # $t0 <- a
li $v0, 4 # print the prompt "b = "
la $a0, prmptb
syscall
li $v0, 5 # read integer from the keyboard
syscall
move $t1, $v0 # $t1 <- b
# gcd関数を呼び出す
move $a0, $t0 # 引数1 (a)
move $a1, $t1 # 引数2 (b)
jal gcd
move $t3, $v0 # $t3に結果を保存
# 結果の表示
li $v0, 4 # print "gcd(a,b)= "
la $a0, ans
syscall
li $v0, 1
move $a0, $t3
syscall
li $v0, 4
la $a0, newln
syscall
# プログラムの終了
lw $ra, 0($sp) # 戻り先アドレスの復元
addi $sp, $sp, 4 # スタックに確保した領域の開放
jr $ra
#--------------------------------------------------------------------------
#
# gcd: 最大公約数(greatest common divisor)をユークリッドの互除法で計算
#
# 入力
# $a0:a
# $a1:b
#
# 出力
# $v0:gcd(a,b) aとbの最大公約数
#
#--------------------------------------------------------------------------
gcd: ...
サブルーチンcoprimeの機能を確かめるためのmainプログラムは次のものを使って良い。coprimeは2つの整数を$a0と$a1で受け取り、互いに素であれは整数値1を、互いに素ではない場合は整数値0を$v0で返す。
#--------------------------------------------------------------------------
#
# coprime: 入力された2整数が互いに素であるかどうか判定する
#
# 情報領域演習第二C演習第3回課題2(2026年6月26日)
#
#
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# データセグメント
#--------------------------------------------------------------------------
.data
prmpta: .asciiz "a= " # aの入力プロンプト
prmptb: .asciiz "b= " # bの入力プロンプト
yes: .asciiz "coprime\n" # 互いに素である
no: .asciiz "not coprime\n" # 互いに素ではない
#--------------------------------------------------------------------------
# テキストセグメント
#--------------------------------------------------------------------------
.text
.globl main
main: sub $sp, $sp, 4 # スタックに1ワードの領域を確保
sw $ra, 0($sp) # 戻り先アドレスの退避
li $v0, 4 # print the prompt "a = "
la $a0, prmpta
syscall
li $v0, 5 # read integer from the keyboard
syscall
move $t0, $v0 # $t0 <- a
li $v0, 4 # print the prompt "b = "
la $a0, prmptb
syscall
li $v0, 5 # read integer from the keyboard
syscall
move $t1, $v0 # $t1 <- b
# coprime関数を呼び出す
move $a0, $t0 # 引数1 (a)
move $a1, $t1 # 引数2 (b)
jal coprime
# 結果の表示
beq $v0, $zero, not_coprime
li $v0, 4
la $a0, yes
syscall
b end_main
not_coprime:
li $v0, 4
la $a0, no
syscall
end_main:
# プログラムの終了
lw $ra, 0($sp) # 戻り先アドレスの復元
addi $sp, $sp, 4 # スタックに確保した領域の開放
jr $ra
#--------------------------------------------------------------------------
#
# comprime: 入力された2整数が互いに素であるかどうか判定する
#
# 入力
# $a0:a
# $a1:b
#
# 出力
# $v0:1 (互いに素である)
# :0 (互いに素ではない)
#
#--------------------------------------------------------------------------
coprime: ...
課題3:文字列の処理
入力れた文字列中の文字種を判定するプログラム"charkind.s"を作れ.
入力文字列を格納するための ASCII型の長めのバッファの定義と、バッファ中の文字位置を差し示すポインタが必要である。
空白は "s"、演算子(+, -, *, /)は"O"、数字は"D"と表示する(下記実行例を参照)。
文字種の判定にはASCII文字コードにおいて、NULLは0、改行は10、空白は32、数字は48(文字リテラルは'0')から57(文字リテラルは'9')であることを利用する。
(spim) load "charkind.s"
(spim) run
expression: 3 4 +
DsDsO
(spim)
charkindのプログラム例の冒頭を以下に示す。
#--------------------------------------------------------------------------
#
# charkind: 入力された文字列中の文字種を判定する
#
# 文字種は次の3種類
# 空白: s
# 数字(1桁):D
# 演算子(+,-,*,/):O
#
# 情報領域演習第二C演習第3回課題3(2026年6月26日)
#
#
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# データセグメント
#--------------------------------------------------------------------------
.data
prompt: .asciiz "expression: " # プロンプト
isspc: .asciiz "s" # 空白
isopr: .asciiz "O" # 演算子
isdgt: .asciiz "D" # 数字
newln: .asciiz "\n" # 改行
buffer: .space 1024 # 入力文字列バッファ(1024バイト)
SPIMプログラム開発と動作確認について
★ MIPSシミュレータSPIMの使い方については SPIM を参照のこと。
★ SPIMをリセットするためには reinitialize コマンドを使ってください。このコマンドは、SPIMを起動したまま修正したプログラムを読み込む前に実行します。
★ 実行例は複数示す必要があります。その他、課題実行、レポート作成にあたっては レポート に従うこと。