FPGAでENC28J60を動かしたい

需要不明記事に以下のツイートを添えて

FPGAからUDPパケットを10Gbpsで送信したい、というのは非常に自然な欲求です。ですが、非常に残念なことに、この欲求を実現するには決して安くない金額が必要になります。10G Ethernetに対応したPHYが載っているFPGAボードの値段を見てみたら、4桁で単位がドルでした。ふふってなりますよね、僕はなりました。
もう一つの選択肢としてPHYを単体で購入して外付けする方法があります、これは楽しそうなので200年後くらいにやります。

それはさておき、10Mbpsなら比較的安価に、比較的手軽にFPGAからパケットを送信する方法があります。そうですね、ENC28J60です。SPIで制御可能なEthernetコントローラ!すごい!嬉しい!お手軽!
お手軽そうですね、やっていきましょう。

ja.aliexpress.com

目標:パケット送信

Ethernetケーブルを繋いでWiresharkでパケットが見るのを目標にしましょう。

FPGAとSPI

ENC28J60とFPGAを通信させるにあたって、FPGAにSPI Masterを実装する必要が出てきます。SPIの仕様を確認しましょう。

ja.wikipedia.org

SPIには4つのモードがあるようです。ENC28J60との通信に使うのはこの内のMode 0です、つまりidle時にはSCLKは0, SCLKの立ち上がりでMISOの状態を記録する, SCLKの立ち下がりでMISOに次のデータを出力ということです、
図にするとこう。

f:id:Cra2yPierr0t:20200730160300p:plain
図1 mode0の波形

ENC28J60仕様

次にENC28J60と通信するデータフォーマットを調べましょう。データシートを読みます。

f:id:Cra2yPierr0t:20200730171513p:plain
図2 データフォーマット
パケットの送信に最低限必要なレジスタは以下です

f:id:Cra2yPierr0t:20200802001653p:plain
図3 送信に最低限必要なレジスタ

つまりEWRPTを駆使しながらバッファに送信したいデータを書き込み、ETXSTとETXNDにデータの先頭と末尾のアドレスを格納し、ECON1.TXRTSにビットを立てる。を行えばデータが送信されるというわけです。
ちなみに送信したいデータというのは送信先MACアドレスやタイプも含むのでEthernetⅡやIEEE802.3のフレームの仕様書とにらめっこして頑張りましょう。CRCはENC28J80が計算してくれます。

これを理解したらステートマシンを書いて制御機構を実装するだけですね、簡単!コードはここに置いておきます。

ENC28J60/enc_driver.sv at master · Cra2yPierr0t/ENC28J60 · GitHub

既にお手軽とは?みたいな雰囲気が漂ってますが僕もそう思います。

ENC28J60プログラミング

不穏な見出しですがそれはさておき、バッファメモリに書き込むデータを検討しましょう。

Ethernet Ⅱフレームの仕様は次のようになっています。

f:id:Cra2yPierr0t:20200802025345p:plain
図4 EthernetⅡフレームの仕様

プリアンブルとFCSはENC28J60がよしなにやってくれます、ありがとうENC28J60。よって我々が決める必要があるのはMACアドレスプロトコルタイプ、パケットですね。所詮まともな処理を受けることのないパケットです、適当に決めましょう。

f:id:Cra2yPierr0t:20200802030927p:plain
図5 適当に決めたフレーム

先頭にある「制御」はパケットの制御バイトと呼びENC28J60でパケットを送信するときに、フレームの先頭に付ける必要のあるものです。実際に送信はされません。今回は0Fhを付けます。プロトコルタイプの86DDhはIPv6を示しています。 またパケットの内容ですが、私はレイヤ3以上の知識を持たないので、愛すべき弊学の略称でも詰めときましょう。

さて、必要な情報を全て揃えた今、ENC28J60に書き込むデータとアドレスの組を用意し、書き込むロジックを用意する必要があります。マジ?

