家にリモコン、いくつありますか?
IoTセンサーとリモコン制御プログラミングで、手軽に自作のスマートホーム!

寝室のエアコンの自動運転がいまいちで、寒かったり暑かったりして起きてしまう問題。 IchigoJamと赤外線LED、sakura.ioを使って、家のエアコンをスマホ制御できるようにして一歩前進。 IchigoJamのプログラムはとってもシンプル!

10 N=IOT.IN() 20 IF N=0 GOTO 10 30 ?N:F=FILE():R=10:LRUN N,200

LRUNを使っているので、このプログラムを保存してから、実行。 sakura.ioからデータ受信する IOT.IN() で信号を受け取り、エアコン停止のファイル1、28℃設定ONのファイル2、29℃設定ONのファイル3を呼び出します。(リモコン制御部分のプログラムは後述)

次はスマホ側、sakura.ioの連携サービスとしてWebSocketを設定し、スマホからの操作用のプログラムはJavaScriptで操作用アプリを作ります。 HTML/CSS/JavaScriptの基本スキルと、サンプルプログラムがあればカスタマイズし放題です。

IchigoRemocon IoT src on GitHub

高精度温湿度計SHT-31を使った、家のIoT温湿度計と合わせ、あとは快適に眠っていられる、ちょうどいいしきい値を決めるのみ。

温度が下がりすぎて寒くなって設定を緩めたらどんどん暑くなっていった、夜の記録。

IchigoJamで、赤外線を見よう!
ご家庭のほとんどのリモコンは赤外線リモコン。赤色より少し低い周波数の光を使って信号をリモコンから本体へと届けています。 目には見えませんが、赤外線受光モジュール(センサーの一種)を使って観測しましょう。

赤外線リモコン受信モジュール GP1UXC41QS (秋月電子で50円)を、IchigoJamにつなぎます。 データシートを見ると、丸い部分を手前にして、左から、信号出力のVout、GND、VCCの順。それぞれIchigoJamのIN1、GND、VCCに接続し、早速実験プログラム! (電源電圧VCCは2.7V〜5.5Vとあるので、5Vを使ってもOKです)

1 ?IN(1);:CONT

ずらっと1が並びますが、赤外線受光モジュールに向けて、リモコンボタンを押すと、0001010 などと、反応します。これが信号で、ボタンごと、機種ごとに違うものが送られています。

いろいろなリモコンで試してみましょう。

どんなリモコン信号を受けたら動かすだけなら、これでOKですが、信号の内容によって動きを変えたい場合は、もうひと工夫必要です。

リモコンの原理とマシン語活用
リモコンは赤外線を1秒間に3.8万回、38kHzの点滅を基本として、太陽光などに含まれる赤外線と区別しています。 その点滅があるときがON、無い時がOFFとし、ON時間とOFF時間を交互に計測し、一定時間OFFが続いたら一連の信号が終了、その一連の信号を見て判断すればOKと原理はシンプルですが、IchigoJam BASICでは速度が間に合いません。

そこでマシン語!以前作った、リモコン送受信コードを流用して、プログラム領域にデータを格納し、LRUNを使ったファイル連携で簡単に使えるようにしました。

1 'IR-REMOCON 100 INPUT"0:SEND 1:RECV ",N 110 IF N=0 N=USR(#D00,0):GOTO 100 120 L=USR(#D00,1) 130 ?"LEN:";L 140 FOR I=0 TO L-1 150 IF I%64=0 ?:?"POKE#";HEX$(#E00+I); 170 ?",";PEEK(#E00+I); 180 NEXT:? 190 GOTO 100 200 L=USR(#D00):LRUN F,R POKE#D00,112,181,114,182,14,34,18,2,138,24,0,40,53,208,80,35,27,3,1,51,27,3,1,36,164,4,2,38,54,2,2,62,0,33,0,240,37,248,1,49,33,66,28,209,29,104,0,45,247,209,228,8,0,32,0,33,0,240,26,248,1,49 POKE#D3E,33,66,17,209,29,104,0,45,247,208,17,84,1,48,0,33,0,240,15,248,73,28,33,66,6,209,29,104,0,45,247,209,17,84,1,48,176,66,231,209,0,33,17,84,1,48,98,182,112,189,156,37,173,0,1,61,253,209 POKE#D78,112,71,80,35,27,2,1,51,27,4,4,51,1,36,0,38,17,92,73,0,0,41,234,208,28,96,0,240,22,248,30,96,0,240,19,248,1,57,247,209,1,48,17,92,73,0,0,41,221,208,0,0,0,0,0,240,8,248,0,0,0,0,0,240,4,248 POKE#DBA,1,57,245,209,1,48,226,231,154,37,1,61,253,209,112,71

プログラムを入力し、実行すると 0:SEND 1:RECV と、送信するか受信するか聞いてきます。 まずは1、エンターで受信。リモコン信号を受光モジュールに当てると、#D00に記録した内容が表示されます。

0または単にエンターで、赤外線を発信します。OUT1とGNDに赤外線LEDを付け、本体に向けてやってみましょう!無事制御できましたか!?

1行目に何の信号か分かるように名前をつけて、保存しておきましょう(EEPROMを使えば追加で最大128種類保存可能)。 あとは、好きなようにプログラムを作るだけです。

USBシリアルでPCと接続している場合、受診時に表示されるPOKE文を保存しておき、上記プログラムと合わせて書き込むことでもリモコン信号を復元できます。

ちょっと詳しい解説編
1KBのプログラム領域、こんな風に使っています。
#C00-#CFF 256byte BASIC(溢れてないよう ?FREE() が768以下にならないよう注意!)
#D00-#DFF 256byte マシン語(赤外線送受信)
#E00-#FFF 512byte 赤外線データ

マシン語のasm15ソースコードはこちら。以前作成したものを、#E00から最大512byte使って保存するように変更し、#D00から書き込んで使います。(エアコンの信号で440byte、収まります!)

