遅いけど、今年の抱負など

今年の抱負は今抱えてる問題を無事に解決することなんだが、それ以外にもいくつかあるので自分で忘れないように列挙しておく。

1.リンカを作る。

2.実行ファイルからツールの力を借りてソースコードを擬似的に再現する。

3.チート行為についての理解を深める。

4.絵を描く

5.コンパイラを作る。

6.積ん読を減らす

7.英語の勉強をする(主に読解、単語、英会話、英作文について)。

8.世界史を他人に教えられるくらい、解説動画を作れるくらいちゃんとやり直す。

9.数学をやる。

10.物理をやる。

11.競プロを始める。

12.コンピュータの低レイヤーについて知識を深める。

13.FPGAを使ってCPUを作る。

14.コンピュータセキュリティに関して知識を深める。

15.機械学習に手を出す。

16.できるだけ毎日何をやったかの記録をつける。

17.3Dモデリングに手を出す(具体的にはblenderと仲良くなる)。

18.自分専用のソシャゲを作る。

19.これ以上無駄にパソコンを増やさない。

以上のうちできるやつから手を付け始めていくが、今抱えている問題が解決しないことには16.以外手を出せないので、まずはそこからということになります。今抱えている問題が解決しない場合上記のリストはそのまま来年にスライドすることになります。

何をやったかはこのブログでもいいし、アプリに書き溜めていくのでもいいと思うので自分に合う方を選んでやっていきたい。(Donelistというアプリが使いやすそうなのでそれを使いそうではある)

 

スクランブルを解除してついでにエンコードするスクリプトを書いた話

9月18日に全国公開された「劇場版 ヴァイオレット・エヴァーガーデン」。京アニ事件以来の京都アニメーションの作品である。私は、原作は未読だが、3週間限定で劇場公開された「ヴァイオレット・エヴァーガーデン 外伝 -永遠と自動手記人形- 」を観に行っていたので、「劇場版」の方も見ようと思っていた。しかし、問題があった。私はTVアニメの方も見ていないのである。しかも「劇場版」はどうやらTVアニメの続編的な立ち位置のようで、TVアニメの方を見ていないと楽しさが半減してしまうのではないかと思い、TVアニメの方を見ようと思い至った。

配信サービスを使って見ようと思ってもみたが、昔に自分で立てた録画鯖で録画していた記憶があり、録画番組の記録から検索してみると録画した形跡があった。最初の放送と劇場版公開に合わせて行われた再放送の両方とも録画してあった。

しかし、ここで問題があった。今では録画鯖に使っているラズパイ4の電源のおかげでチューナーとどっかに転がっていたB-CASカードを使って録画時にスクランブル解除を同時に行えているのだが、ヴァイオレット・エヴァーガーデンを録画していた当時のラズパイ3の貧弱な電源ではチューナーを使いながらB-CASカードを利用することができず、録画データを再生するにはいちいちスクランブル解除を手動で行わなければならなかった。

そのため、「劇場版」を見に行く前にTVアニメの方を予習するため録画データを掘り起こしスクランブル解除をする必要があった。というわけで、スクランブルがかかった状態の録画データを一旦集めて、ラズパイ4に転送し、スクランブル解除をして、ついでにエンコードしてしまおうと考えた。

というわけで、その時に使ったスクリプトが以下のものである。念の為、スクランブルを解除したファイルを一旦生成しそのファイルをエンコードしてファイルサイズを小さくするという方法をとっているが、これは最初にテストで適当に書いたスクリプトに通したらファイルサイズが0になってしまい、ファイル転送からやり直す羽目になったためである。

#!/bin/sh
filename=$1
tmpname=${1%.ts}.m2ts
outputname=${1%.ts}.mp4
b25 "$filename" "$tmpname"
ffmpeg -i "$tmpname" -codec:v h264_omx -b:v 3000k -s 1280x720 -crf 23 "$outputname"

 ffmpegでのコーデックの指定が単なるh264ではなくh264_omxになっているのはラズパイ4のハードウェアエンコードを利用しているためである。speedはサイズ変更を行っているため0.75xぐらいに落ちるがその分ファイルサイズが小さくなると思うと妥協できる。

そんなこんなでスクランブルがかかっていた録画データをスクランブル解除しついでにエンコードする事ができた。あとは見て、劇場に足を運ぶだけである。

