2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自作仮想マシンの自作アセンブラに向けた自作コンパイラで遊んだ話

Last updated at Posted at 2025-05-05

はじめに

x86_64コンパイラを作ろうとしたのですが、もう複雑で複雑で挫折しました。
そこで、自分で理想のISAを持つ仮想マシンを作ろうとしました。

仮想マシン

こんな感じに実行の様子が見えます。

image.png

仕様はこちら。

Ruka VM

手軽な命令セットアーキテクチャを採用した軽量仮想マシン

システム構成

名前 説明 サイズ 読み込み 書き込み
プログラム領域 実行されるバイトコードを格納 可変長 不可 不可
メモリ領域 データやオブジェクトを格納 512バイト固定 可能(アドレス指定) 可能(同左)
スタック領域 関数などとのデータ受け渡し用 可変長 可能(ポップのみ) 可能(プッシュのみ)
関数スタック 呼び出し元アドレスが積まれる 可変長 不可 不可
レジスタ群 演算時の一時的なデータ格納用 64ビット固定 可能(mov命令) 可能(同左)

※ 全ての値は64ビット浮動小数点数(f64)です。

ISA

ニーモニック 意味
MOV レジスタ, 値 データ転送
ADD レジスタ, 値 足し算
MUL レジスタ, 値 掛け算
NEG レジスタ 符号反転
INV レジスタ 逆数
EQL レジスタ, 値 等価比較
LES レジスタ, 値 大小比較
NOR レジスタ, 値 論理ORして否定
JMP 条件, アドレス 条件つきジャンプ
CAL アドレス 関数呼び出し
RET 呼び出し元に戻る
LDA レジスタ, アドレス データ読み込み
STA アドレス, 値 データ書き込み
PSH 値 スタックに追加
POP レジスタ スタックから取り出し
NOP 何もしない
HLT プログラム終了

レジスタ

名前 意味 役割
PC Program Counter 次の命令のアドレス
AR Accumulator Register 演算結果の格納
DR Data Register データの格納
CR Conditional Register 条件の格納
BA Base Address メモリの基底アドレス
SP Stack Pointer スタックに長さ

コンパイラ群

コンパイラを作りました。現在対応してるのはBASICとForthです。他の言語もこれから実装できたらなと思います。

BASIC

Let bit = (1 + 2) * 3 - 7
Let max_1byte = pow(bit, 8) - 1
Exit Program

Sub pow(x, y)
    Let n = 1
    Let i = 0
    While i < y
        Let i = i + 1
        Let n = n * x
    End While
    Return n
End Sub
コンパイルで生成されたアセンブリ
line_0:
	mov ar, 7
	psh ar
	mov ar, 1
	psh ar
	mov ar, 2
	mov dr, ar
	pop ar
	add ar, dr
	psh ar
	mov ar, 3
	mov dr, ar
	pop ar
	mul ar, dr
	mov dr, ar
	pop ar
	neg ar
	add ar, dr
	sta 0, ar	; bit

line_1:
	mov ar, 1
	psh ar
	lda ar, 0
	psh ar
	mov ar, 8
	psh ar
	cal subroutine_pow
	pop ar
	mov dr, ar
	pop ar
	neg ar
	add ar, dr
	sta 1, ar	; max_1byte

line_2:
	hlt

line_4:
subroutine_pow:
	pop ar
	sta 2, ar	; y
	pop ar
	sta 3, ar	; x

line_5:
	mov ar, 1
	sta 4, ar	; n

line_6:
	mov ar, 0
	sta 5, ar	; i

line_7:
while_start_0:
	lda ar, 5
	psh ar
	lda ar, 2
	mov dr, ar
	pop ar
	les ar, dr
	mov cr, ar
	nor cr, cr
	jmp cr, while_end_0

line_8:
	lda ar, 5
	psh ar
	mov ar, 1
	mov dr, ar
	pop ar
	add ar, dr
	sta 5, ar	; i

line_9:
	lda ar, 4
	psh ar
	lda ar, 3
	mov dr, ar
	pop ar
	mul ar, dr
	sta 4, ar	; n

line_10:
	jmp 1, while_start_0
while_end_0:

line_11:
	lda ar, 4
	psh ar
	ret

line_12:
	ret


Forth

思ったよりパーサーの実装が難しかったです。

dup : 2 * ;
half : 2 / ;

main :
    5 dup dup half
    10 =
        ? 1 2
        ¥ 3 4
    # + half
    8 ! ;
コンパイルで生成されたアセンブリ
	cal word_main
	hlt
word_dup:
	psh 2
	pop dr
	pop ar
	mul ar, dr
	psh ar
	ret
word_half:
	psh 2
	pop dr
	pop ar
	inv dr
	mul ar, dr
	psh ar
	ret
word_main:
	psh 5
	cal word_dup
	cal word_dup
	cal word_half
	psh 10
	pop dr
	pop ar
	eql ar, dr
	psh ar
	pop cr
	jmp cr, then_0
	jmp 1, else_0
then_0:
	psh 1
	psh 2
	jmp 1, end_0
else_0:
	psh 3
	psh 4
end_0:
	pop dr
	pop ar
	add ar, dr
	psh ar
	cal word_half
	psh 8
	pop ba
	pop ar
	sta ba, ar
	ret

日本語プログラミング言語Mind風の文法

倍 とは 2 を 掛 ける こと。
半分 とは 2 で 割 る こと。

始まり とは
    5 の 倍 の 倍 の 半分 が
    10 と 等 しい
        ならば 1 と 2 を
        でなければ 3 と 4 を
    つぎに
    足 しあわせて 半分 にして
    メモリの 8 番地に 書 きこむ こと。

感想

ちょうど子供の日なので良いおもちゃになったと思います。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?