福野泰介の一日一創 - create every day

お気に入りCPU、Arm Cortex-M0NXP社製LPC1114シリーズと同じクラス、STMicroelectronics社製STM32F0シリーズでIchigoJamが動きました!


シリアル通信でIchigoJamを便利に使える、IJUtilitiesを使うとスクリーンを使ったゲームも動かせます!


今回は、秋月電子で手に入るSTM32F042K6T6へ書き込んだら、そのままシリアル通信で使えます。 (Nucleoにbinファイル書き込みでも動くかもしれません)

I/Oは、まだLED(PB3とPA7)のみ使えます。他、配置と機能、検討中です。

同じArmなので、USRコマンドを使ったマシン語はそのままで動きます!
ハンドアセンブルで超速計算! - IchigoJamではじめるArmマシン語その2
I/Oを使うマシン語は、LPC1114とSTM32F0、I/Oのメモリマップが違う点に注意です。

ターゲットにしている、STM32F030K6T6TRは、LPC1114と同じ48MHz/Flash32KB/RAM4KBで、1コ175円、12,000コ買えば1つあたりなんと74円

STM32で始めるC言語」で紹介した上級者向けミニマム開発環境サンプルも拡充
(GPIO/Clock変更/UART/割り込み/TIM/SPI/Flash書き込み)

ちっちゃいコンピューターをプログラミングで味方に付け、身の回りをどんどん便利にしちゃいましょう!

Mbed対応のSTM32の開発環境Nucleoでマシン語でエルチカに成功したので、次はいろいろ製品化を見越して、CPUそのままを使って作ってみます。


今回使用したのは、秋月で売っている一番安いSTM32、STM32F042K6T6です。
Arm Cortex-M0 48MHz, Flash32KB, SRAM6KB, LQFP32
LQFP32に対応するDIP化基板へはんだづけ!
0.8mmピッチなので、0.65mmピッチ28ピンのLPC1114FDH28のはんだづけより簡単です。


USBシリアルを使って書き込みます。LEDとUSBシリアルとの接続の仕方はつぎの通り。
VDDA、VDDIO2にも電源供給が必要です。BOOT0をHIGHにすることで、書き込みモードになります。
RTSが使えない場合は、リセットする際、手でジャンパー線をGNDにつなぐか、タクトスイッチをつけましょう。

3.3VVDD 1STM32F032 VSSGND
OSC_IN 231 BOOT03.3V
OSC_OUT 330 PB7
RTSNRST 429 PB6
3.3VVDDA 528 PB5
PA0 627 PB4
PA1 726 PB3
PA2 825 PA15
PA3 924 PA14
PA4 1023 PA13
PA5 1122 PA12
PA6 1221 PA11
PA7 1320 PA10TXD
PB0 1419 PA9RXD
LEDPB1 1518 PA8
GNDVSS 1617 VDDIO23.3V
USBシリアルの書き込みに、"STM32 FLASH Writer Program Using Python" stm32writerを使わせてもらいました。 stm32用プロジェクト一式をGitHub"my-first-stm32" からダウンロードし、マシン語のエルチカを書き込んでみましょう。(Mac用です。USBシリアルの設定は、makefile内を書き換えてください)

t0-asm$ make ../tools/stm32writer/stm32writer.py --port=/dev/tty.SLAB_USBtoUART --go "obj.mot" stm32writer (version: 20171231py) ...

うまくいけば書き込み終了後に自動的にエルチカが始まります。
書き込み終わっているので、USBシリアルを外して、BOOT0をGNDに接続し、3Vくらいにつなげばエルチカマシンのできあがりです!

アセンブリ言語でマシン語プログラムも楽しいですが、C言語で開発できるようにすると楽です。
例えば、48MHzへの切り替えの一部 (asm15 アセンブリ言語 from STM32エルチカ)

R0=[@RCC]L R3=R0+4 ' RCC_CFGR R1=[R3]L R2=`1111 R2=R2<<18 R2=~R2 R1&=R2 R2=4 ' PLLMUL6 R2=R2&lt;<18 R1|=R2 [R3]L=R1

これがC言語だと1行で書けます!

RCC->CFGR = (RCC->CFGR & ~(0b1111 << 18)) | (4 << 18);

t1-led-blinkがC言語でのエルチカ、t2-clockがクロックを48MHzに変更と、stm32の取説に合わせて必要最小限のプログラムになっているので、C言語の雰囲気をつかむのにのぞいてみてください。

t2-usartではstm32とのシリアル通信が一応できていますが、どうも内蔵クロックの精度が悪く計算上の値とは5%ほどずれてしまう点と、切り替えるべきAF(Alternate Function)の番号がstmのシリーズによって違う点が注意です。

STM32F0シリーズの取説は、日本語版もあって親切丁寧です!
参考資料 RM0091 リファレンスマニュアル STM32F0x1/STM32F0x2/STM32F0x8 advanced ARM-based 32bit MCUs

コンピューターをフル活用できる、マシン語とC言語の世界もぜひどうぞ!

