アセンブリのソートについての質問
Posted: 2017年12月26日(火) 13:28
今までのやつは沢山あり、ややこしいので、新しい質問項目にしました。
そこで、今回はアセンブリの問題に取り組んでいて、仕様は
キーボードから入力したデータを昇順にソートして小さい順に表示する sml2のアセンブラプログラム ex01.txtを作成せよ。ただし,配列に入力後,配列をソートする部分は関数とし,prec, call, dclv, rtrn, stof, lodf を用いること。
今わかる範囲でコードを書いてみました。
ソートするプログラム
prec, call, dclv, rtrn, stof, lodf についてよくわかりません。多分わたしとしてはどこかの番地に付け加えいいと思う。
これが命令表記です。
実行は私がやります。だから、precなどについて詳しく解説をお願いします。(解説つき)
そこで、今回はアセンブリの問題に取り組んでいて、仕様は
キーボードから入力したデータを昇順にソートして小さい順に表示する sml2のアセンブラプログラム ex01.txtを作成せよ。ただし,配列に入力後,配列をソートする部分は関数とし,prec, call, dclv, rtrn, stof, lodf を用いること。
今わかる範囲でコードを書いてみました。
ソートするプログラム
0, nop, -1
1, read, -1
2, store, 0
3, read, -1
4, store, 1
5, read, -1
6, store, 2
7, read, -1
8, store, 3
9, read, -1
10, store, 4
11, read, -1
12, store, 5
13, read, -1
14, store, 6
15, ldi, 7
16, store, 15
17, load, 6
18, load, 5
19, opr2, gtr
20, cjump, 27
21, load, 6
22, store, 16
23, load, 5
24, store, 6
25, load, 16
26, store, 5
27, load, 5
28, load, 4
29, opr2, gtr
30, cjump, 37
31, load, 5
32, store, 16
33, load, 4
34, store, 5
35, load, 16
36, store, 4
37, load, 4
38, load, 3
39, opr2, gtr
40, cjump, 47
41, load, 4
42, store, 16
43, load, 3
44, store, 4
45, load, 16
46, store, 3
47, load, 3
48, load, 2
49, opr2, gtr
59, cjump, 57
51, load, 3
52, store, 16
53, load, 2
54, store, 3
55, load, 16
56, store, 2
57, load, 2
58, load, 1
59, opr2, gtr
60, cjump, 67
61, load, 2
62, store, 16
63, load, 1
64, store, 2
65, load, 16
66, store, 1
67, load, 1
68, load, 0
69, opr2, gtr
70, cjump, 77
71, load, 1
72, store, 16
73, load, 0
74, store, 1
75, load, 16
76, store, 0
77, load, 15
78, ldi, 1
79, opr2, sub
80, store, 15
81, load, 15
82, ldi, 0
83, opr2, gtr
84, cjump, 86
85, jump, 17
86, load, 0
87, print, -1
88, load, 1
89, print, -1
90, load, 2
91, print, -1
92, load, 3
93, print, -1
94, load, 4
95, print, -1
96, load, 5
97, print, -1
98, load, 6
99, print, -1
100, halt, -1
0 nop なし -1 "(no operation)operand無し(形式的に -1).no operation; なにもせずに pcを1増やす(次の命令に進む).
"
1 ldi なし 即値 (load immediate data)operandの即値をstackにpushし,pcを1増やす.
2 opr1 なし "単項演算
識別子
(即値)" "operandの即値が示す単項演算をstackに対して実施し,pcを1増やす.
単項演算の種類と意味については sml2_conf.h を参照せよ.
"
3 opr2 なし "二項演算
識別子
(即値)" "operandの即値が示す2項演算をstackに対して実施し,pcを1増やす.
2項演算の種類と意味については sml2_conf.hを参照せよ.
"
4 print "なし
動作の変更有り" "0以外→改行
0→改行しない" "operandが0以外の時(とくに -1の時など),stack topの値を表示して改行する.pcを1増やす.
operandが0の時,stack topの値を表示するが改行しない.pcを1増やす.
いずれの場合でも popしない.従って,stack_ptrは変化しない.この変更に伴い,del命令(11)を導入した."
5 read なし -1 "operand無し(形式的に -1).キーボード入力をstackにpushし,pcを1増やす.
"
6 jump なし "insts 内
絶対番地
(即値)" "pcの値をoperandの値(即値)とする.つまり,operandが示す番地(絶対番地)にジャンプする.
"
7 cjump なし "insts 内
絶対番地
(即値)" "stack topの値が0(偽)の時,popしてjumpする.そうでない場合単にpopし,pcを1増やす.
※1(真)でjumpではないので注意.
"
8 store なし "mem 内
絶対番地
(即値)" "stack topの値をpopして,operand(即値)が示すmem領域の番地に格納し,pcを1増やす.
"
9 load なし "mem 内
絶対番地
(即値)" "operand(即値)が示すmem領域の番地の値を stack にpushし,pcを1増やす.
"
10 halt なし -1 "operand無し(形式的に -1).実行を終了する.
"
11 "del
" 新規 -1 operand無し(形式的に -1).stack topをpopし,その値をstoreせず単に捨てる.pcを1増やす.
12 prec 新規 関数の引数の個数(arity) "関数の呼び出しの準備をするために用いる.この命令は call命令とペアとなり,call命令の直前に実行されなければならない.①prec命令実行前の b_regの値を fstackにpush. ②関数処理終了後(rtrn命令実行後)のprogram counter (pc)の値(戻り番地という)をfstackにpush.③operand(即値)が示す arity個の実引数を stack からpopして fstack にコピーする※.④pcを1増やす.
※③のコピーの順序は stackに先に積まれたものが fstackにも先に積まれるようにする.このため,少なくともpopあるいはpushの一方はsml0で用意したものとは別に(block_pop()やblock_push()など)用意する必要がある.または,このデータ移動のための専用の関数(block_mv())を用意する."
13 call 新規 insts内の関数の開始番地 関数呼び出しに用いる.この命令は prec命令とペアとなり,prec命令の直後に実行されなければならない.pcをoperand(即値)の値に変更する.つまり次に実行する命令番地は関数の開始番地となる.現状では jump命令と全く同じ.
14 dclv 新規 局所変数の個数 operandで指定された個数分の局所変数の領域を fstack に確保し,pcを1増やす.確保した領域は 0クリアする.
15 rtrn 新規 -1 operand無し.形式的に -1.関数の呼び出しから復帰する.base registerの値や pcの値を fstackから復元する.fstack_ptrは関数呼び出し前の関数frameの最後のデータの場所を指すようになる.具体的にはつぎの3処理を順に行う.①fstack_ptr = b_reg-1 とする.②pc = fstack[b_reg+1] とする.③b_reg = fstack[b_reg] とする.
16 stof 新規 fstack内局所変位 stackを popして,popされた値を fstack に格納し,pcを1増やす.値の操作は具体的にはつぎのようになる.dをoperandの即値とするとき, stackをpopし,popされた値を fstack[b_reg+2+d]に格納する.dのことを局所変位(local displacement)という.
17 lodf 新規 fstack内局所変位 operand(即値)が示す番地の fstack の値を stack にpushし,pcを1増やす.値の操作は具体的にはつぎのようになる.dをoperandの即値とするとき, fstack[b_reg+2+d]にある値を stackに積む.dのことを局所変位(local displacement)という.
18 putch printc ascii文字コード(即値) operand(asciiコードで1文字分,即値)を表示し,pcを1増やす.stackは参照しないので,popはしない.
19 val 新規 配列の先頭となる mem[]の番地 operandの値(array_base)にstack topの値(disp)を加えた値(mem_addr=array_base+disp)で示されるmem[]の番地に格納されている値(mem[mem_adr])をstack topに移動し,pcを1増やす.(stack topの値は上書きされて, mem[mem_adr]に等しくなる)stack_ptrは変化しない.
20 ass 新規 配列の先頭となる mem[]の番地 operandの値(array_base)にstack topの1つ下の値(disp = stack[stack_ptr - 1])を加えた値(mem_addr = array_base + disp)で示されるmem[]の番地(mem[mem_adr])に,stack topの値(v)を格納し,stack_ptrを2減らす.pcを1増やす.
21 assv 新規 配列の先頭となる mem[]の番地 operandの値(array_base)にstack topの1つ下の値(disp = stack[stack_ptr - 1])を加えた値(mem_addr = array_base + disp)で示されるmem[]の番地(mem[mem_adr])に,stack topの値(v)を格納し,さらに値(v)をstack topの一つ下(stack[stack_ptr - 1])に格納する.stack_ptrは 1減らす.※注:pcの増加数の違いを除けば,assvは ass命令を実行後,元stack topに在った値 vを再度pushすることに相当する.ただし,ass命令実行後には vは mem上にあり stack上には無くなっているので,assv命令を使用しない場合には,v自体を知っている,もしくは memの何処に格納したかを知っていることが必要である.
実行は私がやります。だから、precなどについて詳しく解説をお願いします。(解説つき)