【アセンブリ】入力されたn番目の素数を表示するプログラム【MIPS】
以前アセンブリで、100番目までの素数を求めるプログラムを作ったが、それを応用して今度は、ユーザから受け取った入力nに対して、n番目の素数を表示するプログラムを作ってみる。
ということで、以下の記事を参考にしながらプログラムを書き直してみる。
http://www.swlab.cs.okayama-u.ac.jp/~nom/lect/p3/what-is-array-in-asm.html
【アセンブリ】再帰で10の階乗を求めるプログラムを通して手続き呼び出し規約を理解する学習ノート【MIPS】 - 凸ろぐ
配列の実現
アセンブリでの配列の実現方法について考察してみる。
まず以下で、400バイト分の領域を確保できる。
array: .space 400
32bitsコンピュータでは4バイト単位でデータを整列化するので、これは100個分のデータ(int)を格納できるわけかな。
そしたら今度はmain部分を書いていく。
$a0
にはさっき宣言したデータの塊のアドレスarrayを$a0に格納してる。そしたらそのあと0($a0)
で先頭のデータを取り出す。
main: la $a0, array # $a0 に array (=8000)を代入する lw $a1, 0($a0) # $a0 のアドレスから 4バイト(word) # 取り出して $a1 に代入(load)
そしたら今度は指定した番号の素数を$t0
を使って指定できる仕組みを作る。
addu $t0, $t0, $t0 # $t0 を2倍に addu $t0, $t0, $t0 # $t0 を更に2倍に addu $a0, $a0, $t0 # $a0 = $a0 + $t0 lw $a1, 0($a0) # 取り出して $a1 に代入(load)
adduを二回して4倍にしてるのが賢い。かなり計算が速くなる気がする。
計算した$t0
は先頭から何バイト目にあるデータをとればいいのか指してる状態になってる。それを$a0
と足したものを$a0
に代入。
それを取り出して代入すれば、$a1
には目的のデータが入ってる、って寸法やな。0($a0)
って使うんだなぁ。ふーん...
そして次は、array[$t0]++を作る。
addu $a1, $a1, 1 sw $a1, 0($a0) # $a0 のアドレスに 4バイト(word) # を書込む(store)
上記サイトに
$a1 の値に1加えて,再び同じメモリに書込めば, array[$t0]++ を実現したことになりますね.
という記述があるけど、これが理解できない。
とりあえずこれでできるのだね。ひとまずおk...
配列の実験プログラム
配列を試すための実験的なプログラムを作成してみた。
$a1には最初に配列の頭を指すアドレスが入ってるのだけど、それを4バイトずつずらしていくのがみそかな。
array: .space 40 .text main: la $a1, array li $t0, 4 sw $t0, 0($a1) lw $t1, 0($a1) li $v0, 1 lw $a0, 0($a1) syscall li $t0, 424 addu $a1, $a1, 4 sw $t0, 0($a1) lw $a0, 0($a1) syscall
次に、これを拡張して、配列の1番目と2番目に定数を格納して、それをコンソールから指定できるプログラムを作ってみた。
array: .space 40 .text main: la $a1, array li $t0, 4 sw $t0, 0($a1) lw $t1, 0($a1) li $t0, 424 addu $a1, $a1, 4 sw $t0, 0($a1) li $v0, 5 syscall move $t2, $v0 li $v0, 1 subu $t2, $t2, 1 addu $t2, $t2, $t2 addu $t2, $t2, $t2 addu $a1, $a1, $t2 lw $a0, 0($a1) syscall
これをもとにプログラムを作ってみる
ソースコード
la
で.space
で確保した領域を何回も初期化しようとしてはいけないらしい。.space
でarrayで指定した最初のアドレスをロードするわけではなさそう。
ということに途中で気づいて、そこにつまずいていたけどなんとかうまくいった。
出力も含め、以下のようになった。
下が出力結果。