低レイヤチョットワカル(nand2tetris/コンピュータシステムの理論と実装4章)

こんにちは。敗北を知った4章です

アセンブリのとこまでやってきたけど心が折れそう

[https://www.oreilly.co.jp/books/9784873117126/:embed:cite]

記録用git

vol.1

vol.2

vol.3

vol.4 いまここ

4章 機械語

理論

アドレッシングモード

要求されたメモリのワードに対してそのアドレスを指定する方法

直接アドレッシング

引数にアドレスを直接渡してアクセスすること

LOAD R1, 67
LOAD R1, bar

イミディエイトアドレッシング

引数の値を直接渡す

LOADI R1, 67

関節アドレッシング

Hack機械語の仕様

メモリアドレス空間

  • 命令メモリ

CPUは命令メモリを読み込み実行する。リードオンリー

  • データメモリ

レジスタ

D/Aの2種類。

D=データ値を保存する。

A=データ値とアドレスレジスタと解釈される=値として利用したりアドレスとして利用したりできる

M=Aのアドレスが参照している値(仮想の値。内部でAレジスタが示すアドレスの値を取得するルール

命令

命令は、16bitである。そのうち、先頭の1bitはA/Cの選別に利用する

A命令

Aレジスタに15bitの値を設定する命令

@100 // 100Aレジスタに保存

@500 // 500Aレジスタに保存

@R0  // 先頭のレジスタをAレジスタに保存

C命令

dest = comp;jampで構成された命令。

@sum   //A命令
M=D    //C命令

@index //A命令
D=M    //C命令
D;JEQ  //C命令

シンボル

  • R0~R15は、 アドレス0~16のレジスタとして使用可能
  • @SCREENは、スクリーンの左上のアドレスを示す
  • @KBDは、キーボードの出力アドレスを示す。値は未入力なら0,入力しているなら入力値である

変数シンボル

ユーザーが定義できるシンボル。アドレスは16から始まる

@sum  // A=16である
M=1   // アドレス161が設定されている

実装

まずは掛け算 を実装。

加算減算しかできないので、愚直に実装

@sum
M=0

// 残りカウントをR1で初期化
@R1
D=M
@count 
M=D

(LOOP)
    // チェック
    @count
    D=M
    @END
    D;JEQ

    // 合計値計算
    @R0
    D=M
    @sum
    M=M+D

    // カウントを減らす
    @count
    M=M-1

    // ループ繰り返す
    @LOOP
    0;JMP
(END)

// R2に記録
@sum
D=M
@R2
M=D

@END
0;JMP

次に、スクリーンの入力に合わせて画面を白黒切り替える実装。くそほど詰まった :innocent:

// 初期化
// 最大スクリーンアドレスの計算
@8192 //256*32
D=A
@SCREEN
D=D+A
@MAXADDRESS //最大スクリーンアドレス
M=D

// 以下、無限ループ
(KEY)

@SCREEN
D=A
@address // スクリーンアドレス初期化
M=D

@KBD //キーボード取得
D=M

// 振り分け
@WHITE
D;JEQ
@BLACK
0;JMP

(WHITE)
@color
M=0
@LOOP
0;JMP

(BLACK)
@color
M=-1
@LOOP
0;JMP

// スクリーン書き換え
(LOOP)
@color
D=M

@address
A=M // 値のアドレスに移動
M=D //アドレスの値をcolorに

D=A+1 //アドレスに1加えたところに移動
@address // 必要!!!
M=D // 次に移動するために新たなアドレスを値として保存

@MAXADDRESS
D=M-D //Dが0かどうか

@LOOP
D;JNE

@KEY
0;JMP
(END)

👇この部分で2時間ほどつまった。

@addressには現在のアドレスを入れているが、A=A+1とすると同時に@addressも一つずれると思い込んでいた(実際は、@addressは元のアドレスのまま。動かない。値が動くだけ)

@address
A=M // 値のアドレスに移動
M=D //アドレスの値をcolorに

D=A+1 //アドレスに1加えたところに移動
@address // 必要!!!
M=D // 次に移動するために新たなアドレスを値として保存

See also