The Elements of Computing Systems, second edition: Building a Modern Computer from First Principles

VMTranslatorの途中で断念

2023年8月9日、難しくてp.169までで断念した。初回はここ。

VMトランスレーター後半 / write_function()、write_return() / SimpleFunction.vm

Chapter 8 今度はwrite_function()とwrite_return()とをCode_Writer.pyに追加する。Figure 8.5 (p.161)の疑似コードを実装する。テキストに用意されているSimpleFunction.vmで試す。 Code_Writer.py: class Code_Writer: def __init__(self, file_path): sel…

VMトランスレーター後半 / FibonacciSeries.vm

Chapter 8 今度はフィボナッチ数列を求める。Code_Writer.pyもVM_Translator.pyもスクリプト本体は前回と同じ。 VM_Translator.py: from Parser import * from Code_Writer import * # .vmファイルを入力して.asmファイルを出力する。 class VM_Translator: …

VMトランスレーター後半 / write_label()、write_goto()、write_if() / BasicLoop.vm

Chapter 8 Code_Writer.pyにwrite_label()、write_goto()、write_if()という3つの函数を加える。 Code_Writer.py: class Code_Writer: def __init__(self, file_path): self.file = open(file_path, "w") self.label_count = 0 self.calcs = { "neg":"M=-D",…

VMの仕様パート2 / プログラムのエントリーポイント / 非公式訳

p.159 プログラムのエントリーポイント どのJackプログラムも、そのうちの1ファイルにはMain.jackという名前をつけなければならず、かつこのファイルに含まれている函数の1つにはmainという名前をつけなければなりません。したがってコンパイル後は、どのVM…

VMの仕様パート2 / VMプログラム / 非公式訳

pp.158-159 VMプログラム VMプログラム(訳註: ここではスタックマシン)は、Jackなどの言語で書かれた高水準プログラムによって生成されます。次章で見るように、高水準プログラムJackは、いくつかの.jackクラスファイルを1個のフォルダーにまとめたものであ…

VMの仕様パート2 / 分岐コマンド、函数コマンド / 非公式訳

p.158 分岐コマンド label label: 函数のコード内にこのコマンドが記述されると、記述された位置にラベルで名前がつけられる。ラベルで示された位置へしかジャンプできない。ラベルのスコープは、そのラベルが定義された函数の範囲内である。labelは、数字、…

VMトランスレーター / VMトランスレーターを作る / StaticTest.vm

Chapter 7 最後はStaticTest.vm。5ファイル全部合格した。これでVMトランスレーターの半分が出来たことになる。 if __name__ == "__main__": a = VM_Translator("StaticTest.vm") a.code_writer.set_pointer("SP", 256) a.generate_asm() 正解: 実行結果:

VMトランスレーター / VMトランスレーターを作る / PointerTest.vm

Chapter 7 今度はPointerTest.vm。 if __name__ == "__main__": a = VM_Translator("PointerTest.vm") a.code_writer.set_pointer("SP", 256) a.generate_asm() 正解: 実行結果:

VMトランスレーター / VMトランスレーターを作る / BasicTest.vm

Chapter 7 今度はBasicTest.vm。 if __name__ == "__main__": a = VM_Translator("BasicTest.vm") a.code_writer.set_pointer("SP", 256) a.code_writer.set_pointer("LCL", 300) a.code_writer.set_pointer("ARG", 400) a.code_writer.set_pointer("THIS", …

VMトランスレーター / VMトランスレーターを作る / StackTest.vm

Chapter 7 今度はStackTest.vm。 if __name__ == "__main__": a = VM_Translator("StackTest.vm") a.code_writer.set_pointer("SP", 256) a.generate_asm() 正解: 実行結果:

VMトランスレーター / VMトランスレーターを作る / SimpleAdd.vm

Chapter 7 テキストが用意しているテストファイルで動作確認をする。 まずSimpleAdd.vm (7+8=15)を計算する。 from Parser import * from Code_Writer import * # .vmファイルを入力して.asmファイルを出力する。 class VM_Translator: def __init__(self, v…

VMトランスレーター / Code_Writerを作る / pushとpopと

Chapter 7 残っていたpushとpopとを追加してChapter 7のCode_Writerは終わり。 class Code_Writer: def __init__(self, file_path): self.file = open(file_path, "w") self.label_count = 0 self.calcs = { "neg":"M=-D", "not":"M=!D", "add":"M=D+M", "su…

VMトランスレーター / Code_Writerを作る / 比較演算子

Chapter 7 今度は比較演算子。 class Code_Writer: def __init__(self, file_path): self.file = open(file_path, "w") self.label_count = 0 self.calcs = { "neg":"M=-D", "not":"M=!D", "add":"M=D+M", "sub":"M=M-D", "and":"M=D&M", "or":"M=D|M",} sel…

VMトランスレーター / Code_Writerを作る / 和、差、論理積、論理和

Chapter 7 今度は和、差、論理積、論理和を追加する。 class Code_Writer: def __init__(self, file_path): self.file = open(file_path, "w") self.calcs = { "neg": "M=-D", "not": "M=!D", "add": "M=D+M", "sub": "M=M-D", "and": "M=D&M", "or": "M=D|M…

VMトランスレーター / Code_Writerを作る / 単項演算子

Chapter 7 まずは簡単な単項演算子だけを実装する。 class Code_Writer: def __init__(self, file_path): self.file = open(file_path, "w") def write_arithmetic(self, command): # まず最後尾値をDレジスタに取り出して、 self.__decrement_pointer("SP")…

VMトランスレーター / Parserを作る

Chapter 7 今度はVMトランスレーター。假想マシン(ここではスタックマシン)をアセンブリに変換する。第7章ではpush、pop、算術・論理演算だけを実装する。まずはParserを作る。各コマンドをオペレーターとオペランドとに分ける。アセンブラのときと同じくPyt…

簡単なスタックマシン

というわけでスタックマシンを知ったので、四則演算のみであるが作ってみる。要は逆ポーランド記法の電卓であった。 下のコードは演算子に対してもEnterしなければならないところがダサい。 stack = [] while True: key_in = input() try: stack.append(eval…

各メモリーセグメントのマッピング / 抄訳

pp.137-138 local、argument、this、that: これらのセグメントはVMトランスレーターによって動的にホストRAMへマップされます。各セグメントのベースアドレスはそれぞれLCL、ARG、THIS、THATに格納されます。どれか假想セグメントのi番目の要素へのアクセス…

7.4.1 Hackプラットフォームでの標準的なVMマッピング、パートI / 抄訳

pp.135ff. VMプログラム: 一連のVMコマンドから成る。ファイル名はFileName.vm。先頭の文字は大文字。VMトランスレーターがVMプログラムをアセンブリ(.asm)に変換する。 データ型: 符号つき整数のみ。trueは-1で表現し(訳註: 要するに全ビットが1)、falseは0…

7.4 実装 / 非公式訳

pp.134-135 7.4 実装 (略) たとえば典型的なフォンノイマン型マシンをターゲットプラットフォームとしましょう。この場合、ホストRAMに含まれる一部のメモリーブロックを使ってVMのスタックを表現することができます。このRAMブロックの先頭を固定ベースアド…

7.3 VMの仕様、パートI / 抄訳

pp.133-134 pushコマンド、popコマンド push segment index: segment[index]の値をスタックにプッシュする。segmentはargument、local、static、constant、this、thatのいずれか。indexは、0を含む正の整数。 pop segment index: スタックの末尾値をポップし…

7.2.3 假想メモリーセグメント / 非公式訳

p.132 7.2.3 假想メモリーセグメント (略) 高水準言語は、x、y、sum、countなどの記号変数が使えます。オブジェクトベース言語の場合、こうした変数はそれぞれ、静的変数(クラスレベル)、フィールド(オブジェクトのインスタンスレベル)、ローカル変数または…

Part Iまとめ

修正に次ぐ修正の末ようやく一往の完成を見た。ハードウェアは結局nandゲートしばりはやめて一から書き直した。 VHDLの練習としてnand2tetrisのHackコンピューターをMAX10 FPGAで作る - Qiita Hackコンピューター(nand2tetris)のアセンブラを作る - Qiita

アセンブラを作る / 最終版を作る

Chapter 6 これでPart I Hardware全6章が終わり。最初はここ。 from Parser import * from Code import * from Symbol_Table import * class Hack_Assember: def __init__(self, input_file_path): # 出力ファイル名は入力ファイル名の拡張子を.hackに変えた…

アセンブラ / ファーストパス、セカンドパス / 非公式訳

pp.108-109 ファーストパス: 行番号の順に1行ずつ最初から最後までアセンブリプログラム全体を見てゆきます。行番号は0から始めて、A命令またはC命令の見つかったときに1増やしますが、コメントまたはラベル宣言のときには増やしません。ラベル宣言(xxx)の見…

アセンブラを作る / シンボルテーブルを作る

Chapter 6 これもテキストの手順どおりに作る。ここでは辞書を使った。 class Symbol_Table: def __init__(self, num_registers=16): self.symbols = {"SP":0, "LCL":1, "ARG":2, "THIS":3, "THAT":4} self.ram_last_address = num_registers - 1 # 疑似汎用…

アセンブラを作る / Hackアセンブラベーシック版

Chapter 6 テキストの手順に従ってベーシック版(変数もジャンプラベルもなく即値のみを前提とする)のアセンブラを作る。 from Parser import * from Code import * class Hack_Assember_Basic: def __init__(self, input_file_path): # 出力ファイル名は入力…

Hackアセンブラ / 非公式訳

p.112 Hackアセンブラ これが、Parser、Codeの両モジュールの各種メソッドを使ってアセンブルプロセス全体を司るメインプログラムです。ここで説明するベーシック版アセンブラは、ソースアセンブリコードにシンボル参照が一切含まれていないことを前提としま…

アセンブラを作る / Codeクラス完成

Chapter 6 class Code: def __init__(self): pass def dest(self, mnemonic): A = (1 << 2) D = (1 << 1) M = (1 << 0) adm = 0 if "A" in mnemonic: adm |= A if "D" in mnemonic: adm |= D if "M" in mnemonic: adm |= M return bin(adm)[2:].zfill(3) def…