' IN1 - 赤外線受光モジュール / OUT1 - 赤外線LED PUSH {LR,R4,R5,R6} CPSID '割り込み禁止 R2=#E 'PROGの後半 #E00 R2=R2<<8 R2=R1+R2 R0-0 IF 0 GOTO @SEND R3=#50 ' IN1 の address PIO0_10 R3=R3<<(24-(10+2)) R3+=1 R3=R3<<(10+2) ' PIO0_10 R4=1 R4=R4<<18 '初回信号オーバーフロー判定 R6=2 'R6=512-2 R6=R6<<8 R6-=2 R1=0 @BACK0 GOSUB @WAIT2526 R1+=1 R1&R4 IF !0 GOTO @END R5=[R3]L R5-0 IF !0 GOTO @BACK0 R4=R4>>(18-15) 'オーバーフロー判定変更 R0=0 '配列書き込み位置 @LOOP R1=0 @BACK1 GOSUB @WAIT2526 R1+=1 R1&R4 IF !0 GOTO @END R5=[R3]L R5-0 IF 0 GOTO @BACK1 [R2+R0]=R1 R0+=1 ' 1byteずつ R1=0 @BACK2 GOSUB @WAIT2526 R1=R1+1 R1&R4 IF !0 GOTO @END R5=[R3+0]L R5-0 IF !0 GOTO @BACK2 [R2+R0]=R1 R0+=1 ' 1byteずつ R0-R6 IF !0 GOTO @LOOP @END R1=0 [R2+R0]=R1 R0+=1 CPSIE ' 割り込み許可 POP {PC,R4,R5,R6} @WAIT2526 R5=156 ' 1cycle '(48000/38*2=2526 - overhead 14cycle - 6) / 4 = 626 (=156*4) R5=R5<<2 R5-=1 ' 1 cycle IF !0 GOTO -1 ' 分岐するとき3cycle しないとき1 - 4*loop-2 RET ' 3cycle @SEND R3=#50 ' OUT1 の address PIO1_0 R3=R3<<8 R3+=1 R3=R3<<16 R3+=`00000100 'PIO1_0 R4=1 'PIOオン用 R6=0 'PIOオフ用 'R2 データが格納されたアドレス 'R0 == 0 @ON R1=[R2+R0] R1=R1<<1 ' 2倍する R1-0 IF 0 GOTO @END @ON_LOOP [R3]L=R4 GOSUB @WAIT631 [R3]L=R6 GOSUB @WAIT631 R1-=1 IF !0 GOTO @ON_LOOP R0+=1 @OFF R1=[R2+R0] R1=R1<<1 ' 2倍する R1-0 IF 0 GOTO @END @OFF_LOOP NOP NOP GOSUB @WAIT631 NOP NOP GOSUB @WAIT631 R1-=1 IF !0 GOTO @OFF_LOOP R0+=1 GOTO @ON @WAIT631 'use R5 R5=154 ' 1cycle '(48000/38/2=631 - overhead 5cycle (+10/2) - 5) / 4 = 154 R5-=1 ' 1 cycle IF !0 GOTO -1 ' 分岐するとき3cycle しないとき1 - 4*loop-2 = 618 RET ' 3cycle