QuartusでROMを生成して、ROM内に必要なデータとアドレスの組を置き、上から順にENC28J60に書き込むロジックを組めばいいですね。それで出来るんですが、その「必要なデータとアドレスの組」は誰が用意するんでしょうか、当然僕です。僕しかいないので。ツールを作りましょう。

f:id:Cra2yPierr0t:20200803005801p:plain
図6 変換
出来ました。上の図のように、命令列を.mifファイルの形式に変換してくれます。オペコードのWCRやオペランドのEWRPTL等は図2と図3を参照してください。コードは以下に置いておきます。

ENC28J60/assembler.c at master · Cra2yPierr0t/ENC28J60 · GitHub

また実際にROMに書き込む命令列を以下に置いておきます。

ENC28J60/prog.S at master · Cra2yPierr0t/ENC28J60 · GitHub

実践

Quartusでプロジェクトを作成しFPGAに書き込みます。EthernetケーブルをPCと接続してWiresharkで見た結果がこちらになります。

うわっ f:id:Cra2yPierr0t:20200805075326p:plainf:id:Cra2yPierr0t:20200805075329p:plainf:id:Cra2yPierr0t:20200805075340p:plain

うっわ f:id:Cra2yPierr0t:20200805075344p:plain

出てますね。

ここまでやっておいてアレなんですが、FPGAでENC28J60を動かす利点とかは特に見いだせませんでした。一応8Mbpsは出てるっぽいのでオーバヘッドは小さい方なのかな?マイコンで動かした経験が無いのでわかませんが。

ありがとうENC28J60。そしてさようなら。

参考文献

高速Ethernet × FPGA  (FPGAマガジン No.3)

高速Ethernet × FPGA (FPGAマガジン No.3)

  • 発売日: 2014/04/12
  • メディア: 単行本

www.microchip.co.jp

マジカル★FPGA

1限に向かう途中に思いついたネタをここに供養する

adventar.org この記事はUEC Advent Calender 2019の9日目の記事です。前日の記事はこちら

ねえよ

FPGAね、紹介記事は既に結構ある。 結構ある中で電通大のオタクがまた1つ紹介記事を生やそうってんだからねえ、何か新規性はあるのかなあ〜〜〜〜〜〜〜〜〜〜〜????????????????

あるわけがない

知ってた。 まあ無いよね、仕方ないね。 こっちは遊びでやってんだ、アカデミック太郎は黙ってて。

つよい

じゃあ本題に入りましょうね。 FPGAってなんだろう?なんですか?ぼくも知らないのでゆるふわに紹介します。

ディジタル回路、ご存知ですか? お手元のスマホを地面に叩きつけると出てくるアレです。FPGAさんは中にLE(ロジックエレメント)とかsliceとか呼ばれる マジカルな何かを沢山持ってまして、そいつらの中身と繋がり方を切り替えることで様々なディジタル回路を構成することが出来るすごいやつです。すごいですね。任意の処理系を代替可能です。最近はiPhoneにも入ってるらしいですよ、すごいですね。

次は開発方法とかについて書くのが一般的なんでしょうが少し逸れて、電通大生諸君にとってFPGAがどんな選択肢になり得るだろうか考えをちょっと書きます。 FPGAさん、立ち位置としては諸説ありますがレイヤーとしては電子工作とプログラミングの中間です。つまりですよつまり、FPGAは「電子工作?敷居高い....」や「プログラミング?なんもわからん(わかる)...」な人の要求に合致している訳です!!!(?????) ハードとソフトの狭間で生きていきませんか?

FPGAさん、HDL(ハードウェア記述言語)を書いて開発していきます。まあ大して難しくはありません。 電通大生は1年生の必修でRubyとCを学ぶはずなので、なんもわからんになることはまず無いでしょう(無いよね?)。 プログラミングに似てますがこれをプログラミングと呼ぶとインターネットの深淵に喰われるのでやめましょう。 また高位合成とかいうC++等のプログラミング言語で書いたコードをHDLに変換する方法もあったりします。すごいですね。

????

