そこで、今回はアセンブリの問題に取り組んでいて、仕様は
キーボードから入力したデータを昇順にソートして小さい順に表示する 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などについて詳しく解説をお願いします。(解説つき)