BASICでプログラムの楽しさを知り
マシン語でコンピューターを知り
C言語でツールの便利さを知る
かつての王道、今でも通じる!?

links
- taisukef/my-first-stm32: first step of STM32F0
- IchigoJamではじめるArmマシン語

jig.jp、2019年4月入社となる新卒エントリーページをオープン!

新卒採用案内 | スマホ(Android/iPhone)アプリ・携帯アプリならjig.jp(ジグジェイピー)

コンテンツ:代表の想い、募集要項、弊社エンジニアの声、座談会、使用技術、使用言語!
jig.jp本店、鯖江の開発センターの雰囲気にビビっと来た人のエントリー、待ってます!

今日の一日一創は、JavaScriptで無いものづくり。

シンプルなアセンブリ言語を「IchigoJamではじめるArmマシン語入門」の解説用に使っていたら、作ってCC0で公開してくれたboxheadroomさんによるasm15アセンブラ! GitHubに載せてオープンソースでオープンライセンスな気軽に使えるWebアプリとして、必要に応じて成長させています。

ターゲットデバイスへのプログラムのバイナリを記述するためのフォーマット、IntelのHEXフォーマットと並ぶ、SRECフォーマット(モトローラSフォーマット、とも呼ばれる)への対応追加!

IoTに最適Arm Cortex-M0からLinuxが動いちゃうCortex-M7までのシームレス感が美しいSTM32の開発環境整備の一貫です。


asm15」 SREC format supported!!

コードを書き足し、テストして、GitHubへコミット!
検索してあえば使う、無ければ創って、共有する。
エンジニアの醍醐味です。

新卒採用案内 | スマホ(Android/iPhone)アプリ・携帯アプリならjig.jp(ジグジェイピー)