受信:ONになっている時間、OFFになっている時間を交互に数えて、メモリに書き出す
送信:メモリを読み、38kHzで点滅するONとただ待つだけのOFFを長さ分だけ繰り返す
(参考、はじめてのマシン語 - IchigoJamではじめるArmマシン語その1

まとめ
プログラミング、言語はいろいろ違っても基本はシンプルです。
大人も子供も学生も、まずは楽しく改造して、ひとつひとつやれること増やしていきましょう!


PCで動く、IchigoJam ap を使って、楽しんでくれたドランクドラゴンのみなさん!


jigインターン、プログラミングできる学生向け、超高速IchigoJam入門&プログラミング大喜利まで1時間!はーどによる「jig.jpオンラインインターン2020 6日目!」に作品あり! アニメーション、音楽、ゲーム、サクッとその場で作れて好評でした!はんだづけもぜひチャレンジしてね!

教え方、または、ゆっくり復習したい方は、こちらの動画をどうぞ!

総合2コマから始める鯖江の小学校プログラミング! 総合的な学習の時間、IT遊具、クラブ活動、地域ICTクラブ、高度IT人材へのベストプラクティススライドPDF

かわくだりゲーム、Hana道場での改造例。

links
- IchigoJamを赤外線リモコンで簡単遠隔操作!スマートホーム実現に向けて、信号の解読にも挑戦しよう!

IchigoJamで楽しく学ぶマシン語入門の16回目、今回はフラグを使ってみましょう。 (キャリーフラグなど対応追加したオープンソースのコアacm0cpu更新、IchigoJam webのマシン語エンジン更新、asm15に新表記追加)

(フラグテクニックも使って、74byteまで縮んだ「オールマシン語かわくだりゲーム」スピードをPOKEで改造するまで動画)

計算結果がゼロかどうかを判定するゼロフラグを使って分岐したりループを作ったりしてきましたが、フラグはそれだけではありません。

Z 結果が0かどうかのゼロフログ
C 桁溢れが分かるキャリーフラグ(引き算は2の補数の足し算になる)
N 結果がマイナスかどうかのネガティブフラグ
V 符号付き計算が破綻したかのオーバーフローフラグ

IchigoJam BASICなどのプログラミング言語では、等号や不等号とIF文を使って判定していますが、実際はこれら4つのフラグが使われています。 試しに、パラーメーターが15以上かどうか判定してみましょう。(CC = キャリーフラグが立っていない時分岐)

R1=0 R0-15 IF CC GOTO 2 R1=1 R0=R1 RET

asm15でアセンブルしたものをIchigoJamでメモリに書き込み、動かしてみましょう。

POKE#700,0,33,15,40,0,219,1,33,8,70,112,71 ?USR(#700,15) 1 ?USR(#700,14) 0

うまく判定できてますね!(-15は、2の補数表現との足し算となるため、15より大きいと桁あふれでキャリーフラグが立ち、CCでキャリフラグが立っていない時はスキップ。)

こちらがフラグ判定に使用できる条件の一覧です。

- フラグ判定
EQ Z=1, ゼロフラグセット(一致) Equals =0
NE Z=0, ゼロフラグクリア(不一致) Not Equals =!0
CS C=1, キャリーフラグセット =HS
CC C=0, キャリーフラグクリア =LO
MI N=1, ネガティブフラグセット
PL N=0, ネガティブフラグクリア
VS V=1, オーバーフローセット
VC V=0, オーバーフローリセット
AL 常に分岐

- 符号なし
HS C=1, 以上, Higher or Same =CS
HI C=1 and Z=0, より大きい, HIgher
LS C=0 or Z=1, 以下, Lower or Same
LO C=0, より小さい, Lower =CC

- 符号付き
GE N=V, 以上
LT N!=V, より小さい
GT Z=0 and N=V, より大きい
LE Z=1 or N!=V, 以下

32bitのレジスタ、符号付きとして使うか、符号なしとして使うかはあなた次第!
いろいろ試してみましょう。

また、キャリーフラグを使った計算命令を使うと大きな桁を使った計算ができます。 IchigoJamの配列を4つ使った8byte、64bitの足し算引き算をしてみましょう。
足し算 [8-11] = [0-3] + [4-7] (下位バイトを先とするリトルエンディアンとしています)

20 CLV 30 LET[0],-1,-1,0,0 40 LET[4],1,0,0,0 60 FOR I=8 TO 11:?[I];" ";:NEXT:?

足し算するマシン語を作ります。

PUSH {R4,PC} R0+=R1 R1=[R0+0]L R2=[R0+1]L R3=[R0+2]L R4=[R0+3]L R1=R1+R3 R2+=R4+C [R0+4]L=R1 [R0+5]L=R2 POP {R4,LR}

R2+=R4+Cで、直前の足し算によるキャリーフラグ分も合わせて足します。 R1+=R3 ではフラグが変化しないので、R0〜R7までのみ使える、R1=R1+R3を使いましょう。 (参考、Cortex-M0 Armマシン語表 asm15

asm15でアセンブルしたマシン語と呼び出しコードを加えて実行してみます。

10 POKE#700,240,181,8,68,1,104,66,104,131,104,196,104,201,24,98,65,1,97,66,97,240,189 50 U=USR(#700,#800) RUN 0 0 1 0

無事、桁上りの計算ができてます!
キャリーフラグ付きの引き算 Rd-=Rm+!C を使って引き算も実装してみましょう。 (引き算は、桁あふれが発生していないときにキャリーフラグがセットされるので、!Cを使います)

@fujitanozomuさんによる、フラグを使ったスゴ技を紹介します。 オールマシン語のかわくだりゲームのキー入力判定、素直につくるとこういう感じで6命令12byte

R0-28 IF !0 GOTO 2 R4-=1 R0-29 IF !0 GOTO 2 R4+=1

左キーが28、右キーが29と連続していることとフラグを使うと、下記のように4命令8byteで実装可能です

R0-=28 R0-=1 IF HI GOTO 2 R4+=R0+C

28減算し、判定したいものを0か1にした後に、更に1減算しつつ符号なしで1より大きければスキップ。 R0が0、つまり左キーの時だったときは、R0が-1になっていて、右キーの時はキャリーフラグが立っているので+1されます。 見事!

IchigoJamのAPIアクセス、#C0をキャッシュし、差分メモリアクセスを使う技を使うと、かわくだりゲームが37命令74byteで実現できました。

PUSH {R4-R7,LR} R7=#C0 R6=[R7+(#C4-#C0)/2]W 'putc R5=[R7+(#CE-#C0)/2]W 'locate R3=[R7+(#CC-#C0)/2]W 'cls GOSUB R3 R4=15 'X=15 @LOOP R0=R4 'locate X,5 R1=5 GOSUB R5 R0=#EC 'putc neko GOSUB R6 R0=32 'rnd(32) R3=[R7+(#C0-#C0)/2]W GOSUB R3 R1=23 'locate R0,23 GOSUB R5 R0=#2A 'putc *, enter GOSUB R6 R0=10 GOSUB R6 R0=3 'wait 3 R3=[R7+(#D6-#C0)/2]W GOSUB R3 R3=[R7+(#CA-#C0)/2]W 'inkey() GOSUB R3 R0-=28 'X=X-(R0=28)+(R0=29) R0-=1 IF HI GOTO 2 ADC R4,R0 R0=R4 'scr(X,5) R1=5 R3=[R7+(#D0-#C0)/2]W GOSUB R3 R0-0 ' IF R0=0 GOTO @LOOP IF 0 GOTO @LOOP POP {R4-R7,PC}

asm15でアセンブルした実行可能にしたものがこちら。(IchigoJam webではAPI未対応のため動きません)

10 POKE#700,240,181,192,39,190,136,253,137,187,137,152,71,15,36,32,70,5,33,168,71,236,32,176,71,32,32,59,136,152,71,23,33,168,71,42,32,176,71,10,32,176,71,3,32,251,138,152,71,123,137,152,71,28,56 20 POKE#736,1,56,0,216,68,65,32,70,5,33,59,138,152,71,0,40,226,208,240,189 30 U=USR(#700)

c4ij/zen4ij/rust4ij/Ruby on Jam でベンチマークしているスコア付きかわくだりゲームも、なんと82byte!

PUSH {R4-R7,LR} R6=#C0 'cls R3=[R6+(#CC-#C0)/2]W GOSUB R3 R4=15 ' X R5=0 ' S 'putc R7=[R6+(#C4-#C0)/2]W 'locate R3=[R6+(#CE-#C0)/2]W R12=R3 @LOOP 'locate X,5 R0=R4 R1=5 GOSUB R12 'putc neko R0=#EC GOSUB R7 'rnd(32) R0=32 R3=[R6+(#C0-#C0)/2]W GOSUB R3 'locate R0,23 R1=23 GOSUB R12 'putc *, enter R0=#2A GOSUB R7 R0=10 GOSUB R7 'wait 3 R0=3 R3=[R6+(#D6-#C0)/2]W GOSUB R3 'inkey() R3=[R6+(#CA-#C0)/2]W GOSUB R3 R0-=28 R0-=1 IF HI GOTO 2 ADC R4,R0 'scr(X,5) R0=R4 R1=5 R3=[R6+(#D0-#C0)/2]W GOSUB R3 R5+=1 R0-0 IF 0 GOTO @LOOP R0=R5-1 POP {R4-R7,PC}

日本のスパコン富岳のコア、A64FXも同じArmのコンピューター(fujitsu/A64FX on GitHub)。 世界最速になったヒミツを探るためにも必要な、マシン語の基本、楽しく習得しておきましょう!

links
- はじめてのマシン語 - IchigoJamではじめるArmマシン語その1

Zen言語で作るIchigoJamプログラム zen4ij、なんとZen言語開発者自ら早速改造!?

実機で動かすため、IchigoJamのはんだづけもしてくれました!無事LEDが光り、PCとのUSBシリアル接続もOK。久利寿とオンラインで話しつつコンパクト版にトライ、動いた! 最終的なサイズは、112byte。C言語より4byte、Arm thumbのマシン語で2命令少ない!


zen4ij に、プルリク送ってもらって、こちらの環境でも確認、マージ完了!
(プルリク=プルリクエスト=改善案置いておくからよかったら引っ張って使ってねという意味、マージ=改善案を採り込むこと、共にGit用語)

Zen言語の使い方や、ビルドのコツを直接聞くことができた。サイズ縮小のポイントとして不要セクションの削減が肝だった。下記が改良版 かわくだりゲーム in Zen言語(switch構文がいい感じ)

const ij = @import("std15.zen"); export fn main() callconv(.C) i32 { ij.cls(); var x: i32 = 15; var score: i32 = 0; while (true) { ij.locate(x, 5); ij.putc(236); ij.locate(ij.rnd(32), 23); ij.putc('*'); ij.putc(10); ij.wait(3); switch (ij.inkey()) { 28 => x -= 1, 29 => x += 1, else => {}, } if (ij.scr(x, 5) != 0) { break; } score += 1; } return score; }

公平を期すため rust4ij も改良、ただ同じく不要セクションを消しても Rust 版では 124byteと、Zenの112byte、C(gcc -Os)の116byteに及びませんでした。 なぜ、サイズが違うのか?それは、それぞれのコンパイラが出力するマシン語に差があるからです。コンパクトなプログラムでいろいろ見比べると個性があっておもしろい!

果たして、どこまで小さくなるのか?
コンパイラを使わず、asm15マシン語でプログラムしてみたところ、82byteで実装できた! (追記、Thanks 100byte→98byte82byte by @fujitanozomuさん)

PUSH {R4-R7,LR} R6=#C0 'cls R3=[R6+(#CC-#C0)/2]W GOSUB R3 R4=15 ' X R5=0 ' S 'putc R7=[R6+(#C4-#C0)/2]W @LOOP 'locate X,5 R0=R4 R1=5 R3=[R6+(#CE-#C0)/2]W GOSUB R3 'putc neko R0=#EC GOSUB R7 'rnd(32) R0=32 R3=[R6+(#C0-#C0)/2]W GOSUB R3 'locate R0,23 R1=23 R3=[R6+(#CE-#C0)/2]W GOSUB R3 'putc *, enter R0=#2A GOSUB R7 R0=10 GOSUB R7 'wait 3 R0=3 R3=[R6+(#D6-#C0)/2]W GOSUB R3 'inkey() R3=[R6+(#CA-#C0)/2]W GOSUB R3 R0-=28 R0-=1 IF HI GOTO 2 ADC R4,R0 'scr(X,5) R0=R4 R1=5 R3=[R6+(#D0-#C0)/2]W GOSUB R3 R5+=1 R0-0 IF 0 GOTO @LOOP R0=R5-1 POP {R4-R7,PC}

IcihgoJam APIは、アドレスの8bit範囲内に16bit範囲内の関数ポインタを書き込んであり、ファームウェアのバージョンが変わっても使用できるMSXのBIOS的な仕組みを採っています。(例、CLSの呼び出し)

'cls R7=#CC R7=[R7]W GOSUB R7

削減のポイントは、使える命令が限定されるハイレジスタ(R8以降)で、唯一関数内で値を保存せず使用してよいレジスタ、R12を繰り返し使用するAPIのキャッシュとして使用したところです。 だいぶ最適化が進むコンパイラ技術ですが、まだ発展の余地があるってことですね!

ちょうどネコのキャラクターパターンが96byte目からなので、#700からマシン語を書き込んでも動きます!

POKE#700,240,181,204,39,63,136,184,71,15,36,0,37,196,39,56,136,132,70,127,137,32,70,5,33,184,71,236,32,224,71,32,32,192,38,54,136,176,71,23,33,184,71,42,32,224,71,10,32,224,71,3,32,214,38,54,136 POKE#738,176,71,202,38,54,136,176,71,28,40,0,209,1,60,29,40,0,209,1,52,32,70,5,33,208,38,54,136,176,71,1,53,0,40,219,208,104,30,240,189 ?USR(#700)

コンピューターに初めての触るこどもから、ガチなエンジニアまで、幅広く楽しめるIchigoJam。 そのヒミツを書いた「情報処理 2020年8月号 (日本語) 雑誌」 now on sale!

この度、情報処理学会の会誌『情報処理』に「プログラミング...

上松 恵理子さんの投稿 2020年7月20日月曜日


今日のおやつ、いちごティー

情報処理学会「情報処理」8月号の特集「プログラミング教育の最前線」(目次記事一覧
モダン言語全盛時代に、なぜBASICか?なぜはんだづけなのか?6,586文字、7ページで綴りました。コンピューター好きな人、増やしましょう!

気になるモダンプログラミング言語の1つ、Rust(ラスト)。Denoとrust4ijをきっかけに入門。 IchigoJam と、Arm Cortex-M0 マシン語を使って、C言語の代替手段にできるか検証開始!

Rustの特徴のひとつ、ゼロコスト抽象化は、C言語の構造体と構造体ポインタを使った関数群や、関数ポインタをすっきり記述できていい感じ。 trait(トレイト)は、C言語では関数ポインタで実装するJavaのインターフェイス的なもの、こちらもきれいな記述でゼロコスト。

メモリを扱う際にもよく使う配列、うっかり領域外アクセスがバグやセキュリティホールになりがちです。Rustでどのように防いでいるか逆アセンブルして確認してみました。

let mut ar:[i32; 4] = [1, 2, 3, 4]; ar[param as usize] = 100;

長さ4の配列を作って、パラメータで指定された場所に100を書き込むプログラム。4以上の値が指定されると領域外アクセス、まずいです。

14: 9100 str r1, [sp, #0] 16: 2803 cmp r0, #3 18: d80c bhi.n 0x34 1a: 0080 lsls r0, r0, #2 1c: 4669 mov r1, sp 1e: 2264 movs r2, #100 ; 0x64 20: 500a str r2, [r1, r0]

Rustでコンパイルしたコードを見てみると、配列の初期化後、「cmp r0, #3」で配列の長さ-1と比較し「bhi.n 0x34」で範囲外ならジャンプ(GOTO)させ、不正なプログラムを走らせないように保護するコードが生成されていました。 2命令、たった2クロックのオーバーヘッドなので、サイズ的にも速度的にも問題になることは少ないでしょう。

領域外として判定された際のジャンプ先が panic 処理となります。panic_handlerとして自由に定義できるので、試しにただのループに変更してみました。

use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo) -&lt; ! { loop {} }

すると、なんと、下記のように領域外チェックが消えました。仕様なのかどうなのかは未調査ですが、これならそこそこ攻めた作りもできそうです。

14: 9100 str r1, [sp, #0] 12: 0080 lsls r0, r0, #2 14: 4669 mov r1, sp 16: 2264 movs r2, #100 ; 0x64 18: 500a str r2, [r1, r0]

panic 処理内で、volatile_storeとunsafeを使って、不正なメモリアクセスをあえて実行して、IchigoJam BASICの「Segmentation Fault」を起こすようにすると使いやすくなります。

#![no_std] #![no_main] #![feature(core_intrinsics)] use rust4ij::std15::*; use core::intrinsics::volatile_store; use core::panic::PanicInfo; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { //putstr("panic!\n".as_bytes().as_ptr()); // show message (+23byte) unsafe { volatile_store(1 as *mut i32, 1); } // invoke the Segmentation fault for safe (+32byte) loop {} } #[link_section = ".main"] #[no_mangle] fn main(param:i32, _ram:i32, _rom:i32, _divfunc: fn(u32,u32) -> u64) -> i32 { let mut ar:[i32; 4] = [1, 2, 3, 4]; ar[param as usize] = 100; let mut sum:i32 = 0; for i in 0..ar.len() { sum += ar[i]; } return sum; }

転送して、?USR(#800,4) と領域外アクセスするとエラーとなることが確認できます。不正アクセスするマシン語は下記のように、最小限のマシン語に変換されています。

44: 2001 movs r0, #1 46: 6000 str r0, [r0, #0]

前後に余計なコードが混ざってしまうため、数byte単位でも容量がほしい、現行 IchigoJam の移植はちょっと無理にしろ、かなり広範囲でのマイコン組み込み開発に良さそうです。

Rust、なかなかかわいく思えてきました。 次は、所有権の概念を使った動的メモリ確保を多用するメモアプリとかの実装にチャレンジして、より仲良くなってみようと思います。


創造はじめのいっぽ,Apple I/TK-80/MSX が生んだ感動をすべての子どもたちへ!」と題したIchigoJamにかけるこどもプログラミングの想いでも触れたコンピューター自体を理解し、好きになることと大切さ。

使うだけじゃなくて、IchigoJamみたいな素晴らしいハードウェアのきっかけになったのはすごく嬉しいことだ。あれは素晴らしい。
また英国がコンピューターの歴史を作るときが来た——「英国のMakerムーブメントは世界一」Raspberry Pi財団代表エベン・アプトンが語る | fabcross

Raspberry Pi、安価なパソコンをこども達に!想いに共感しに出会った2013年。小学生にはもう一段簡単なパソコンが必要と思って作った IchigoJam。 イベントを通じて、創始者、Eben Upton とも日本で会え、それがきっかけで産まれた IchigoJam RPi は、ラズパイで使えるサードパーティーOSとしても紹介してくれました!

世界中のこどもたちが「創造はじめのいっぽ」を楽しく踏み出せるよう、日々精進。

プログラミング好きのこどもを増やそう、IchigoJam。
プログラミング好きのおとなの多数のご協力あり、日本に世界にじわじわ成長中です。


BASICでプログラミングの基本を楽しんでから触れてみてほしい、コンピューターの真の力を引き出すマシン語。 スパコン富岳も世界一の計算力を実現するには、マシン語の理解は必須です(Fujitsu's Arm A64FX)。 ファミコンの日の6502系マシン語に続き、MSXでなじみ深いZ80版も試作しました。

Z80の開発者は、Intelの初代マイクロプロセッサ4004にも名前を残す、静岡出身の日本人、嶋正利さん! 初期の日本のパソコン時代、多くのパソコン少年が熱中したマシン語はZ80でした。 欲しかったファミリーベーシックではなく、MSXが届いた私にとってのファーストマシン語もZ80です。


3E は、Aレジスタへの8bitの値を代入するマシン語。C9はたぶん一番有名なZ80マシン語、サブルーチンからのリターン。IchigoJamのUSR関数で呼び出すと、Aレジスタの値が返ります。

今回の試作に使ったのは「libz80 - Z80 emulation library」C言語で書かれたZ80エミュレーターです。ライセンスに明記がなかったため非公開ですが、IchigoJam web で遊べるようにするとか、マイコン上で動かせるよう調整するのもいいかも?

ただ、ネイティブで使ってこそ、マシン語。 ちっちゃくて、100円しかしない IchigoJamのCPU、Arm Cortex-M0 の底力、引き出してみませんか? 素直で書きやすいマシン語なので、ちょっと慣れたこどもはもちろん、かつてチャレンジした大人の方にもオススメです!
はじめてのマシン語 - IchigoJamではじめるArmマシン語その1

日本政府のSNSにて、Hana道場の運営する、NPO法人エルコミュニティー竹部代表が登場!IchigoJamや、イチゴ帽子、どこかで見た後ろ姿が写ってます。 ict4e原さんのアフリカ企画でルワンダのPCNキガリと鯖江の子供をつないだときの様子!

links
- IchigoJamでつながるルワンダこどもと鯖江のこども! Hana道場で踏み出す新たな一歩! ビーズ x はんだづけがかわいい
- ファミコンの日、6502マシン語が使えるIchigoJam試作

1983年7月15日、ファミコン発売日、プログラマー人生のきっかけだった。 CPUは、MOS 6502(1975年)から、BCDとメモリーマップ機能を省き、音源とDMAを追加した Richo 2A03。 6502は、Apple I/IIや、アメリカでのMSX的存在であるコモドール社製のパソコンに搭載されたので、きっとアメリカではZ80よりメジャーなはず。

Arm設計の参考になったとも言われる、RISCアーキテクチャーに通じるシンプルな設計が今見ても美しい。 記念に、オープンソースな6502のC言語実装「Fake6502 CPU emulator core v1.1」を使って、IchigoJam ap で、6502マシン語が使えるようにしてみました。


6502のエミュレーションはコンパイルすると数十キロ程度、通常のIchigoJamには組み込めないので、ひとまず IchigoJam ap で仮実装して、遊んでみた。
渡されたパラメータに1を足す、簡単なマシン語プログラムが動いた!

#18 = CLC、キャリフラグのクリア
#69 = ADC、Aレジスタにキャリーと指定数値(1)の足す
#60 = RTS、サブルーチンからの復帰(RETURN)
(参考、NES研究室 - 6502

なんと、秋月電子で、現役6502系CPUが購入可能!
8ビットマイコン W65C02S6TPG-14: マイコン関連 秋月電子通商-電子部品・ネット通販
開発者のいろんな想いが詰まったコンピューターのアーキテクチャー、6502は知っておいて損なし!


IchigoJam web の6502版を作って、ぜひ遊んでもらおうと思いましたが、関数ポインタがうまくWebAssemblyでコンパイルできず・・・。またがんばります。


MSXとの出会い、頼んだのはこちらファミリーベーシックだった。


50音順に並ぶカタカナ。この配置がメジャーだったら、ローマ字派はここまで多くはならなかった!?


裏面。ファミリーコンピュータ用 キーボード 任天堂株式会社。IchigoJamで使えるキーボードとして改造したい。

links
- 日本政府広報に登場、国産PC、IchigoJam! Z80マシン語が使えるIchigoJam試作

ITの楽しさ伝える、福井県立科学技術高校、2年生全員向け講演。

体育館に掲げられている「技」と「創」が良い!


情報技術に関してとリクエストいただいたので「情報技術の活かし方・遊び方・学び方」と題したプレゼンテーション、IchigoJamゲームのライブコーディング、質疑応答の50分。


IchigoJamのCPU、凄い!という感想。作った私も凄いと思ったほどです。100円なのにね。スライドの16:9化に伴い、京と富岳を並べる形にアップグレード。 同じ予算なのに性能100倍!世界一のスパコン「富岳」の活躍、これからも楽しみです。


こちら、引退したスパコン「京」で、実際動いてたコンピューター。かっこいい!
7億6000万個のトランジスタでできているこのコンピューターを、88,128個つないで動かしていたのがスパコン京。 CPUの動作周波数は2GHzとみなさんのスマホと同等です。IchigoJamの48MHzともたかだか40倍しか変わりません。

計算が速い=時間の創出=社会が豊かになる

IchigoJamで三平方の定理を使った斜めの距離計算をやってみましょう。

10 ?"CALC LEN" 20 INPUT "X?",X 30 INPUT "Y?",Y 40 N=X*X+Y*Y 50 ?"X*X+Y*Y=";N

横(X)と縦(Y)の長さを入れてもらって、それぞれ自乗したものを足した数(N)。これのルートをとれば斜めの距離がでます。 ルートを計算するコマンドはないので、ひとまずシンプルに愚直に繰り返して求めてみましょう。

60 L=0 70 L=L+1 80 IF L*L<=N GOTO 70 90 L=L-1 100 ?"SQRT(";N;")=";L

長さ(L)を1足しながら自乗した値が先程計算したNを超えたら、1戻して表示するプログラム。 X=3、Y=4で結果Lが5とでました!

30, 40 だと、50。100,100だと144。数が大きくなると遅くなります。IchigoJam BASIC は、1コマンド1文字ずつ間違いがないか確認しながら丁寧に実行するので、間違っても安心な楽ちん言語ですが、その分速度が犠牲になっています。

そんな時は「マシン語」、コンピューターの能力をフルに引き出してみましょう。 BASICに似たマシン語生成用プログラミング言語 asm15 を使ったルートの計算はこちら。

R1=0 @LOOP R1+=1 R2=R1 R2*=R2 R0-R2 IF GE GOTO @LOOP R0=R1-1 RET

変数の代わりにコンピューター内部にある最も高速なメモリ、レジスタ(R0〜)を使います。IF GE GOTO は、もし、直前の計算結果が0以上だったらを意味する(GE)を使って、ループしています。 やってることはほぼ同じですね。

C言語と同様、これをマシン語に変換します。asm15 assemblerを使ってできたマシン語をメモリに書き込み、USR関数を使って呼び出しましょう。

POKE#700,0,33,1,49,10,70,82,67,144,66,250,218,72,30,112,71 ?USR(#700,25) 5 ?USR(#700,10000) 144

計算できました!大きな値でも一瞬ですね!
IchigoJamは1秒間5000万回、富岳は100京回、マシン語を使うとコンピューターの性能をフルに引き出せます。

汎用的に使えるC言語(IchigoJam BASICもC言語で作っています)、スマホやPC、サーバーでも気軽に動かせるJavaScript、並列処理に便利なC言語に似たGLSLなど、用途に合わせたいろんな言語も最終的にはそれぞれのコンピューターに合わせたマシン語となって動いています。

コンピューターと人間はステキな補完関係、うまく付き合っていきましょう!


HTMLはじめのいっぽ
30分でOK、HTMLからはじめる、自分だけのアプリづくり入門。CSSでデザインに凝るもよし、JavaScriptで動きに凝るも良し。


科学技術高校生による福井県てぬぐいがステキです!オリジナルスマホアプリづくりにもぜひチャレンジしたくなったら、どうぞお声がけください!


ハードウェア好きなら、栃木県立栃木工業高校による「SkyBerryJAM」のように、IchigoJamをベースにした、オリジナルハードづくり、楽しいかも?


講演資料「情報技術の活かし方・遊び方・学び方
CC BY のオープンデータです。ご活用ください!

福井県立科学技術高校のみなさん、楽しい時間、ありがとうございました!

京都府舞鶴市、東舞鶴の商店街の大門通り沿い、元舞鶴高専の先生で、PCN舞鶴代表の町田さんによる、プログラミングもできる電子工作&模型屋さん「舞鶴電脳工作室」オープン!(アクセス


こどもから大人まで、ワクワクするお店!店頭の模型や、電子工作見ていると、ちょっと覗いてみたくなりますね。


福井県大野市、元福井高専の先生、前川さんによるPCN大野研究所で採れたイチゴを直送!


電波の先生、前川さん。電波を見るツール「Nano VNA」が良い感じとのこと。 オープンソースな高周波解析機。日本語ユーザーガイドもオープンソースで作成されていました。 コロナ禍、飛行機に電波を当てて反射させての通信実験、旅客機は減っても、貨物は比較的飛んでいるとのこと。人には見えないものが見える力、広めましょう!


真っ赤になった、甘いイチゴ!いつの日かしたい、イチゴ収穫ロボコン。


舞鶴電脳工作室で仕入れた電子部品と大野さんイチゴのコラボ!IchigoJamでMAX7219マトリクスLEDチェーンの制御できました!


風通しの良い店内、ミニ四駆コースがこどもに人気とのこと!IchigoJamを使った計測システムも計画中とのこと!


抵抗、コンデンサ、LED、基本パーツが揃っていてうれしい、電子パーツコーナー。


15 マイコン、と書かれた電子工作用部品コーナーにはIchigoJamも。右下に見慣れない部品を発見!


8x8の赤色マトリクスLEDx4、全部に制御用のIC、MAX7219搭載でデイジーチェーン対応。これで400円は安い!

MAX7219制御のマトリクスLEDx4のIchigoJam制御チャレンジ!

MAX7219/MAX7221データシートをチェック、日本語ドキュメントがありますね。7セグLEDを8コまとめて制御するチップの様子。 4bitで数を指定すると7セグLED用にデコードするモードと、そのままストレートに8bit分出すモードがあります。8桁以上に対応するためにWS2812Bの用にデータを後ろにパスする仕組みがあります。 転送方式は16bitのSPI、FM音源チップYMF825などでやりました。

VCC 5V
GND GND
DIN シリアルデータ入力 - IchigoJamのOUT3
CS チップセレクト - IchigoJamのOUT1
CLK クロック - IchigoJamのOUT2

とIchigoJamと接続して、ひとまずBASICで実験!

500 @SPIW:OUT1,0:FORI=15TO0STEP-1:OUT2,0:OUT3,N>>I&1:OUT2,1:NEXT:OUT1,1:RTN N=12<<8|1:GSB@SPIW

付きました!(SHUTDOWNアドレス12のbit0に1で表示)

SPIはBASICのままだとゆっくりなので、マシン語化して高速化。ライブラリとして整えて、サンプルプログラムと合わせてできあがり!

10 GSB@INIT 20 N=5:GSB@INTENSITY 30 S="0528":GSB@SHOW:WAIT30 40 S=" jig.jg ":FORK=0TO10:GSB@SHOW:WAIT10:S=S+1:NEXT 60 S="17th":GSB@SHOW 70 FORJ=0TO7:N=J&1*9+5:GSB@INTENSITY:WAIT10:NEXT:WAIT30 80 GOTO 20 200 @INIT 210 POKE#700,80,35,27,2,91,28,27,4,1,33,201,3,0,34,8,66,0,208,4,50,154,97,2,50,154,97,73,8,246,209,112,71 220 N=7:GSB@SCANLIMIT:N=1:GSB@DISPLAY:RTN 300 @SHOW:FORJ=0TO7:OUT1,0:A=(J+1)<<8:FORI=0TO3:C=ASC(S+I):N=PEEK(C*8+J):U=USR(#700,A|N):NEXT:OUT1,1:NEXT:RTN 400 @INTENSITY:N=10<<8|N&#F:GSB@CMD:RTN 410 @DISPLAY:N=12<<8|N&1:GSB@CMD:RTN 420 @SCANLIMIT:N=11<<8|N:GSB@CMD:RTN 500 @CMD:OUT1,0:FORI=0TO3:U=USR(#700,N):NEXT:OUT1,1:RTN

300 @SHOW S:display chars 4桁表示 (I,J,A,C,N,Uが破壊される)
400 @INTENSITY N=0-15 輝度設定 (I,Uが破壊される)
410 @DISPLAY N=0/1 表示のON/OFF制御、最初にONにする (I,Uが破壊される)
420 @SCANLIMIT N=0-7 使用する最後の行、今回は7まで8行全部使う (I,Uが破壊される)
500 @CMD cmd send x4 - 16bitのコマンドを4つ分送信 (I,Uが破壊される)


後ろにどんどんつなげることができるので、もっと長くしたり、縦16ドットにしてみたり、高速化するためにループをマシン語化してみるなど、必要に応じて改造しましょう!

今回のプログラムの見どころ、4文字表示する処理300行@SHOWを丁寧に書くと、下記のような2重ループになっています。

300 @SHOW 310 FORJ=0TO7 320 OUT1,0:A=(J+1)<<8 330 FORI=0TO3 340 C=ASC(S+I):N=PEEK(C*8+J) 350 U=USR(#700,A|N) 360 NEXT 370 OUT1,1 380 NEXT 390 RTN

OUT1でCSを0に、4つ分のデータをSPI転送して、CSを1にすることでバケツリレー!

@SPIWのマシン語バージョンはこちら。asm15でアセンブルしてみましょう。

' @SPIW:FORI=15TO0STEP-1:OUT2,0:OUT3,N>>I&1:OUT2,1:NEXT:RTN @SPIW R3=#50 ' R3=#50010000 R3=R3<<8 R3=R3+1 R3=R3<<16 R1=1 R1=R1<<15 @LOOP R2=0 R0&R1 'F=N>>(15-I)&1 IF 0 GOTO @SKIP R2+=4 ' for OUT3 @SKIP [R3+`110]L=R2 ' OUT2,0:OUT3,F R2+=2 ' for OUT2 [R3+`110]L=R2 ' OUT2,1 R1=R1>>1 IF !0 GOTO @LOOP @END RET

OUTポートを変更する場合は、適宜プログラム内の数を変更しましょう(マシン語入門


小学生の頃、敷居の高さにあきらめたプラモデルの塗装。


塗装コーナー、人気とのこと!


美しい、塗装された模型!VRで塗装体験できるもの作ってみるのも入門にいいかも!?

新しい世界への入口「舞鶴電脳工作室&PCN舞鶴」でした!

links
- 舞鶴電脳工作室に子供パソコンIchigoJamの開発者の福野さんがご来店 | Cyber Workshop in Maizuru

以前紹介した、5コ950円で買える、安価でIchigoJam BASICだけでも使える超音波センサー「HC-SR04」。 他デバイスとの関係で、どうしてもBTNを使いたいとご要望あり。


できました!IchigoSodaにつないでIoT化していますが、IchigoJam、IchigoDakeでもOKです!

BTNはIchigoJam付属のボタンとSLEEPからの復帰のため外部でプルアップ抵抗をつなげていて、ANA(0)としてアナログ入力としても使えます。 つまり、CPU内部の設定としてはアナログになっているので前回紹介したマシン語で読み出そうとしてもうまくいきません。


BTNを割り当てているPIO1_4、LPC1114のデータシートの IOCON_PIO1_4 (アドレス#40044094) を見ると設定方法が書いてあります。 一度、マシン語を使ってどういう設定になっているか読み出してみましょう。

R0=[@IOCON_PIO1_4]L R0=[R0]L RET @IOCON_PIO1_4 DATA L #40044094

asm15でアセンブルして、読みだした値を8桁の2進法で表示

POKE#700,1,72,0,104,112,71,0,0,148,64,4,64 OK ?BIN$(USR(#700,0),8) 01000001

2:0 つまり最下位の0bit目から2bit目の3bitを使ったFUNCは1、次の2bitのMODEは0(プルアップなどなし)、次の1bitのHYSは0(無効)、6bit目はReservedとして予約されていて1を設定することになっていて、7bit目ADMODEが0でアナログ入力モードとなっています。

これをADMODE:デジタル入力+FUNC:PIO1_4と、`11000000 に一時的に変更する作戦でいきます。前回のカウントプログラムの前後にこの設定を足します。

PIO1のベースアドレスは #50010000、BTNは、PIO1_4の場所なので
?"#5001";HEX$(1<<(4+2),4) → #50010040 を@INに設定します。

'BTN(PIO1_4) <- digital R1=`11000000 R3=[@IOCON_PIO1_4]L [R3]L=R1 'count check R0=0 R1=[@IN]L @LOOP R2=[R1]L R0=R0+1 R2-0 IF !0 GOTO @LOOP R0=R0>>9 'BTN(PIO1_4) <- analog R1=`01000001 [R3]L=R1 RET @IOCON_PIO1_4 DATA L #40044094 @IN DATA L #50010040 'BTN=PIO1_4

アセンブルして、BASICのプログラムと組み合わせて、できあがり!

10 POKE#700,192,33,6,75,25,96,0,32,5,73,10,104,64,28,0,42,251,209,64,10,65,33,25,96,112,71,0,0,148,64,4,64,64,0,1,80 20 OUT1,1:OUT1,0:?USR(#700,0) 30 WAIT 5:GOTO 20

マシン語でカウントした値、R0をBASICに返す前に9ビット右シフト、つまり512分の1にしています。マシン語のカウントだと速すぎて大きな値になってしまうからですが、ここをいじると精度アップが見込めます。 ただ、IchigoJamでは1秒間に1.5万回くらい画面表示用の割り込みが発生するので、高い精度で計測するには割り込みを一時的に止める必要があります。

CPSID R0=0 R1=[@IN]L @LOOP R2=[R1]L R0=R0+1 R2-0 IF !0 GOTO @LOOP R0=R0>>5 CPSIE RET @IN DATA L #50001000 'IN1=PIO0_10

割り込みの一時停止は CPSID、最下位は CPSIE です。戻し忘れると何も操作できなくなってしまいます。下記、CPSIDした後リターンする危険なプログラム、SAVEした後、お試しください。

LET[0],#B672,#4770:?USR(#800,0)

完成した、超音波センサー、TrigをIN1に接続し、精度16倍バージョンがこちら!

10 POKE#700,114,182,0,32,3,73,10,104,64,28,0,42,251,209,64,9,98,182,112,71,0,16,0,80 20 OUT1,1:OUT1,0:A=USR(#700,0):?A 25 LED A<300 30 WAIT 5:GOTO 20

一定距離から近づくとLEDがついてお知らせ、リレー経由でスゴイ照明と組み合わせると防犯ライトにもなりますね!

5 B=0 26 IF B=0 AND A<300 B=1:N=N+1:IOT.OUT N:?"IOT!";N:WAIT30 27 IF B=1 AND A>=300 B=0

IchigoSodaを使って通ったらIOT.OUTでカウントを送るように改造も簡単です!
福井県で始まった「混雑状況オープンデータ」との連携も便利そう。


Let's IoT with IchigoJam x various sensors!

links
- 200円 超音波距離センサー HC-SR04 を IchigoJam で使う方法 - Armマシン語で時間を測ろう
- 今週末は越前がにロボコン! IchigoJamで超音波センサーをIN1とは違うポートで使う方法 BASIC編 マシン語編

初心者にはオススメできないC言語ですが、多くの高専の授業で登場するC言語

#include <stdio.h> int main() { printf("Hello World!\n"); return 0; }

このC言語のプログラムを実行すると

Hello World!

と出ます。これで感激できるのはC言語を作った人と、環境構築に苦労した人くらい。大抵の人は「で?」と思うだけでしょう。 なぜ # で始まる? <stdio.h> はHTMLのタグとは違う? studio のつづり違い?など1行目から分からないことだらけです。

こちら、その謎に本質から迫るため開発した、x64版の超シンプルマシン語標準入出力ライブラリ stdio.asm を Windows 10で動かした様子。Mac/Linux/FreeBSDでも同様に動きます。

今日の記事はC言語を少しやったけど、なんだかスッキリしない人、現代PCの主力CPU、Intel/AMDのx86系x64マシン語を使ったOSの深い話が気になる人向けです。 まずは楽しくプログラミングでゲームを作ってみたい人や、マシン語の基本は、シンプル&コンパクトなパソコン、IchigoJamからスタートするのがオススメです。(IchigoJam入門動画はじめてのマシン語

C言語プログラミング、本当のはじめのいっぽはこちらです。

int main() { return 1 + 1; }

これを test1.c と保存し、コンパイルし、実行し、実行結果を表示すると(for macOS/Linux)

gcc test1.c ./a.out echo $? 2

1 + 1 という人間らしい言葉で、コンピューターに計算させることに成功!

細かく解説すると・・・。 こちら、整数(int)を返すmainと名付けた関数(数学の関数と似たもの)を作り、中身に「1 + 1」を返して(return)と記述したC言語のプログラムです。 mainという名前は特別で、プログラム起動時に最初に呼び出されます。 「1 + 1 」という人にわかりやすい言葉を、コンピューターが分かる言葉、マシン語へ変換してくれるのがC言語のコンパイラというツールです。 gccというコンパイラは、特に何も指定しないと a.out という実行ファイルができます。それを、実行。 プログラムが実行した結果をみるコマンド(echo $?)を使って、コンピューターが計算した結果「2」を得ることができた。というわけです。

ゲームのキャラクターを表示したい、コントローラー入力を使いたい、音を慣らしたい、いろいろ欲が出てきます。 そこで登場するのがライブラリ。コンピューターの仕様を隅から隅まで調べなくても、誰かが作ってくれた便利な部品を使うことで楽できます!

そんなライブラリの代表格が stdio.h(スタンダードI/Oの略) で定義されている標準ライブラリというものです。 基本的な文字の表示(output)と入力(input)のための関数が揃っています。 冒頭に登場した、printfという関数もそのひとつ。

int main() { printf("hello!\n"); return 0; }

上記のようにプログラムを変更してコンパイルすると、printfって何?とエラーになります。

printfを事前に定義する必要があります。stdio.h というファイルに定義があります。#include は指定したファイルを埋め込んでくれます。 ファイル stdio.h はどこにあるのでしょう?コンパイラが含めるために使うディレクトリが決まっていてその中のを使ってというのが、「<」と「>」で囲う意味でした。 その場にある自分で作ったファイルを含めるときは、ダブルクォートで囲みます。 HTML,CSS,BASIC,C,JavaScript,Pythonなど、コンピューター言語毎に、記号の意味は変わります。

文字の表示やサウンド出力などの手順は、Windows/macOS/LinuxなどのOS毎に違います。 C言語のコンパイラはCPUの違いを吸収してマシン語を生成してくれますが、手順の違いを吸収するのはライブラリの役目。

例えば、Macで文字を出力するには、レジスタrsiに出力したい文字列の先頭アドレスを、レジスタrdxに長さを、rdiに1を、raxに0x2000004をそれぞれ設定して、システムコール(syscall)を呼ぶことで、OSが文字を表示してくれます。(stdio_mac64.asm src on GitHub、cmd: nasm -f macho64 hello.asm -DMAC64; ld -lSystem hello.o -o hello )

mov rdi, 1 ; fd = stdout mov rax, 0x2000004 ; syscall write syscall

CentOS, Ubuntu, Debian, OpenSuSE, Arch Lniux, Fedoraなど、多くのLinuxではレジスタraxに設定するシステムコール番号を変えるだけでOKです。(stdio_linux64.asm src on GitHub、cmd: nasm -f elf64 hello.asm -DLINUX64; ld -e _main hello.o -o hello )

mov rdi, 1 ; fd = stdout mov rax, 1 ; syscall write syscall

FreeBSDでは他のLinuxと異なります。macOSはBSD系の子孫、この値に 0x2000000 数を足したものです。(stdio_bsd64.asm src on GitHub、cmd: nasm -f elf64 hello.asm -DBSD64; ld -m elf_x86_64_fbsd -e _main hello.o -o hello )

mov rdi, 1 ; fd = stdout mov rax, 4 ; syscall write syscall

Windowsでは直接システムコールを呼んではいけないことになっていて、dll(ダイナミックリンクライブラリ)を経由しての呼び出しとなります。stdio_stdout の初期化が必要で、レジスタの使い方や、スタックの使い方も違います。(stdio_win64.asm src on GitHub、cmd: nasm.exe -fwin64 hello.asm -DWIN64& link.exe /entry:_main /subsystem:console hello.obj kernel32.lib )

mov r8, rdx ; len mov rdx, rsi ; buffer mov rcx, [rel stdio_stdout] mov r9, stdio_bytesWritten push qword 0 call WriteFile

このようにOSによってそれぞれ使い方は異なりますが、名前と使い方に揃えれば、以後気にしなくてよくなります。stdio.asm で、環境によって使うライブラリを切り替えるようにしておきます。

%ifdef WIN64 %include "stdio_win64.asm" %elifdef MAC64 %include "stdio_mac64.asm" %elifdef LINUX64 %include "stdio_linux64.asm" %elifdef BSD64 %include "stdio_bsd64.asm" %endif

こうして準備をしておき、stdio.asm を include すれば、どのOSでも動くマシン語でプログラム「Hello World!」が、このようにシンプルに書けます。NASMでのファイルへの埋め込みのincludeは#ではなく%。 いろんな環境での動作確認はConoHaのVPSを使うと1環境1時間1円〜と、とても手軽です。

%include "stdio.asm" global _main section .rodata MESSAGE db "Hello World!", 0x0d, 0x0a LEN_MESSAGE equ $-MESSAGE section .text _main: call stdio_init mov rsi, MESSAGE mov rdx, LEN_MESSAGE call stdio_write mov rdi, 0 call stdio_exit ret

開発効率、速度、汎用性の向上や、特殊な用途への特化するためなど、さまざまなプログラミング言語が誕生し、使われたり、廃れたりしていますが、結局動いているのはこれらマシン語です。 基本を抑えておけば、余計な手間をかけることなく、楽しく楽に開発できてますますプログラミングが楽しくなります。

理解を深めるには、実際にやってみるのが一番です!Windows/Mac/Linux/FreeBSD、それぞれ環境に合わせた c-*.sh/bat、c-*-test.sh/bat を使って、実際に動かしてみましょう。(src on GitHub

開発に必要なツールを設定しましょう。Windowsでは「Visual Studio C++ 2019 コミュニティ」、Macでは「Xcode」がそれぞれ無料で提供されています。 アセンブリ言語をマシン語化してくれるツール、アセンブラ「NASM」もオープンソース、無料です。

Visual Studio C++ 2019 コミュニティ、右側赤枠で囲んだ2つ、ビルドツールとSDKがあれば、ひとまず今回の開発は可能です。セットアップ後、コマンドプロンプトで hello-x64asm のディレクトへ移動し init-win.bat を動かし、開発ツールとNASMにPATHを通して、レッツトライ!

stdio.asm は、stdio.h が持つ機能の極一部。自分なりのライブラリや、プログラミング言語づくりにチャレンジするのもおもしろいですよ!

links
- taisukef/hello-x64asm: the first step of x64 64bit assembly programming on Windows/macOS/Linux
- C言語開発者「C言語は初心者にはお勧めできない」 エントリーにオススメBASICは、世界初のクラウド対応言語だった! IoTで起業家甲子園目指す、長岡高専チームメンタリング
- プログラミング言語は何から学ぶべきか? ロボットプログラミングゲームをIchigoJamでプログラミング! C言語の教科書「Springs of C」より
- 高専でなぜC言語を学ぶのか? IchigoJamマシン語生成プログラム c4ij で作る、C言語版かわくだり
- IchigoJamからのステップアップ - IchigoJam BASIC / Python3 / JavaScript / Java / C言語 対照表
- ハンドアセンブルで高速計算! RISC-V、RV32ICエミュレーターのC言語実装
- マシン語対応 IchigoJam web、気軽にハンドアセンブルして遊べます!
- OpenCL/C言語 GPUプログラミングはじめのいっぽ on Mac
- わずか16KB! WebAssemblyで動くミニC言語オフラインコンパイラ&インタプリタ webci0
- 深いプログラミング言語学習に最適! 512行のC言語コンパイラ ci0 を使ってみました
- 地味なC言語がなぜ楽しいのか?

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY / @taisukef / アイコン画像 / プロフィール画像 / RSS