FPGAに手を出してみた

FPGAに手を出してみた。

8月上旬に手に入れたALTERA製のFPGAであるMAX10のついた基板とそれに関する雑誌を秋葉原のマルツで手に入れた。

家に帰ってから早速電源につないだところ基板についているLEDに反応がない。手順を間違えたのか、それとも壊してしまったのか、電源がまずかったのか、それとも、電源ケーブルイカれているのか。問題の切り分けをすべく、まずは電源を疑ってみた。雑誌によると、iPhoneの充電器で良いと書かれていたので、純正のiPhoneの充電器を持ってきてつないだが反応なし。つぎはケーブルがだめなのかとヨドバシに行ってケーブルを買ってきたがだめ。基板が壊れていたのかと思い、基板を買い直すもだめであった。

これはさすがにおかしいと思い、雑誌をよく読むと、基板のはんだジャンパの部分をショート、つまりはんだ付けを行う必要があるとわかった。こんなことで無駄に時間と金を使ってしまったかと思うと、もっと雑誌を読めばという後悔が絶えない。

気を取り直したものの、家にはんだ付けの環境というか、はんだごてやはんだなどはない為これまたアキバまで行って入門者用みたいなセットを購入して、はんだジャンパの箇所をはんだ付けしショートさせた。

これで準備に抜かりはないか、雑誌をよく読み、これで問題ないと確認し、いざ電源につなぐと簡単に動作した。良かった、間違ってなかったと安堵した。

さて、これではまだFPGAに書き込みができる準備ができただけで、実際は何もやってない。プログラミングで例えると、環境構築が終わった。楽器で例えるなら楽器を購入したとかのレベルである。

雑誌に従って、最初の回路であり伝統あるLチカ(LEDを光らせること)をやってみることにした。これは簡単に終わった。1秒毎に赤、緑、黄、青、マゼンタ、シアン、白、黒(発光しない)を繰り返すだけの回路が組めた。これで初心者の仲間入りといったところか。

しかし、ハードウェア記述言語であるVerilog HDLはよくわかってないのでどこかで勉強したい。書籍が何冊かあるようなので時間があるときに読みたい。

次は、徐々にLEDの色が変化するというのをやった。イルミネーションみたいで思ったよりきれいで感動している。

最終的にはFPGAで昔のCPUを再現するみたいなので、そこまで三日坊主にならず進めたい。

Raspberry pi 4を購入したりX260を購入したりした

Raspberry pi 4の8GBモデルが出たというので、早速買ってみることにした(スペック厨)。録画鯖を更新しようと思いMicroSDはせっかくだし512GBのを買ってみた。最初は公式からようやく提供されたイメージ書き込みツールを使ってUbuntu64bitをいれてh.264のハードウェアエンコードができるか試していたんだけど、結局知識不足でできなくて、32bitのraspbianを入れることにした。で、いろいろ環境構築することにしたんだけど、以前使ってたchinachu betaからchinachu gammaに移行したり、mirakurun入れたりしてスクランブル解除も録画時に行えるようにしたりと色々行ってた。

で、今持ってるノートPCのメモリが全部8GBでラズパイと同じなのはなんか癪だなとか思っていたら、アキバのiosysThinkPad X260のFHDモデルが3万円で売られていたので購入した。スペックはメモリ4GB、ストレージはHDD500GBというものだったので、Amazonで16GBのメモリとSSD500GBを注文して、換装した。そしてWindowsUbuntuデュアルブートをしていまはUbuntuでwebブラウジングしてる。

もともとメインで使ってたゲーミングPCがファンの調子が悪くなって使えなくなり、メモリ8GBの生活を強いられていたのだが、これで16GBの世界に戻ってきた。chromeでたくさんタブを開いて、他のタブを見たあとにTweetdeckに戻るっても再読み込みしない生活がこんなにも快適だったとは思わなかった。8GBだとどうしても再読み込みが発生し不快とは言わないまでもなんか嫌だなと思ってたのが解消されてよかった。

まだUbuntuで面白いことはやっていなくて、なんかやりたいなとpythonの勉強をしようと本を購入したり、低レイヤの勉強をしてみたいなと思ったりしている。あとラズパイの方もせっかくなんだし電子工作の方にも手を出してみたいと思ったりしている。