Arm社の日本法人、アーム株式会社を訪問。Armと言えば、に、LPC810に、Z80以来のマシン語、楽しませてもらっています!(連載、Armマシン語入門
* 今年、2017.8.1、Arm社は、ARMからArmへと社名とブランドとロゴを変更(ロゴは全部小文字)。合わせて、本ブログ表記もArmへと変更しました。

内海社長ともお会いできました!クリスマスツリーの電飾は、おなじみWS2812B、Armでコントロールされたました!

おみやげに頂いた厚い本「ディジタル回路設計とコンピュータアーキテクチャ[ARM版]
スイッチサイエンスさんも翻訳出版に協力
原著はなんとKindleでも1万円オーバーの超大作「Digital Design and Computer Architecture: ARM Edition

なぜコンピューターは計算が速いのか?」で解説したスイッチの実体、トランジスタや2進数などの基本もしっかり。

マシン語、アセンブリ言語に関する解説もArmの実アーキテクチャーに添っていて実用的!

HDLや、具体的なCPU設計にまで踏み込むマイクロアーキテクチャの章まで揃っていて読み応え抜群。

サイトからI/Oや、C言語に関する解説などをpdfで読むことができます。
Elsevier · Harris, Harris: Digital Design and Computer Architecture · Welcome

2017.12.25(月)、クリスマス。Yahoo! Japan ロッジにて、Armマイコン、IchigoJamで作るクリスマスツリーづくりワークショップを復興庁さん主催で開催!

Fw:東北Weekly 家族でプログラミングしてみよう! 東北発のほやアートをつくってみよう! | Peatix
小中学生のこどもと保護者の方が対象です。プログラミングがはじめての人でもOK!自分だけのオリジナルキラキラツリーを作りましょうっ

(おまけ)Arm訪問記念マシン語プログラム for LPC810、24MHzで800kHz正確コントロール版。

DATA L #10000400 ' stack DATA L #21 ' entry point DATA L 0, 0, 0, 0, 0 DATA L #EFFFFBDF ' VALID_CODE = 0x100000000-0x10000400-0x21 @ENTRY R0=[@SYSAHBCLKCTRL]L R1=#DF 'SWM, GPIO, I2C:off, FLASH, FLASHREG, RAM, ROM, SYS [R0]L=R1 R0=[@FLASHCFG]L R1=[R0]L R2=3 ' flash no wait: set 0b00 R2=~R2 R1&=R2 [R0]L=R1 ' clock setting 24MHz R0=[@PDRUNCFG]L ' PLL power on R1=[R0]L R2=128 R2=~R2 R1&=R2 [R0]L=R1 R0=[@MAINCLKSEL]L R1=3 ' set PLL [R0]L=R1 R0=[@SYSPLLCTRL]L R1=1 ' 0:12MHz 1:24MHz, 2:36MHz, 3:48MHz, 4:60MHz, 7:96MHz, 8:108MHz NG [R0]L=R1 R0=[@MAINCLKUEN]L R1=0 [R0]L=R1 R1=1 [R0]L=R1 ' GPIO setting R0=[@PINENABLE0]L R1=[@PINENABLE0_DATA]L [R0]L=R1 R0=[@GPIO_DIR0]L R1=`1100 ' PIO0_2 and PIO0_3 [R0]L=R1 R4=[@GPIO_NOT0]L R2=`100 ' PIO0_2 ' WS2812B driver ' R0 - data count ' R1 - data address (G1,R1,B1,G2,R2,B2 ....) ' R2 - OUT value ' R3 - data value ' R4 - GPIO address ' R5 - bit count ' R7 - wait count @WS2812B R0=15 R1=@DATA_LED @LOOP_DATA R5=#80 R3=[R1] @LOOP_BIT [R4]L=R2 R3&R5 IF !0 GOTO @ONE @ZERO ' 10-20clock R7=2 ' wait 2*3 = 6clock R7-=1 IF !0 GOTO -1 NOP [R4]L=R2 R7=3 ' wait 3*3 = 9clock R7-=1 IF !0 GOTO -1 GOTO @JOIN @ONE ' 20-10clock R7=5 ' wait 5*3 = 15clock R7-=1 IF !0 GOTO -1 NOP [R4]L=R2 NOP @JOIN R5=R5>>1 IF !0 GOTO @SKIP2 ' 7clock == 1 R1+=1 R0-=1 IF !0 GOTO @LOOP_DATA GOTO @END @SKIP2 NOP NOP NOP GOTO @LOOP_BIT @END R7=[@WAIT_N]L R7-=1 'wait R7*3+1 clock IF !0 GOTO -1 GOTO @WS2812B ' init @SYSAHBCLKCTRL DATA L #40048080 @FLASHCFG DATA L #40040010 @PINENABLE0 DATA L #4000C1C0 @PINENABLE0_DATA DATA L #FFFFFFBF @GPIO_DIR0 DATA L #A0002000 @GPIO_NOT0 DATA L #A0002300 ' clock setting @MAINCLKSEL DATA L #40048070 @MAINCLKUEN DATA L #40048074 @SYSPLLCTRL DATA L #40048008 @PDRUNCFG DATA L #40048238 ' WS2812B @WAIT_N DATA L 4000000 @DATA_LED DATA B 10,0,0, 0,10,0, 0,0,10, 10,0,10, 0,10,10

正確に10clockと20clockに合わせているので、きれいな800kHzの波形がでているはず!
Flashのwait stateを0にしながら、24MHzが正しいのかはちょっと謎ですが、動いてはいるようです。
asm15 アセンブリ言語、アセンブルは、asm15 Assembler でどうぞ!

起業家甲子園出場権を手にしたアントレプレナー研究会のある、富山高専射水キャンパスにてメンタリング。
富山高専本郷キャンパスでjigインターンのOB、すがっちとなぽりたんもジョイン!
高専生ならではの感性と創造力で北陸から一石、投じよう!

北陸、福井、鯖江の銘菓、めがね堅パンのハートエディション!

昨日のLPC810 x WS2812Bにバグが見つかり、無事光るカセットテープのLPC810エディションが点灯!

12MHz版だとちょっと信号はいい加減ですが、ちゃんと光りました!
(原因:asm15の DATA B 0,0,0 が、2byteアラインされてしまうため)

マシン語で作る、簡易キラキラプログラムがこちら!
末尾、16byteを変更すると、アニメーションするLEDの色が変わり、その前4byteでウェイトを調整できます。

10 POKE#700,0,4,0,16,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,223,251,255,239,33,72,223,33,1,96,33,72 20 POKE#728,1,104,3,34,210,67,17,64,1,96,31,72,31,73,1,96,31,72,12,33,1,96,31,76,4,34,15,32,32,161,30,75,14,120,30,112,1,49,1,51 30 POKE#750,1,56,249,209,15,32,26,73,128,37,11,120,34,96,43,66,8,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,96,7,224,0,0,34,96 40 POKE#778,0,0,0,0,0,0,0,0,0,0,0,0,109,8,233,209,1,49,1,56,228,209,13,79,1,63,253,209,10,73,14,120,14,32,79,120,15,112,1,49 50 POKE#7A0,1,56,250,209,14,112,213,231,128,128,4,64,16,0,4,64,192,193,0,64,191,255,255,255,0,32,0,160,0,35,0,160,0,0,0,16,128,26,6,0 60 POKE#7C8,20,0,0,20,20,0,20,0,20,20,20,0,0,20,0,0 70 A=#700:L=216:LRUN1 'FILE1 100 'LPC810 Writer 256byte from ADR:A 110 UART3,2:OUT2,0:OUT1,0:WAIT9:OUT1,1 120 CLS:?"?";:GSB@R 130 ?"Synchronized":GSB@R 140 ?12000:?:GSB@R:GSB@R 150 ?"A 0":GSB@R:GSB@R 160 ?"U 23130":GSB@R 170 ?"W 268436096 ";256:GSB@R:UART1,2:LC0,-1:FORI=0TO255:?CHR$(PEEK(A+I));:NEXT:UART3,2:LC0,6 180 ?"P 0 0":GSB@R 190 ?"E 0 0":GSB@R 200 ?"P 0 0":GSB@R 210 ?"C 0 268436096 256":GSB@R 215 '?"G 268436128 T":GSB@R:END 220 OUT2,1:OUT1,0:OUT1,1:END 500 @R:K=INKEY():IF K=13 K=INKEY():WAIT9:RTN ELSE CONT

マシン語のプログラムはこちら。
データを一旦RAM(#10000000)へ転送し、1ループごとにローテートさせています。

DATA L #10000400 ' stack DATA L #21 ' entry point DATA L 0, 0, 0, 0, 0 DATA L #EFFFFBDF ' VALID_CODE = 0x100000000-0x10000400-0x21 @ENTRY R0=[@SYSAHBCLKCTRL]L R1=#DF 'SWM, GPIO, I2C:off, FLASH, FLASHREG, RAM, ROM, SYS [R0]L=R1 R0=[@FLASHCFG]L R1=[R0]L R2=3 ' flash no wait: set 0b00 R2=~R2 R1&=R2 [R0]L=R1 R0=[@PINENABLE0]L R1=[@PINENABLE0_DATA]L [R0]L=R1 R0=[@GPIO_DIR0]L R1=`1100 ' PIO0_2 and PIO0_3 [R0]L=R1 R4=[@GPIO_NOT0]L R2=`100 ' PIO0_2 @COPYTORAM R0=15 R1=@DATA_LED R3=[@RAM]L @COPYTORAM_LOOP R6=[R1] [R3]=R6 R1+=1 R3+=1 R0-=1 IF !0 GOTO @COPYTORAM_LOOP ' WS2812B driver ' R0 - data count ' R1 - data address (G1,R1,B1,G2,R2,B2 ....) ' R2 - OUT value ' R3 - data value ' R4 - GPIO address ' R5 - bit count ' R7 - wait count @WS2812B R0=15 ' R1=@DATA_LED R1=[@RAM]L @LOOP_DATA R5=#80 R3=[R1] @LOOP_BIT [R4]L=R2 R3&R5 IF 0 GOTO @ZERO NOP NOP NOP NOP NOP NOP NOP [R4]L=R2 GOTO @JOIN @ZERO NOP [R4]L=R2 NOP NOP NOP NOP NOP NOP @JOIN R5=R5>>1 IF !0 GOTO @LOOP_BIT R1+=1 '+6clock R0-=1 IF !0 GOTO @LOOP_DATA @WAIT R7=[@WAIT_N]L R7-=1 'wait R7*3+1 clock IF !0 GOTO -1 R1=[@RAM]L R6=[R1] R0=14 @SLIDE R7=[R1+1] [R1]=R7 R1+=1 R0-=1 IF !0 GOTO @SLIDE [R1]=R6 GOTO @WS2812B ' init @SYSAHBCLKCTRL DATA L #40048080 @FLASHCFG DATA L #40040010 @PINENABLE0 DATA L #4000C1C0 @PINENABLE0_DATA DATA L #FFFFFFBF @GPIO_DIR0 DATA L #A0002000 @GPIO_NOT0 DATA L #A0002300 ' WS2812B @RAM DATA L #10000000 @WAIT_N DATA L 400000 @DATA_LED DATA B 20, 0, 0, 20, 20, 0, 20, 0, 20, 20, 20, 0, 0, 20, 0

asm15 assembler」でアセンブルできます!
WS2812Bの信号は、800kHz(秒間80万回、1.2マイクロ秒に1回)の波の形で、0と1とを区別するので、とても人の手では制御できませんが、マシン語ならたった30円のコンピューターにさせれば余裕です。

切っても切れない、社会とコンピューター。誰にでもオススメしたいプログラミング体験。
IchigoJam BASIC で、プログラミングの基本を、マシン語を使ってコンピューターの真の実力を、それぞれかんたんに体験できます!

光るカセットテープで活躍するWS2812Bを、LPC810を使って自在に点灯できたら簡単、気軽にカセットテープ内にボタン電池も含めて収められてうれしいかも? (IchigoJamを書き込んだLPC1114を使って光るカセットテープを作った例 by JO3GBDさん)


LPC810から制御したWS2812B。
拡大してみると、信号が来るDI側から順に、緑、赤、青と小さく光っている様子が分かります。
データを送信する順も緑、赤、青!

プログラムはこの通り、マシン語部分が長くなってきたら、100行以降を別プログラムとして保存しましょう。

10 POKE#700,0,4,0,16,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,223,251,255,239,24,72,223,33,1,96,24,72 20 POKE#728,1,104,3,34,210,67,17,64,1,96,22,72,22,73,1,96,22,72,12,33,1,96,22,76,4,34,3,32,22,161,128,37,11,120,34,96,43,66,8,208 30 POKE#750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,96,7,224,0,0,34,96,0,0,0,0,0,0,0,0,0,0,0,0,109,8,233,209,1,49 40 POKE#778,1,56,228,209,7,79,1,63,253,209,222,231,128,128,4,64,16,0,4,64,192,193,0,64,191,255,255,255,0,32,0,160,0,35,0,160,64,66,15,0 50 POKE#7A0,2,2,2,0 60 A=#700:L=164:LRUN1 'FILE1 100 'LPC810 Writer 256byte from ADR:A 110 UART3,2:OUT2,0:OUT1,0:WAIT9:OUT1,1 120 CLS:?"?";:GSB@R 130 ?"Synchronized":GSB@R 140 ?12000:?:GSB@R:GSB@R 150 ?"A 0":GSB@R:GSB@R 160 ?"U 23130":GSB@R 170 ?"W 268436096 ";256:GSB@R:UART1,2:LC0,-1:FORI=0TO255:?CHR$(PEEK(A+I));:NEXT:UART3,2:LC0,6 180 ?"P 0 0":GSB@R 190 ?"E 0 0":GSB@R 200 ?"P 0 0":GSB@R 210 ?"C 0 268436096 256":GSB@R 215 '?"G 268436128 T":GSB@R:END 220 OUT2,1:OUT1,0:OUT1,1:END 500 @R:K=INKEY():IF K=13 K=INKEY():WAIT9:RTN ELSE CONT

ちょうど50行、#7A0からの3byteがG(緑)、R(赤)、B(青)の数を指定しています。
書き換えて、実験してみましょう。


LPC810と光ったWS2812B!

マシン語プログラムの解説

asm15でWS2812Bの制御用マシン語プログラムは、LPC1114用を元に、LPC810用に修正します。
Cortex-M0+のLPC810では、OUTポートの扱いがNOTを使えるので短く、1クロックで読み書きできるので高速!
ただ、標準動作の12MHz用に、ウェイトはループではなく、NOPコマンドで調整しました。
厳密にはデータの区切りで速度が追いついていないので、たくさん光らせようとするとおかしくなってしまうため、周波数を上げるかSPIでの制御にしないといけなさそうです。(追記、勘違いでした12MHzでもいけました!

DATA L #10000400 ' stack DATA L #21 ' entry point DATA L 0, 0, 0, 0, 0 DATA L #EFFFFBDF ' VALID_CODE = 0x100000000-0x10000400-0x21 @ENTRY R0=[@SYSAHBCLKCTRL]L R1=#DF 'SWM, GPIO, I2C:off, FLASH, FLASHREG, RAM, ROM, SYS [R0]L=R1 R0=[@FLASHCFG]L R1=[R0]L R2=3 ' flash no wait: set 0b00 R2=~R2 R1&=R2 [R0]L=R1 R0=[@PINENABLE0]L R1=[@PINENABLE0_DATA]L [R0]L=R1 R0=[@GPIO_DIR0]L R1=`1100 ' PIO0_2 and PIO0_3 [R0]L=R1 R4=[@GPIO_NOT0]L R2=`100 ' PIO0_2 ' WS2812B driver ' R0 - data count ' R1 - data address (G1,R1,B1,G2,R2,B2 ....) ' R2 - OUT value ' R3 - data value ' R4 - GPIO address ' R5 - bit count ' R7 - wait count @WS2812B R0=3 R1=@DATA_LED @LOOP_DATA R5=#80 R3=[R1] @LOOP_BIT [R4]L=R2 R3&R5 IF 0 GOTO @ZERO NOP NOP NOP NOP NOP NOP NOP [R4]L=R2 GOTO @JOIN @ZERO NOP [R4]L=R2 NOP NOP NOP NOP NOP NOP @JOIN R5=R5>>1 IF !0 GOTO @LOOP_BIT R1+=1 '+6clock R0-=1 IF !0 GOTO @LOOP_DATA @WAIT R7=[@WAIT_N]L R7-=1 'wait R7*3+1 clock IF !0 GOTO -1 GOTO @WS2812B ' init @SYSAHBCLKCTRL DATA L #40048080 @FLASHCFG DATA L #40040010 @PINENABLE0 DATA L #4000C1C0 @PINENABLE0_DATA DATA L #FFFFFFBF @GPIO_DIR0 DATA L #A0002000 @GPIO_NOT0 DATA L #A0002300 ' WS2812B @WAIT_N DATA L 1000000 @DATA_LED DATA B 2, 2, 2

開始アドレスを0に変えて、hexファイルに変換したものがこちら。
こちらをLPC810に直接書き込んでも動きます!

:1000000000040010210000000000000000000000BB :10001000000000000000000000000000DFFBFFEF18 :100020001848DF210160184801680322D2431140BB :10003000016016481649016016480C210160164CF3 :100040000422032016A180250B7822602B4208D0C1 :10005000000000000000000000000000000022601E :1000600007E0000022600000000000000000000027 :1000700000006D08E9D101310138E4D1074F013F9B :10008000FDD1DEE78080044010000440C0C1004084 :10009000BFFFFFFF002000A0002300A040420F0090 :0400A0000202020056 :00000001FF

links
- IchigoJamでLPC810マイコン開発!(デプロイ・完結編)
- IchigoJamでも光る大五郎! 300コのフルカラーLEDを簡単コントロール! IchigoJam x WS2812B/SK6812/NeoPixel
- はじめてのマシン語 - IchigoJamではじめるArmマシン語その1

IchigoJam web(ブラウザで動くIchigoJam)で使っているお気に入り技術、WebAssembly。
マシン語をバイナリで直接書いてみる第一回、初歩的なアセンブラ体験する第二回に続く第三回のテーマは、コンパイラです。

おさらいとして、前回のアセンブラで、param+10 を計算するプログラムを作ってみましょう。

正解はこちら

get_local $0 i32.const 10 i32.add end

paramが1の時、ちゃんと答は11と出ます。では、param+100 を計算するプログラムに変えてみてください。

おや、おかしいですね!?では、128にすると、今度はコンパイルエラーになってしまいます。

WebAssemblyのマシン語での数値は大きさによって1byteから5byteまで長さを変えて表します。最上位bitが1なら、次のbyteを読んで上位に追加していく仕組みになっています。 つまり、1byteで表せる数は、7bitで表せる-64〜63まで。100(2進数で1100100)はこの範囲を超えているので、上位bitを1にして、残りのbitを次のbyteで表すので、1 1100100 (e4) と 0 0000000 (00) となります。

WebAssemblyのコードを書き換えて試してみましょう。

20 0 41 e4 0 6a b

i32.const を表す 41 の後の 64 (=10進数の100) を、e4 に変えてその後ろに 0 を加えて「RUN」
ちゃんと答がでました!

このような計算をいちいち手でやらなくて済む方法は?・・・そうです、プログラムですね。
命令表から手打ちするのも面倒なので、短く楽にプログラムを書けるようにするソフトをつくりましょう。

コンパイラはじめのいっぽ
「P 3 +」と空白区切りで書いたら対応するアセンブリ言語を出力するものです。
※ P は、パラーメータ0を意味することにします

compilebtn.onclick = function() { var src = srcprg.value.split(" "); var asm = []; for (var i = 0; i < src.length; i++) { var s = src[i]; if (s == "P") { asm.push("get_local 0"); } else if (s == "+") { asm.push("i32.add"); } else if (parseInt(s) == s) { asm.push("i32.const " + s); } } asm.push("end"); srcasm.value = asm.join("\n"); }

簡単ですね。このようなソフトをコンパイラといいます。
掛け算とかいろいろ足したものがこちら「WebAssembly poor compiler」です。

WebAssembly poor compiler

「P 3 +」と入力し「COMPILE」「ASSEMBLE」「RUN」と順に押して、答が出してみましょう。

課題:パラメータを自乗して1を足すプログラムをつくってみよう!

アセンブラも上記、大きな数値にも対応するよう改良してあるので、プログラムを確認してみてください。

次はこのコンパイラをもう一歩進めて、もっと自然な数式で書けるように改良してみます。
待ちきれない人は、どんどん進めちゃってください!

WebAssemblyマシン語入門
- ブラウザだけでOK! 1+1からはじめる、WebAssemblyマシン語入門その1
- プログラミングはプログラミングで楽をする、WebAssemblyマシン語入門その2
- もっと楽するコンパイラ、WebAssemblyマシン語入門その3

- 連載、IchigoJamではじめる、Armマシン語入門
1. はじめてのマシン語
2. ハンドアセンブルで超速計算!
3. マシン語メモリアクセスで画面超速表示!
4. マシン語でLEDを光らせよう!
5. 楽しさ広がるマルチバイトメモリアクセスとスタック
6. マシン語使いこなしTIPS
7. カジュアルに使うインラインマシン語
8. アセンブラを使って楽しよう
9. マシン語で高速SPI
10. マシン語を制するもの時間を制す
11. 画面をイチゴで埋め尽くす12の方法
12. レジスタ不足に上位レジスタとスタック操作

links
- WebAssembly Advent Calendar 2017 - Qiita 参加!

小さくても立派な32bit Arm Cortex-M0+のCPU、NXP社製、LPC810、75円 @marutsu
最大動作周波数30MHz、秒間3000万回計算してくれます!

本ブログでも、暗闇で自転車を探すフラッシュライトにしてみたり、おもちゃに音を組み込んだりクリスマス手作りプレゼントや、PCGサウンドライブラリSoundCortexをつかってIchigoJamから三和音鳴らしたりと、活躍。

このかわいいマイコンLPC810をIchigoJamでクロスプロットフォーム開発できる環境を目指し、BASIC風表記なアセンブリ言語 asm15 で、まずは基本にして、コンピューター制御の本質、LEDをチカチカさせる「エルチカ」プログラムをつくってみます。

エルチカは、2ステップあります。まずは、LEDを光らせること。そして、思い通りの時間待たせること。

LPC810のピンをこのように並びで使います。

RESETLPC810RXD
TXDGND
PIO0_33.3V
PIO0_2ISP

LPC1114と同様、電源を入れた時や、RESETがGNDから復帰した際、ISPがGNDになっていると書き込みモードになり、RXD/TXDをつかって、USBシリアルとソフト(FlashMagicやlpc21ispなど)で書き込みます。


ちょっと横着して、PIO0_2にLEDの長い方、PIO0_3に短い方を差し込んでテストします。

DATA L #10000400 ' stack top DATA L #21 ' entry point DATA L 0,0,0,0,0 DATA L #EFFFFBDF ' VALID_CODE = 0x100000000-0x10000400-0x21 @ENTRY R0=[@SYSAHBCLKCTRL]L R1=#DF 'SWM, GPIO, I2C:off, FLASH, FLASHREG, RAM, ROM, SYS [R0]L=R1 R0=[@PINENABLE0]L R1=[@PINENABLE0_DATA]L [R0]L=R1 R0=[@GPIO_DIR0]L R1=`1100 ' PIO0_2 and PIO0_3 [R0]L=R1 R0=[@GPIO_B0]L R1=1 [R0+2]=R1 GOTO 0 @SYSAHBCLKCTRL DATA L #40048080 @PINENABLE0 DATA L #4000C1C0 @PINENABLE0_DATA DATA L #FFFFFFBF @GPIO_DIR0 DATA L #A0002000 @GPIO_B0 DATA L #A0000000

LPC1114はCortex-M0、LPC810はCortex-M0+とマシン語はほぼ一緒ですが、IOの扱い方が違います。
1. LPC810のRAMは#10000000からの1KBなので、スタック初期値を#10000400に設定
2. 書き込みチェック用コードの次、#21にプログラム本体をおく
3. SYSAHBCLKCTRLで、GPIO、SWT(スイッチマトリクス、IOを切り替えるモノ)を設定
4. PINENABLE0で、PIO0_2/PIO0_3をGPIOとして使うよう設定
5. GPIO_DIR0で、PIO0_2/PIO0_3を出力に切り替え
6. GPIO_B0で、PIO0_2に1を書き込むと光る!
7. そのまま実行を続けてしまわなないように GOTO 0 で停止させておく

asm15で、Start Addressを0に設定、「hex file」出力を選択し、USBシリアルで書き込みます。
*3はスキップしても大丈夫でしたが、念のため。(参考、LPC1114の場合

次に、IchigoJam BASICでいう、WAITコマンドを実現して、0.5秒ごとについたり消えたりさせます。

DATA L #10000400 ' stack DATA L #21 ' entry point DATA L 0,0,0,0,0 DATA L #EFFFFBDF ' VALID_CODE = 0x100000000-0x10000400-0x21 @ENTRY R0=[@SYSAHBCLKCTRL]L R1=#DF 'SWM, GPIO, I2C:off, FLASH, FLASHREG, RAM, ROM, SYS [R0]L=R1 R0=[@FLASHCFG]L R1=[R0]L R2=3 ' set 0b00 == no wait R2=~R2 R1&=R2 [R0]L=R1 R0=[@PINENABLE0]L R1=[@PINENABLE0_DATA]L [R0]L=R1 R0=[@GPIO_DIR0]L R1=`1100 ' PIO0_2 and PIO0_3 [R0]L=R1 R0=[@GPIO_NOT0]L R1=`100 ' PIO0_2 R2=[@WAIT_N]L @LOOP [R0]=R1 ' 1cycle single cycle I/O R3=R2 ' 1cycle R3-=1 ' 1cycle IF !0 GOTO -1 'wait R3*3+2 cycles GOTO @LOOP ' 2cycles @SYSAHBCLKCTRL DATA L #40048080 @FLASHCFG DATA L #40040010 @PINENABLE0 DATA L #4000C1C0 @PINENABLE0_DATA DATA L #FFFFFFBF @GPIO_DIR0 DATA L #A0002000 @GPIO_NOT0 DATA L #A0002300 @WAIT_N DATA L 2000000

Cortex-M0+は、Cortex-M0と比較しGPIOアクセスや、GOTOのサイクルが短くなっています。(2→1、3→2、詳細はマニュアル参照

起動時の動作クロックは、内蔵オシレーターの12MHz。ウェイト用の1ループにかかる時間は3cycles。よって、12M/3で400万回ループで1秒。0.5秒のウェイトのために、WAIT_Nに200万を設定すればOK!

GPIO_NOT0という指定したビットに対応するIOを反転させるという便利な機能をつかって、エルチカループ(LOOP)をつくります。

注意点は、FLASHCFGの設定でウェイトを外しておくこと。 初期状態ではFlash ROMへのアクセスにウェイトがついているため、思ったより遅い点滅に悩みました。


2.54mmピッチではんだづけ工作にも優しい、8ピンDIPパッケージ(Dual inline package)のLPC810は、マシン語でさくっと遊べちゃうところもかわいい!

Armマシン語に興味もった方、「はじめてのマシン語 - IchigoJamではじめるArmマシン語」をどうぞ!

links
- [PDF]UM10601 LPC81x User manual - NXP Semiconductors
- LPCマイコン情報:LPC800 Cortex-M0+搭載-スイッチ・マトリックス,LPC824,LPC822,LPC810,LPC811,LPC812,LPC810M021FN8,LPC824M201,LPC822M101,LPC811M001,LPC812M101

前回「ブラウザだけでOK! 1+1からはじめる、WebAssemblyマシン語入門その1」では、マシン語の命令表からひとつずつ選んで数を書いてみました。 プログラムをこのようにマシン語にする作業のことをアセンブル(英語で組み立てを意味する)と言います。

数が多くなってくると、こうして手で変換するのは大変なので、プログラムを作って自動化しましょう。 今使っている環境の範囲だけで動く簡易的なアセンブラ「WebAssembly poor assembler」をJavaScriptで作りました。


WebAssembly poor assembler

こちら、前回はマシン語だった param+1 を計算するプログラムのアセンブリ言語プログラムです。

get_local $0 i32.const 1 i32.add end

「ASSEMBLE」ボタンを押すと、下に数字の並びに変換され、RUNで動かせます。

20 0 41 1 6a b

試しに、i32.add を i32.mul に書き換えて、ASSEMBLE、RUNしてみましょう。
i32.const 1 を i32.const 5 に書き換えて、ASSEMBLE、RUNしてみましょう。
param に、10と入力しなおして、RUNしてみましょう。

ちょっとだけ複雑な計算をさせてみます。

get_local $0 i32.const 5 i32.mul i32.const 1 i32.add end

i32.const 1 と i32.add を書き加えて、n*5+1 を計算するプログラムにしました。
ASSEMBLE、RUNしたり、paramを書き換えてみましょう。

このようにアセンブルを自動化するプログラムのことを、アセンブラといいます。
(手でアセンブルすることをハンドアセンブルといい、アセンブラがない時代の必須テクニックでした)

次はコンパイラを作ってみます。お楽しみに!

WebAssemblyマシン語入門
- ブラウザだけでOK! 1+1からはじめる、WebAssemblyマシン語入門その1
- プログラミングはプログラミングで楽をする、WebAssemblyマシン語入門その2
- もっと楽するコンパイラ、WebAssemblyマシン語入門その3

コンピューターの気持ちに近づけるマシン語。
IchigoJamだけで始めるArmマシン語入門に続き、
ブラウザだけで始めるWebAssemblyマシン語入門その1です。

コンピューターは高速に計算する機械(=マシン)です。

メモリ(=記憶装置)に2つの数があったら足し算する電子回路があるとします。
1と1をメモリに書いたら瞬時に2が得られます。
(参考「なぜコンピューターは計算が速いのか? 電気回路で計算ができる謎を解く」)

足し算だけだと使いみちが限られるので、引き算・掛け算や、計算順序を変える機能などを追加します。
機能を区別する方法は何でもいいのですが、計算が得意なコンピューターのために、それぞれの機能に数を割り当ててあげると効率的です。
やってほしい計算を表す数をずらずらと並べたもの、これがマシン語プログラムとなります。

IchigoJamで使っているのはArmという会社が考えたコンピューターなので、Armマシン語。
今回使うWebAssemblyマシン語は、ブラウザで動くことにした仮想的なコンピューターです。
仮想的とは、マシン(ハードウェア)をソフト(=プログラム)で表現したものを言います。

とりあえず、動かしてみましょう。
WebAssembly testenv」を開き、「RUN」を押すと、2とでます。


WebAssembly testenv」で、1+1=2 をマシン語プログラムでつくり、動かした様子

「param」に1と書いてあるものを、10に変えて、もう一度「RUN」を押してみましょう。
きっと、今度は11と出ます。
(もし動かないならば、きっとお使いのブラウザがWebAssemblyに対応していません!Chrome/FireFox/Safariの最新版をダウンロードしましょう)

20 0 41 1 6a 0b

実はこれがWebAssemblyのマシン語です。(0〜9とa〜fの15種類の文字を使った16進法表記)

右の表を照らし合わせてみると・・・
20 0 ・・・ get_local $0 (渡された数をメモリに書くよ)
41 1 ・・・ i32.const 1 (1をメモリに書くよ)
6a ・・・ i32.add (メモリに書かれた2つの数を足してメモリに書くよ)
0b ・・・ end (プログラムを終わって、メモリに書かれたものを返すよ)

と解読できます。

10-1を計算させるには、i32.add (6a) の代わりに i32.sub (6b) を使います。

20 0 41 1 6b 0b

計算できました!

コードの上に書いてある、WebAssmeblyマシン語であることを表すIDなどと組み合わせて、.wasmファイルを作成すれば、ブラウザ上で高速に動くプログラムができるわけです!

右の表にあるものはもちろん一部です。
興味があればWebAssemblyの仕様書を覗いてみましょう。

ひとつひとつ表から照らし合わせてプログラムを書くのは大変なので、普通はこの作業をプログラムで自動化します。
アセンブラとか、コンパイラなどと呼ばれるソフトで、その数だけプログラミング言語があるわけですね!

マシン語が分かれば自分だけのプログラミング言語を作ることもできちゃいます!
日本生まれで世界に広がるプログラミング言語 Ruby に続こう!

WebAssemblyマシン語入門
- ブラウザだけでOK! 1+1からはじめる、WebAssemblyマシン語入門その1
- プログラミングはプログラミングで楽をする、WebAssemblyマシン語入門その2
- もっと楽するコンパイラ、WebAssemblyマシン語入門その3

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