FUNCTIONS
call命令とret命令を追加する
call命令は...
「現在のカウンタの値+4アドレス」をスタックへPUSHし、呼び出した関数のラベル位置へジャンプする
ret命令は...
returnアドレスをPOPして、そのアドレスへジャンプする
追加命令のOpcode
00 001 000 (8): call
call sp sp_offset function_label
spはスタックポインタ
M[sp + sp_offset] = counter + 4
sp = sp + 1
jump function_label
(※)現状での実装はcallを呼ぶたびにr5がインクリメントされるため、実質spはr5固定となっている
00 001 001 (9): ret
ret sp sp_offset 0
counter = M[sp + sp_offset]
sp = sp - 1
(※)現状での実装はretを呼ぶたびにr5がデクリメントされるため、実質spはr5固定となっている
functionの呼び出し規約
r1, r2, ...で引数を渡す
結果がr1, r2へ返される
call前に必要な値はスタックへPUSHしておくこと
SP自動インクリメント
通常は第3引数にレジスタが来た時のみ save_ctrl が真となるが、call と ret が来たときも真にしたい
call の時はインクリメント、ret の時はデクリメント、そうじゃない時はALUから流れてくる値を利用してレジスタの値を更新する
(※) SPの自動インクリメント/デクリメントの実装が大変なので、SPはr5固定にしている
メモ
LEG2へSP自動インクリメントを実装するため、LEG2をコピーしてLEG3を作成、そちらへSP自動インクリメントを実装していく。
参考
スタック、スタックポインタ $sp
サンプルプログラム
code:fibonacci.rb
def fibonacci(n)
if n == 0
0
elsif n == 1
1
else
fibonacci(n - 2) + fibonacci(n - 1)
end
end
if __FILE__ == $0
p fibonacci(ARGV.shift.to_i)
end
code:fibonacci.asm
const sp 5
const n 1
const n1 2
const n2 3
# init n
add input 0 n
#
code:2_Call_ret
const add 0
const add_ri 64
const add_ii 192
const sub 1
const sub_ri 65
const jeq 32
const jeq_ii 224
const jlt 34
const jlte 35
const sw 16
const sw_ri 80
const lw 17
const lw_ri 81
const call 8
const ret 9
const r0 0
const r1 1
const r2 2
const r3 3
const r4 4
const r5 5
const sp 5
const sp_offset 4
const counter 6
const input 7
const output 7
# n = 10
expect 1 10
add_ii
10
0
r1
expect 5 1
call
sp
r0
triple
expect 7 30
add
r1
0
output
label stop
jeq
r0
r0
stop
label triple
expect 2 10
add
r1
r0
r2
expect 5 2
call
sp
r0
double
add
r1
r2
r1
ret
sp
r0
0
label double
expect 1 20
add
r1
r1
r1
expect 5 1
ret
sp
r0
0