私生活が色々あってその機会は来年度になりそうだけどなんとかならねーかなーとか思って生活している。

コンパイラを自作する。

こんにちは、こんばんは。高崎です。

この記事はCCS Advent Calendar 2019 †裏†の10日目の記事です。

 

adventar.org

 前日は

yoooomaruuuu.hatenablog.com

でした。

 

プログラマの皆さんは必ずやりたい3つの夢を持っていると思います(※個人の感想です)。

自作os、自作cpu、自作言語のこの3つです。今回は自作言語の中でもコンパイラに焦点を当ててみました。

 

コンパイラとは

コンパイラとは言語aを言語bに変換するプログラムのことです。

今回は「5+4-3」という文字列を受け取って「6」を返すようなコンパイラを作っていきたいと思います。機能としては加減算のみとします。理由は積除算が入ると計算順序を考える必要があり、この記事の中では解説しきれなくなるからです。申し訳ないです。

環境構築

環境としてはLinux(Ubuntuなど)でCPUはx64を想定しています。

理由としてはツールが手に入りやすいのと、情報が多いこと、アセンブリ言語の関係です。

環境構築としては最低限、gccbinutilsが入っていれば動くと思います。 

CPUとアセンブラ

CPUは中央処理装置または中央演算処理装置の頭文字でコンピューターの脳に相当する部分です。このCPUがメモリから機械語を読み取ってデコードし、計算結果を返すのがプログラムの基本的な流れです。

機械語は0と1で表されたCPUが解釈可能なデータ列のことで、画像やテキスト、動画などは実は01の2つの数字の列で表すことができます。このあたりは皆さんご存知なのではないでしょうか。

アセンブラについて知らない方もいるかも知れません。現在、C言語などのプログラミング言語は直接機械語に翻訳されることはほとんど無いです。一回中間表現やアセンブリ言語に翻訳されてから機械語に翻訳されています。これは多くのCPUに対応するため柔軟さをもたせた結果でもあります。

CPUが異なると同じ機械語でも異なる命令ととらえたり、解釈できないことがおこるためこんな仕組みになっています。JavaC#はまた少し違った仕組みをしているので気になる方は調べてみてください。

話しがそれました、アセンブラについて話しましょう。

アセンブリ言語は機械ごと一対一に対応した、人がわかりやすいかたちに直した言語のことで、アセンブラはそのアセンブリ機械語に翻訳するプログラムのことです。人にわかりやすいというのがどういうことなのかというと

アセンブリだと「MOV EAX, 01234567」のようにかけますが、機械語だと「B867452301」と書かなくてはなりません。ちょっとどころではなく難しいですね。このあたりの詳しい話は昨年のアドベントカレンダーの私のスライドショーを見ていただければ解ると思います。

足し算引き算ができるコンパイラ

さて、本題です。足し算引き算ができるコンパイラを作ってみましょう。「これのどこがコンパイラなんだよ」と思う方もいるかも知れませんが、定義的にはこれも立派なコンパイラなので安心してみていてください。

まずは一個の数字を返すプログラムを書いてみましょう。

C言語だと

int main(int argc, char **argv) { return 42; }

みたいなかんじのものになると思います。

これをアセンブリで書いてみると

.intel_syntax noprefix

.global main

main:

  mov rax, 42

  ret 

これをtest.sと名前をつけて

gcc -o test test.s

./test

echo $?

これで42が表示されると思います。x64のアセンブリではraxに帰り値を渡しておくという規則があるためraxを使っています。また、最初の「.intel_syntax noprefix」はおまじないみたいなものです。今回は説明しません。

アセンブリc言語で書いて、そして拡張し値を一つ受け取ってそれを返すようにしてみましょう。

#include  <stdio.h>