FPGAの用途についてです。 FPGAさん、汎用性が高いので学生が使うとなると用途に逆に困ります。これが正しい「逆に」の用法ですね。なので「よっし作るぞ」な気持ちで適当に作るものを決めて始めるのがいいんじゃないですかね。CPUとかどうですか?上にOS載せたくないですか?コンピュータ完全に理解したくありませんか?僕はしたいです。

宗教

主要なFPGAベンダにはintel様とXilinx(ザイリンクス)がありまして、皆さんも買うときは恐らくこの二択になるでしょう。どちらか一方を推すともう片方の勢力から陰湿な嫌がらせ を受けるかもしれないので明言は避けますが、私はintel製のFPGAの購入をオススメします。 どちらも開発環境を無料で配布してくれているのですが、Xilinxさんが出してる 開発環境のvivadoさんがカスなので気さくな書き込みをしたい人には辛いです。intelさんがよりましなquartus primeを出してる のでそちらを使いましょう。メモリ4GBのThinkPad X240でも快適です。

インテル® FPGA およびプログラマブル・デバイス - インテル® FPGA https://japan.xilinx.com/products/silicon-devices/fpga.html

ほらよ

ここまで読んだ貴方はFPGAの幻覚すら見えるはずです。買いましょう。DE0-CVとかオススメですよ。アカデミック版はなんと通常版の6000円引きです。CYC1000とか MAX1000もいいんじゃないですか。4000円台です。ちょっと買ってみませんか、大丈夫大丈夫怖くない怖くない、買うだけ買うだけ、ね?大丈夫だから?僕なんてほらこんなに 買ってるから。ほんとに大丈夫だから、一個、一個だけ買ってみない?

solitonwave.shop

追記

FPGAゼミ需要ありますか?

脳死で作る!クソ低機能アセンブラ

ネットコンテンツへようこそ これやります

アセンブラ is 何

アセンブリをバイナリに変換するやつです、出たバイナリをCPUが食べて(人類が)幸せになります。

何相手のアセンブラ作るの?

そう、これが問題。 CPUが違えばアセンブリも違う、怖い、言オリかよ。

詳しくは以下の素晴らしい本が出てるので買いましょう、買いましょう

大熱血! アセンブラ入門

大熱血! アセンブラ入門

だから何相手のアセンブラ作るの??

コンピュータシステムの理論と実装という本がある。(通称 nand2tetris)

Nandゲートから各種ゲート、そっからALU、なんやかんやあってCPU、OS作ってテトリス動かそうぜ!

そんな本です。 エモいですね?楽しそうですね? 買いましょう作りましょう、そんで教えて下さい。

コンピュータシステムの理論と実装 ―モダンなコンピュータの作り方

コンピュータシステムの理論と実装 ―モダンなコンピュータの作り方

で?

そう、それでですね、このnand2tetrisは、著者の作ったハードウェアシミュレータ上で自分で書いたHDLを動かして進めてくのが基本的な序盤のスタイルなんですよ。

そんでCPUも著者から仕様が与えられてHDLで書いていくので、「アーキテクチャ何?x86_64?MIPS?」とか聞かれるとつらい、僕はnand2tetrisに出てくるCPUのアセンブラを書いている、それ以上でもそれ以下でもない

ついでに言うとアセンブラの他にVMとか作るんですが、それらは読者の好きな言語で作る。 好き。 今回アセンブラはCで書きます。

Hackアセンブリ言語の仕様

読み返してみたら著者がnand2tetrisのアセンブリをHackアセンブリって呼んでました、じゃあアセンブラはHackアセンブラでいいですね、そう呼びます。

HackCPU1 の命令長は固定で16bitです。 またAレジスタ2とDレジスタ、Mレジスタ?3があります。

MのアドレスはAレジスタに入っている値です、変数みたいな扱いが出来ますね。

命令にはA命令とC命令の二種類、またシンボルが扱えます。

  • A命令はAレジスタの値を変更する命令で@R1とか@5と書きます、この場合前者はR1に対応するアドレス、後者はAに5が代入されます。

  • C命令は演算と分岐です、分岐先はAレジスタのアドレスになります。(分かり辛いですがシンボル使えばなんとなくわかります)

