The Elements of Computing Systems, second edition: Building a Modern Computer from First Principles
2023年8月9日、難しくてp.169までで断念した。初回はここ。
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…
Chapter 8 今度はフィボナッチ数列を求める。Code_Writer.pyもVM_Translator.pyもスクリプト本体は前回と同じ。 VM_Translator.py: from Parser import * from Code_Writer import * # .vmファイルを入力して.asmファイルを出力する。 class VM_Translator: …
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",…
p.159 プログラムのエントリーポイント どのJackプログラムも、そのうちの1ファイルにはMain.jackという名前をつけなければならず、かつこのファイルに含まれている函数の1つにはmainという名前をつけなければなりません。したがってコンパイル後は、どのVM…
pp.158-159 VMプログラム VMプログラム(訳註: ここではスタックマシン)は、Jackなどの言語で書かれた高水準プログラムによって生成されます。次章で見るように、高水準プログラムJackは、いくつかの.jackクラスファイルを1個のフォルダーにまとめたものであ…
p.158 分岐コマンド label label: 函数のコード内にこのコマンドが記述されると、記述された位置にラベルで名前がつけられる。ラベルで示された位置へしかジャンプできない。ラベルのスコープは、そのラベルが定義された函数の範囲内である。labelは、数字、…
Chapter 7 最後はStaticTest.vm。5ファイル全部合格した。これでVMトランスレーターの半分が出来たことになる。 if __name__ == "__main__": a = VM_Translator("StaticTest.vm") a.code_writer.set_pointer("SP", 256) a.generate_asm() 正解: 実行結果:
Chapter 7 今度はPointerTest.vm。 if __name__ == "__main__": a = VM_Translator("PointerTest.vm") a.code_writer.set_pointer("SP", 256) a.generate_asm() 正解: 実行結果:
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", …
Chapter 7 今度はStackTest.vm。 if __name__ == "__main__": a = VM_Translator("StackTest.vm") a.code_writer.set_pointer("SP", 256) a.generate_asm() 正解: 実行結果:
Chapter 7 テキストが用意しているテストファイルで動作確認をする。 まずSimpleAdd.vm (7+8=15)を計算する。 from Parser import * from Code_Writer import * # .vmファイルを入力して.asmファイルを出力する。 class VM_Translator: def __init__(self, v…
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…
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…
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…
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")…
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番目の要素へのアクセス…
pp.135ff. VMプログラム: 一連のVMコマンドから成る。ファイル名はFileName.vm。先頭の文字は大文字。VMトランスレーターがVMプログラムをアセンブリ(.asm)に変換する。 データ型: 符号つき整数のみ。trueは-1で表現し(訳註: 要するに全ビットが1)、falseは0…
pp.134-135 7.4 実装 (略) たとえば典型的なフォンノイマン型マシンをターゲットプラットフォームとしましょう。この場合、ホストRAMに含まれる一部のメモリーブロックを使ってVMのスタックを表現することができます。このRAMブロックの先頭を固定ベースアド…
pp.133-134 pushコマンド、popコマンド push segment index: segment[index]の値をスタックにプッシュする。segmentはargument、local、static、constant、this、thatのいずれか。indexは、0を含む正の整数。 pop segment index: スタックの末尾値をポップし…
p.132 7.2.3 假想メモリーセグメント (略) 高水準言語は、x、y、sum、countなどの記号変数が使えます。オブジェクトベース言語の場合、こうした変数はそれぞれ、静的変数(クラスレベル)、フィールド(オブジェクトのインスタンスレベル)、ローカル変数または…
修正に次ぐ修正の末ようやく一往の完成を見た。ハードウェアは結局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 # 疑似汎用…
Chapter 6 テキストの手順に従ってベーシック版(変数もジャンプラベルもなく即値のみを前提とする)のアセンブラを作る。 from Parser import * from Code import * class Hack_Assember_Basic: def __init__(self, input_file_path): # 出力ファイル名は入力…
p.112 Hackアセンブラ これが、Parser、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…