int main(int argc, char **argv) {

    printf(".intel_syntax noprefix\n");

    printf(".global main\n");

    printf(".global main\n");

    printf("main:\n");

    printf("  mov rax, %d\n", atoi(argv[1]));

    printf("  ret\n");

 これをminicc.cとして保存して次のコマンドを実行してみてください

gcc -o minicc minicc.c

./minicc 123 > tmp.s

gcc -o tmp tmp.s

echo $?

すると123が得られていることが解ると思います。次は一気に足し算引き算を実装してみましょう。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
 char *p = argv[1];

 printf(".intel_syntax noprefix\n");
 printf(".global main\n");
 printf("main:\n");
 printf(" mov rax, %ld\n", strtol(p, &p, 10));

 while (*p) {
  if (*p == '+') {
   p++;
   printf(" add rax, %ld\n", strtol(p, &p, 10));
   continue;
  }

  if (*p == '-') {
   p++;
   printf(" sub rax, %ld\n", strtol(p, &p, 10));
   continue;
  }

  return 1;
 }

 printf(" ret\n");
 return 0;
}

 最初に数字を読み込んで、strtolでポインターを更新し(1文字か2文字かそれ以上かわからないためこの関数を呼んでポインターの更新を行っております)、pが1文字読んで「+」ならaddの命令を、「-」ならsubの命令を読んで、引数にまたstrtolを呼んでいます。

これに以下のコマンドを実行すると、

gcc -o minicc minicc.c

./minicc '12+34-5' > tmp.s

gcc -o tmp tmp.s

echo $?

とすると、41が得られていると思います。

./minicc '12+34-5'の部分を色々いじってみてください。ちゃんと計算されていることが解ると思いますし、tmp.sをみるとちゃんとアセンブリが書かれていることが解ると思います。これで、足し算引き算ができるコンパイラが完成しました。当初の目的、完遂しましたね!お疲れ様です。

 

この先

  これ以上のことを話すと本が書けるレベルの長さになります。というか本になってます。この記事の元ネタもこの本からお借りしています。

www.sigbus.info

興味のある方は再帰下降構文解析やlex、yaccなど調べてみると良いかも知れません。

今、私が自作しているc言語コンパイラは四則演算、比較演算子、単項演算子、整数型、文字型、ポインター型、構造体、アロー演算子、関数定義、関数呼び出し、ローカル変数、グローバル変数、if文、for文、while文、配列、sizeof演算子などが実装されています。typedefなどの機能が実装できれば自分で自分をコンパイルできるようになる、いわゆるセルフホスティングができるようになります。現在はそれを目指しています。またリンカー、ローダーの開発も行って、アセンブラの開発も行い、オレオレツールチェインを目指すのもいいかも知れません。

自作osは以前

https://www.amazon.co.jp/30%E6%97%A5%E3%81%A7%E3%81%A7%E3%81%8D%E3%82%8B-OS%E8%87%AA%E4%BD%9C%E5%85%A5%E9%96%80-%E5%B7%9D%E5%90%88-%E7%A7%80%E5%AE%9F/dp/4839919844/

この本で行ったため、あとは自作cpuが残りの夢なのですが、最近はFPGAなどで回路が組めるようになってきたためそれも時間の問題かも知れません、risc-vのようなオープンな規格が出てきたためぜひやってみたいですね。

これを機にコンパイラやOSなどいつも使っているプログラムがどのような風にできているのか、気にして調べたり作ったり、興味を持っていただければ幸いです。

明日の記事は

 @NocreateNolifeさんの、「
攻略情報を一切シャットアウトして目指すポケモン図鑑完成(盾)」
です。楽しみですね。
 
宣伝ですがこの記事はnina77さんの音楽を聴きながら作成しました。最近は「東京カラー」や「サヨナラ夜風」などをヘビロテしてます。みなさんも聞いてみてください。

日記:ボーッとした日

本日の体調:良

よく寝たので体調がよかったです。

PHPの勉強をしたのでなんかwebエンジニアっぽい雰囲気になれました。

労を今日は休んだのでその代わりに勉強をしたという感じですね。

そろそろ寝ます。

起きたら労です。

日記:本を買うの忘れた

本日の体調:良

たくさん寝るということは健康にいい、古事記にも書かれている。

今日はそれが実践できる日だったので二度寝、三度寝を行ってました。そのおかげで体調が良かったです。

電車移動が多い日だったので遅延を無事引き予定がめちゃくちゃにされながら生きたりしていました。

晩飯がコンビニ弁当になるか焼きうどんになるか駆け引きをしなくてはならない状況が発生したので無理やり焼きうどんになるように誘導し無事焼きうどんをゲットしました。

データサイエンスの勉強が一ミリも進んでないのでこれからやろうと思います。ベイズの定理、頭いいけど一見わからなくないですか?

ぼくリメ、めしにしましょう魔法使いの嫁を買おうと思っていたのに駅の近くの本屋になかったので週末に外出したいと思います。