適当に書いてみるとこんな感じです。

@R1
M=1
D=1
(LOOP)
D=D+1
A=D
@LOOP
0;JMP

0;JMPは無条件分岐なので上のコードではD=D+1 A=Dが無限ループします

他の命令は是非nand2tetrisを買って読んで下さい。

脳死で作ろう!!

Hackアセンブリ、よく出来てますね。

「えっ!?シンボルとかの機能あるのに脳死で作れるの!?」と驚いた方は安心して下さい、無理です

今からこのよく出来たアセンブリを台無しにするんですよ?ゾクゾクしませんか?ゾクゾクしますね?

機能削ります、クソ削ります、鰹節です、生ハムの原木です。

仕様

  • シンボル使えません
  • A命令は@R0~@R15のみ
  • コメント使用不可

実装の方針

NULL

実装

正直タイトルの出オチ感凄くないですか?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc,char *argv[]){
    FILE *bin_file,*asm_file;
    char bin_file_name[1024] = {"\0"};
    char command[1024] = {"\0"};
    char command_bin[1024] = {"\0"};

    strcpy(bin_file_name,argv[1]);
    bin_file_name[strlen(bin_file_name) - 4] = '\0';
    strcat(bin_file_name,".hack");

    asm_file = fopen(argv[1],"r");
    bin_file = fopen(bin_file_name,"w+");

    if(asm_file == NULL || bin_file == NULL){
        perror("[ERROR]\n");
        exit(EXIT_FAILURE);
        }

    while(fgets(command,1024,asm_file) != NULL){

        command[strlen(command) - 1] = '\0';
        if(strcmp(command,"D=0") == 0){
            strcpy(command_bin,"1110101010010000");
        }else if(strcmp(command,"D=1") == 0){
            strcpy(command_bin,"1110111111010000");
        }else if(strcmp(command,"D=-1") == 0){
            strcpy(command_bin,"1110111010010000");
        }else if(strcmp(command,"D=D") == 0){
            strcpy(command_bin,"1110110001100000");
        }else if(strcmp(command,"D=A") == 0){
            strcpy(command_bin,"1110110000010000");
        }else if(strcmp(command,"D=!D") == 0){
            strcpy(command_bin,"1110001101010000");
        }else if(strcmp(command,"D=!A") == 0){
            strcpy(command_bin,"1110110001010000");
        }else if(strcmp(command,"D=-D") == 0){
            strcpy(command_bin,"1110001111010000");
        }else if(strcmp(command,"D=-A") == 0){
            strcpy(command_bin,"1110110011010000");
        }else if(strcmp(command,"D=D+1") == 0){
            strcpy(command_bin,"1110011111010000");
        }else if(strcmp(command,"D=A+1") == 0){
            strcpy(command_bin,"1110110111010000");
        }else if(strcmp(command,"D=D-1") == 0){
            strcpy(command_bin,"1110001110010000");
        }else if(strcmp(command,"D=A-1") == 0){
            strcpy(command_bin,"1110110010010000");
        }else if(strcmp(command,"D=D+A") == 0){
            strcpy(command_bin,"1110000010010000");
        }else if(strcmp(command,"D=D-A") == 0){
            strcpy(command_bin,"1110010011010000");
        }else if(strcmp(command,"D=A-D") == 0){
            strcpy(command_bin,"1110000111010000");
        }else if(strcmp(command,"D=D&A") == 0){
            strcpy(command_bin,"1110000000010000");
        }else if(strcmp(command,"D=D|A") == 0){
            strcpy(command_bin,"1110010101010000");
        }else if(strcmp(command,"D=M") == 0){
            strcpy(command_bin,"1111110000010000");
        }else if(strcmp(command,"D=!M") == 0){
            strcpy(command_bin,"1111110001010000");
        }else if(strcmp(command,"D=-M") == 0){
            strcpy(command_bin,"1111110011010000");
        }else if(strcmp(command,"D=M+1") == 0){
            strcpy(command_bin,"1111110111010000");
        }else if(strcmp(command,"D=M-1") == 0){
            strcpy(command_bin,"1111110010010000");
        }else if(strcmp(command,"D=D+M") == 0){
            strcpy(command_bin,"1111000010010000");
        }else if(strcmp(command,"D=D-M") == 0){
            strcpy(command_bin,"1111010011010000");
        }else if(strcmp(command,"D=M-D") == 0){
            strcpy(command_bin,"1111000111010000");
        }else if(strcmp(command,"D=D&M") == 0){
            strcpy(command_bin,"1111000000010000");
        }else if(strcmp(command,"D=D|M") == 0){
            strcpy(command_bin,"1111010101010000");
        }else if(strcmp(command,"A=0") == 0){
            strcpy(command_bin,"1110101010100000");
        }else if(strcmp(command,"A=1") == 0){
            strcpy(command_bin,"1110111111100000");
        }else if(strcmp(command,"A=-1") == 0){
            strcpy(command_bin,"1110111010100000");
        }else if(strcmp(command,"A=D") == 0){
            strcpy(command_bin,"1110001100100000");
        }else if(strcmp(command,"A=A") == 0){
            strcpy(command_bin,"1110110000100000");
        }else if(strcmp(command,"A=!D") == 0){
            strcpy(command_bin,"1110001101100000");
        }else if(strcmp(command,"A=!A") == 0){
            strcpy(command_bin,"1110110001100000");
        }else if(strcmp(command,"A=-D") == 0){
            strcpy(command_bin,"1110001111100000");
        }else if(strcmp(command,"A=-A") == 0){
            strcpy(command_bin,"1110110011100000");
        }else if(strcmp(command,"A=D+1") == 0){
            strcpy(command_bin,"1110011111100000");
        }else if(strcmp(command,"A=A+1") == 0){
            strcpy(command_bin,"1110110111100000");
        }else if(strcmp(command,"A=D-1") == 0){
            strcpy(command_bin,"1110001110100000");
        }else if(strcmp(command,"A=A-1") == 0){
            strcpy(command_bin,"1110110010100000");
        }else if(strcmp(command,"A=D+A") == 0){
            strcpy(command_bin,"1110000010100000");
        }else if(strcmp(command,"A=D-A") == 0){
            strcpy(command_bin,"1110010011100000");
        }else if(strcmp(command,"A=A-D") == 0){
            strcpy(command_bin,"1110000111100000");
        }else if(strcmp(command,"A=D&A") == 0){
            strcpy(command_bin,"1110000000100000");
        }else if(strcmp(command,"A=D|A") == 0){
            strcpy(command_bin,"1110010101100000");
        }else if(strcmp(command,"A=M") == 0){
            strcpy(command_bin,"1111110000100000");
        }else if(strcmp(command,"A=!M") == 0){
            strcpy(command_bin,"1111110001100000");
        }else if(strcmp(command,"A=-M") == 0){
            strcpy(command_bin,"1111110011100000");
        }else if(strcmp(command,"A=M+1") == 0){
            strcpy(command_bin,"1111110111100000");
        }else if(strcmp(command,"A=M-1") == 0){
            strcpy(command_bin,"1111110010100000");
        }else if(strcmp(command,"A=D+M") == 0){
            strcpy(command_bin,"1111000010100000");
        }else if(strcmp(command,"A=D-M") == 0){
            strcpy(command_bin,"1111010011100000");
        }else if(strcmp(command,"A=M-D") == 0){
            strcpy(command_bin,"1111000111100000");
        }else if(strcmp(command,"A=D&M") == 0){
            strcpy(command_bin,"1111000000100000");
        }else if(strcmp(command,"A=D|M") == 0){
            strcpy(command_bin,"1111010101100000");
        }else if(strcmp(command,"M=0") == 0){
            strcpy(command_bin,"1110101010001000");
        }else if(strcmp(command,"M=1") == 0){
            strcpy(command_bin,"1110111111001000");
        }else if(strcmp(command,"M=-1") == 0){
            strcpy(command_bin,"1110111010001000");
        }else if(strcmp(command,"D=D") == 0){
            strcpy(command_bin,"1110001100001000");
        }else if(strcmp(command,"M=A") == 0){
            strcpy(command_bin,"1110110000001000");
        }else if(strcmp(command,"M=!D") == 0){
            strcpy(command_bin,"1110001101001000");
        }else if(strcmp(command,"M=!A") == 0){
            strcpy(command_bin,"1110110001001000");
        }else if(strcmp(command,"M=-D") == 0){
            strcpy(command_bin,"1110001111001000");
        }else if(strcmp(command,"M=-A") == 0){
            strcpy(command_bin,"1110110011001000");
        }else if(strcmp(command,"M=D+1") == 0){
            strcpy(command_bin,"1110011111001000");
        }else if(strcmp(command,"M=A+1") == 0){
            strcpy(command_bin,"1110110111001000");
        }else if(strcmp(command,"M=D-1") == 0){
            strcpy(command_bin,"1110001110001000");
        }else if(strcmp(command,"M=A-1") == 0){
            strcpy(command_bin,"1110110010001000");
        }else if(strcmp(command,"M=D+A") == 0){
            strcpy(command_bin,"1110000010001000");
        }else if(strcmp(command,"M=D-A") == 0){
            strcpy(command_bin,"1110010011001000");
        }else if(strcmp(command,"M=A-D") == 0){
            strcpy(command_bin,"1110000111001000");
        }else if(strcmp(command,"M=D&A") == 0){
            strcpy(command_bin,"1110000000001000");
        }else if(strcmp(command,"M=D|A") == 0){
            strcpy(command_bin,"1110010101001000");
        }else if(strcmp(command,"M=M") == 0){
            strcpy(command_bin,"1111110000001000");
        }else if(strcmp(command,"M=!M") == 0){
            strcpy(command_bin,"1111110001001000");
        }else if(strcmp(command,"M=-M") == 0){
            strcpy(command_bin,"1111110011001000");
        }else if(strcmp(command,"M=M+1") == 0){
            strcpy(command_bin,"1111110111001000");
        }else if(strcmp(command,"M=M-1") == 0){
            strcpy(command_bin,"1111110010001000");
        }else if(strcmp(command,"M=D+M") == 0){
            strcpy(command_bin,"1111000010001000");
        }else if(strcmp(command,"M=D-M") == 0){
            strcpy(command_bin,"1111010011001000");
        }else if(strcmp(command,"M=M-D") == 0){
            strcpy(command_bin,"1111000111001000");
        }else if(strcmp(command,"M=D&M") == 0){
            strcpy(command_bin,"1111000000001000");
        }else if(strcmp(command,"M=D|M") == 0){
            strcpy(command_bin,"1111010101001000");
        }else if(strcmp(command,"MD=0") == 0){
            strcpy(command_bin,"1110101010011000");
        }else if(strcmp(command,"MD=1") == 0){
            strcpy(command_bin,"1110111111011000");
        }else if(strcmp(command,"MD=-1") == 0){
            strcpy(command_bin,"1110111010011000");
        }else if(strcmp(command,"MD=D") == 0){
            strcpy(command_bin,"1110001100011000");
        }else if(strcmp(command,"MD=A") == 0){
            strcpy(command_bin,"1110110000011000");
        }else if(strcmp(command,"MD=!D") == 0){
            strcpy(command_bin,"1110001101011000");
        }else if(strcmp(command,"MD=!A") == 0){
            strcpy(command_bin,"1110110001011000");
        }else if(strcmp(command,"MD=-D") == 0){
            strcpy(command_bin,"1110001111011000");
        }else if(strcmp(command,"MD=-A") == 0){
            strcpy(command_bin,"1110110011011000");
        }else if(strcmp(command,"MD=D+1") == 0){
            strcpy(command_bin,"1110011111011000");
        }else if(strcmp(command,"MD=A+1") == 0){
            strcpy(command_bin,"1110110111011000");
        }else if(strcmp(command,"MD=D-1") == 0){
            strcpy(command_bin,"1110001110011000");
        }else if(strcmp(command,"MD=A-1") == 0){
            strcpy(command_bin,"1110110010011000");
        }else if(strcmp(command,"MD=D+A") == 0){
            strcpy(command_bin,"1110000010011000");
        }else if(strcmp(command,"MD=D-A") == 0){
            strcpy(command_bin,"1110010011011000");
        }else if(strcmp(command,"MD=A-D") == 0){
            strcpy(command_bin,"1110000111011000");
        }else if(strcmp(command,"MD=D&A") == 0){
            strcpy(command_bin,"1110000000011000");
        }else if(strcmp(command,"MD=D|A") == 0){
            strcpy(command_bin,"1110010101011000");
        }else if(strcmp(command,"MD=M") == 0){
            strcpy(command_bin,"1111110000011000");
        }else if(strcmp(command,"MD=!M") == 0){
            strcpy(command_bin,"1111110001011000");
        }else if(strcmp(command,"MD=-M") == 0){
            strcpy(command_bin,"1111110011011000");
        }else if(strcmp(command,"MD=M+1") == 0){
            strcpy(command_bin,"1111110111011000");
        }else if(strcmp(command,"MD=M-1") == 0){
            strcpy(command_bin,"1111110010011000");
        }else if(strcmp(command,"MD=D+M") == 0){
            strcpy(command_bin,"1111000010011000");
        }else if(strcmp(command,"MD=D-M") == 0){
            strcpy(command_bin,"1111010011011000");
        }else if(strcmp(command,"MD=M-D") == 0){
            strcpy(command_bin,"1111000111011000");

中略


       }else if(strcmp(command,"D+M;JGT") == 0){
            strcpy(command_bin,"1111000010000001");
        }else if(strcmp(command,"D-M;JGT") == 0){
            strcpy(command_bin,"1111010011000001");
        }else if(strcmp(command,"M-D;JGT") == 0){
            strcpy(command_bin,"1111000111000001");
        }else if(strcmp(command,"D&M;JGT") == 0){
            strcpy(command_bin,"1111000000000001");
        }else if(strcmp(command,"D|M;JGT") == 0){
            strcpy(command_bin,"1111010101000001");
        }else if(strcmp(command,"0;JEQ") == 0){
            strcpy(command_bin,"1110101010000010");
        }else if(strcmp(command,"1;JEQ") == 0){
            strcpy(command_bin,"1110111111000010");
        }else if(strcmp(command,"-1;JEQ") == 0){
            strcpy(command_bin,"1110111010000010");
        }else if(strcmp(command,"A;JEQ") == 0){
            strcpy(command_bin,"1110110000000010");
        }else if(strcmp(command,"!D;JEQ") == 0){
            strcpy(command_bin,"1110001101000010");
        }else if(strcmp(command,"!A;JEQ") == 0){
            strcpy(command_bin,"1110110001000010");
        }else if(strcmp(command,"-D;JEQ") == 0){
            strcpy(command_bin,"1110001111000010");
        }else if(strcmp(command,"-A;JEQ") == 0){
            strcpy(command_bin,"1110110011000010");
        }else if(strcmp(command,"D+1;JEQ") == 0){
            strcpy(command_bin,"1110011111000010");
        }else if(strcmp(command,"A+1;JEQ") == 0){
            strcpy(command_bin,"1110110111000010");
        }else if(strcmp(command,"D-1;JEQ") == 0){
            strcpy(command_bin,"1110001110000010");
        }else if(strcmp(command,"A-1;JEQ") == 0){
            strcpy(command_bin,"1110110010000010");
        }else if(strcmp(command,"D+A;JEQ") == 0){
            strcpy(command_bin,"1110000010000010");
        }else if(strcmp(command,"D-A;JEQ") == 0){
            strcpy(command_bin,"1110010011000010");
        }else if(strcmp(command,"A-D;JEQ") == 0){
            strcpy(command_bin,"1110000111000010");
        }else if(strcmp(command,"D&A;JEQ") == 0){
            strcpy(command_bin,"1110000000000010");
        }else if(strcmp(command,"D|A;JEQ") == 0){
            strcpy(command_bin,"1110010101000010");
        }else if(strcmp(command,"M;JEQ") == 0){
            strcpy(command_bin,"1111110000000010");
        }else if(strcmp(command,"!M;JEQ") == 0){
            strcpy(command_bin,"1111110001000010");
        }else if(strcmp(command,"-M;JEQ") == 0){
            strcpy(command_bin,"1111110011000010");
        }else if(strcmp(command,"M+1;JEQ") == 0){
            strcpy(command_bin,"1111110111000010");
        }else if(strcmp(command,"M-1;JEQ") == 0){
            strcpy(command_bin,"1111110010000010");
        }else if(strcmp(command,"D+M;JEQ") == 0){
            strcpy(command_bin,"1111000010000010");
        }else if(strcmp(command,"D-M;JEQ") == 0){
            strcpy(command_bin,"1111010011000010");
        }else if(strcmp(command,"M-D;JEQ") == 0){
            strcpy(command_bin,"1111000111000010");
        }else if(strcmp(command,"D&M;JEQ") == 0){
            strcpy(command_bin,"1111000000000010");
        }else if(strcmp(command,"D|M;JEQ") == 0){
            strcpy(command_bin,"1111010101000010");
        }else if(strcmp(command,"@R0") == 0){
            strcpy(command_bin,"0000000000000000");
        }else if(strcmp(command,"@R1") == 0){
            strcpy(command_bin,"0000000000000001");
        }else if(strcmp(command,"@R2") == 0){
            strcpy(command_bin,"0000000000000010");
        }else if(strcmp(command,"@R3") == 0){
            strcpy(command_bin,"0000000000000011");
        }else if(strcmp(command,"@R4") == 0){
            strcpy(command_bin,"0000000000000100");
        }else if(strcmp(command,"@R5") == 0){
            strcpy(command_bin,"0000000000000101");
        }else if(strcmp(command,"@R6") == 0){
            strcpy(command_bin,"0000000000000110");
        }else if(strcmp(command,"@R7") == 0){
            strcpy(command_bin,"0000000000000111");
        }else if(strcmp(command,"@R8") == 0){
            strcpy(command_bin,"0000000000001000");
        }else if(strcmp(command,"@R9") == 0){
            strcpy(command_bin,"0000000000001001");
        }else if(strcmp(command,"@R10") == 0){
            strcpy(command_bin,"0000000000001010");
        }else if(strcmp(command,"@R11") == 0){
            strcpy(command_bin,"0000000000001011");
        }else if(strcmp(command,"@R12") == 0){
            strcpy(command_bin,"0000000000001100");
        }else if(strcmp(command,"@R13") == 0){
            strcpy(command_bin,"0000000000001101");
        }else if(strcmp(command,"@R14") == 0){
            strcpy(command_bin,"0000000000001110");
        }else if(strcmp(command,"@R15") == 0){
            strcpy(command_bin,"0000000000001111");
        }

        command_bin[strlen(command_bin)] = '\n';
        fputs(command_bin,bin_file);
        }

    fclose(asm_file);
    fclose(bin_file);
    return 0;
    }

脳死で書けましたね? おめでとうございます。

明日は友達に「僕はアセンブラ書きましたけど、あなたは?」 と煽りましょう。

まとめ

いかがでしたか?

nand2tetrisは良いです

またネタ思いついたらなんか書きます


  1. nand2tetrisのCPU

  2. レジスタはCPUにあるポケットみたいな認識でいいです(最高の例え

  3. レジスタと呼んではいけない気がする