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

WS2812Bを観察しよう!IchigoJamで開発するLPC810でフルカラーLED点灯実験

2017/12/17
#IchigoJam #maker #lpc810 #asm 

光るカセットテープで活躍する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 'SWT, 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

もっと楽するコンパイラ、WebAssemblyマシン語入門その3

2017/12/05
#asm #wasm #js 

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 参加!

マシン語で作る!75円のかわいいArmマイコン、LPC810用エルチカプログラム

2017/11/28
#lpc810 #maker #asm 

小さくても立派な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 'SWT, 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 'SWT, 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

プログラミングはプログラミングで楽をする、WebAssemblyマシン語入門その2

2017/11/09
#asm #wasm #js 

前回「ブラウザだけで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

ブラウザだけでOK! 1+1からはじめる、WebAssemblyマシン語入門その1

2017/11/07
#asm #wasm 

コンピューターの気持ちに近づけるマシン語。
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

LPC1114マシン語ベアメタル開発の魅力、プログラミングも世界共通語!

2017/10/21
#IchigoJam #asm 

たった28byteから始めるマシン語アプリ開発」でエルチカがうまくいかない謎が解けました。
4byteの数値が続くヘッダの8番目「Criterion for valid user code」の不備でした。(Thanks Amaganagi-san

ということで、LED1に相当するマシン語の最小コード改はこのコードを含めた32byteとなります。

DATA L #10001000 DATA L #00000009 R1=[@GPIO1DIR]L R0=`100000 [R1]=R0 R1=[@LED]L [R1]L=R0 GOTO 0 @GPIO1DIR DATA L #50018000 @LED ' PIO1_5 DATA L #50010080 @VALID_USER_CODE DATA L #FEDC5665

命令byteが20byteを超える場合は、次のように記述します。

DATA L #10001000 DATA L #00000021 DATA L 0,0,0,0,0 DATA L #EFFFEFDF R1=[@GPIO1DIR]L R0=`100000 [R1]L=R0 R2=0 R7=[@WAITCNT]L R1=[@LED]L @LOOP [R1]L=R0 R6=R7 R6-=1 IF !0 GOTO -1 [R1]L=R2 R6=R7 R6-=1 IF !0 GOTO -1 GOTO @LOOP @GPIO1DIR DATA L #50018000 @LED ' PIO1_5 DATA L #50010080 @WAITCNT DATA L 3000000

VALID_CODEは、hex(0x100000000-0x10001000-0x21) = 0xEFFFEFDF と計算します。
これで心置きなくマシン語でプログラミングできそうです!

夜中の帰国となり、大阪泊、オーストラリアから来ていたプログラマーの人に会いました。
LPC1114の開発に興味津々、C言語/マシン語でのベアメタル開発、楽しさを紹介!

世界に広がるPCN、音楽と同じようにプログラミングも世界共通語になりそうです!

大阪、道頓堀近く、HOLTEL HYAKU にて!

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

画面をイチゴで埋め尽くす12の方法 / IchigoJamではじめるArmマシン語その11

2017/09/24
#IchigoJam #asm 

IchigoJamのキャラクターコード255は、イチゴ。
これで画面を埋め尽くす12の方法、まずはBASICから!


1. 延々イチゴを表示して埋め尽くす(GOTO編)

10 ?CHR$(255);:GOTO10 RUN

2. 延々イチゴを表示して埋め尽くす(CONT編)

1 ?CHR$(255);:CONT

再開するCONTコマンドは、プログラム内に書くとその行を再度実行として機能します

3. FOR/NEXTコマンドで埋め尽くす(768=32*24)

FORI=1TO768:?CHR$(255);:NEXT

4. VIDEO0で一旦画面出力を止めて高速化(画面表示OFFで約3倍速)

VIDEO0:FORI=1TO768:?CHR$(255);:NEXT:VIDEO1

5. LOCATE(短縮計LC)を使って縦に埋める

FORI=0TO31:FORJ=0TO23:LCI,J:?CHR$(255);:NEXT:NEXT

6. VRAMに直接書き込む(HELPコマンドでVRAMのアドレスが確認できます)

FORI=#900TO#BFF:POKEI,255:NEXT

7. COPYコマンドを使って一瞬で埋める

POKE#900,255:COPY#901,#900,768-1

実用的にはこれで十分ですが、マシン語を使って究極を目指してみます

8. マシン語を使って埋める (22byte 5383cycle)

R2=9 R2=R2<<8 R1=R1+R2 R2=32 R3=24 R2*=R3 @LOOP [R1]=R0 R1+=1 R2-=1 IF !0 GOTO @LOOP RET

32*48で768、数値が1byteの上限255を超えるので、掛け算命令で設定。

POKE#700,9,34,18,2,137,24,32,34,24,35,90,67,8,112,1,49,1,58,251,209,112,71 U=USR(#700,255)

ハンドアセンブルか、asm15アセンブラを使ってマシン語を作成しUSRコマンドで実行!
1cycle = 21nsec、割込が無いとすれば、113usec、つまり0.1ミリ秒で処理完了です。

9. マシン語、4byteまとめて埋めて高速化 (26byte 1353cycle)

R2=9 R2=R2<<8 R1=R1+R2 R2=R0<<8 R0+=R2 R2=R0<<16 R2+=R0 R0=192 @LOOP [R1]L=R2 R1+=4 R0-=1 IF !0 GOTO @LOOP RET

メモリへの書き込みは1byte、2byte、4byteと3種類。まとめて4byte書くように変更することで、プログラムは10byte増えてしまいましたが、約4倍速に!

10. マシン語、まとめて転送命令STMを使って高速化 (36byte 378cycle)

PUSH {LR,R4,R5,R6,R7} R2=9 R2=R2<<8 R1=R1+R2 R2=R0<<8 R0+=R2 R2=R0<<16 R2+=R0 R3=R2 R4=R2 R5=R2 R6=R2 R7=R2 R0=32 @LOOP STM R1,{R2,R3,R4,R5,R6,R7} R0-=1 IF !0 GOTO @LOOP POP {PC,R4,R5,R6,R7}

Arm Cortex-M0にあるまとめて転送命令STMは、アドレスR1へ複数指定したレジスタの値をアドレスの値を変更しながら高速に転送してくれます(転送時間=転送数+1クロック)。 R2からR7まで6レジスタ、24byteまとめて転送できるので32回ループすれば画面全部を埋められます。

11. マシン語、ループ展開 (86byte 248cycle、転送部分220cycle)

PUSH {LR,R4,R5,R6,R7} R2=9 R2=R2<<8 R1=R1+R2 R2=R0<<8 R0+=R2 R2=R0<<16 R2+=R0 R3=R2 R4=R2 R5=R2 R6=R2 R7=R2 R0=R2 STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3,R4,R5,R6,R7} STM R1,{R0,R2,R3} POP {PC,R4,R5,R6,R7}

ループのために分岐すると3cycle時間を消費してしまうので、ループの数がそれほど多くなければ展開して高速化できます。 ループ用の変数が不要になるので、7レジスタ使ってSTMの回数も減らせて一石二鳥。 ただ、プログラム量は必然的に多くなりがちなので、容量に余裕がある時に使いましょう。

12. キーボードで ALT+V 押しっぱなし(手動)
プログラムを作ることはあくまで手段。手でやったほうが速いこともあります。

目的を達成するための方法は様々です。

同じマシン語でも8番のシンプルなマシン語に比べ、11番のプログラムでは、24倍も速くできました。
ターゲットのCPUに合わせた最適化を行うことで、ぐっと効率が上げられたりします。

BASICであってもコマンドの使い方次第でぐっと速くできます。
リファレンスを見直して、いろいろな使い方を探ってみるのもいいですね。

速度重視?容量重視?作りやすさ重視?
目的に合わせて選択できる手段を増やしておくと、叶う夢の幅が広がります!

(追記)
13. マシン語、ループ展開 PUSH編 (84byte 247cycle、転送部分214cycle)
IchigoJam-FANにて、PUSHを使った更に速い方法が発見されました!(Thanks Amanagi-san)
転送部分のみで214cycle、方法11と仕様を合わせても84byte/247cycleと、2byte減って1cycle/21nsec高速!

PUSH {LR,R4-R7} R2=#C R2=R2<<8 R1=R1+R2 R2=R0<<8 R0+=R2 R2=R0<<16 R2+=R0 R12=R13 R13=R1 R1=R2 R3=R2 R4=R2 R5=R2 R6=R2 R7=R2 R0=R2 R14=R2 PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {LR,R0-R7} PUSH {R0-R2} R13=R12 POP {PC,R4-R7}

* スタックポインタ(R13)を破壊可能なR12に退避し、VRAMの末尾アドレスに変更、LR(R14)も使って36byte(9レジスタ*4byte)転送するという技!埋めるキャラクターがイチゴ(#FF)なのを利用して、更に縮めることも!?

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

MSXのZ80マシン語解析と、IchigoJamの太字化マシン語プログラム

2017/09/17
#IchigoJam #asm #MSX 

IchigoJamの太字化、MSXの例に習ってマシン語化してみました。

POKE#800,7,34,18,2,137,24,10,120,19,70,82,8,26,67,10,112,1,49,1,56,247,209,112,71

PCGの#700に使いたい文字のパターンをコピー(この例は0〜9の数字をALT+0〜9へコピー)

COPY#700,ASC("0")*8,10*8

あとは太字化処理したいバイト数を指定してマシン語呼び出し!(2度実行すると更に太字に!)

U=USR(#800,10*8)

ALT+0〜9で書いてみましょう!プログラムでももちろん使えます

FOR I=0 TO 9:?CHR$(224+I):NEXT

ベースのアイデアはこちらMSX版

MSX BASICのプログラム、70行で書き込んでいる23byteのマシン語部分を解析(逆ハンドアセンブル)してみました。(表示用につくった MSXLIST

Z80のニーモニックを、asm15表記風に書いてみるとこんな感じです。

BC=#700 HL=#100 @LOOP GOSUB @RDVRM E=A A>>=1 A|=E GOSUB @WRVRM HL+=1 BC-=1 A=B A|=C IF !0 GOTO @LOOP RET

Z80のレジスタは基本8bitなので、16bitとして使うBCレジスタの0判定がおもしろいですね! MSXのVRAMはRAMに割り当てられていないので、BIOSというMSX組み込みのコードを呼び出していました(RDVRM/WRVRM)。 どうもこの呼出が結構遅い様子。VDPという一種のGPUを使って高速化するのが常套手段だったようです。(VDPはGPUの元祖かも?)

IchigoJam用に書き換えたマシン語がこちら(asm15 assemblerでアセンブルできます)

R2=7 R2=R2<<8 R1=R1+R2 @LOOP R2=[R1] R3=R2 R2=R2>>1 R2|=R3 [R1]=R2 R1+=1 R0-=1 IF !0 GOTO @LOOP RET

ほぼ一緒ですね!

このようにCPUが違うとそのCPUで使えるレジスタや、コマンドが違いますが、やっていることは基本的に同じ。 C言語やJavaなどは、このようなCPU毎の差を埋めるプログラム(コンパイラ)が助けてくれているわけです。

何でも作れちゃう感がアップする「マシン語」おすすめです!
連載、IchigoJamではじめる、Armマシン語入門 1. はじめてのマシン語

amiiboも読める! マシン語で実用的になったRFID-RC522リーダー on IchigoJam

2017/08/22
#IchigoJam #maker #asm 

電車社会では手放せないFeliCa。
ピッと読み取るひみつは NFC(Near Field Communication / 近距離無線通信)という技術にあります。
カード側には電池が不要なので、安く、手軽に使えるのがポイントです。

先日実験した300円のNFCリーダー、RFID-RC522のIchigoJamプログラムを一部マシン語化して、実用的な速度になりました!(Amazonでタグ1枚100円未満!、リーダーRC522はなんと250円〜

FeliCaとは違う規格、RC522はMIFAREのRFIDリーダーですが、なんと任天堂の人形、amiiboが読めました!

amiibo認識するIchigoJamのデモ、子供に人気でした!

高校生三崎くんは、どこまで浮かせて読めるか早速実験!楽しいおもちゃを作って上げられそうっ

RC522-RFIDリーダープログラム、マシン語化手順(参考、SPI高速送信SPI高速受信
OUT2がSCK、OUT3がMOSI、IN1がMISOとして使う1byte(=8bit)のSPI通信は、BASICで書くとこうなります。

10 @SPI:N=0 'send:M recv:N 20 FOR I=7 TO 0 STEP-1 30 OUT2,0 40 OUT3,M>>I&1 50 N=IN(1)<<I|N 60 OUT2,1 70 NEXT

これをアセンブリ言語で書いて

@SPI PUSH {LR,R4,R5} R3=#50 ' R3=#50010000 GPIO1 R3=R3<<8 R4=R3 ' R4=#50000000 + (1<<(10+2)) IN(1) GPIO0_10 R3=R3+1 R3=R3<<16 R4=R4<<16 R2=1 R2=R2<<12 R4=R4+R2 R5=0 R1=#80 @LOOP R2=0 R0&R1 'F=N>>(7-I)&1 IF 0 GOTO @SKIP1 R2+=4 @SKIP1 [R3+`110]L=R2 ' OUT2,0:OUT3,F R2=2 [R3+`0010]L=R2 ' OUT2,1 R2=[R4]L ' IN(1) R2-0 IF 0 GOTO @SKIP2 R5=R5+R1 @SKIP2 R1=R1>>1 IF !0 GOTO @LOOP @END R0=R5 POP {PC,R4,R5}

レジスタの役割:R0 送信データ、R1 カウンタ、R2 書き込み用、R3 GPIO1 for OUT、R4 GPIO0 for IN、R5 受信データ

asm15アセンブラでマシン語化

10 POKE#700,48,181,80,35,27,2,28,70,91,28,27,4,36,4,1,34,18,3,164,24,0,37,128,33,0,34,8,66,0,208,4,50,154,97,2,34,154,96,34,104 20 POKE#728,0,42,0,208,109,24,73,8,242,209,40,70,48,189

前回はBASICだったSPI通信部分をマシン語呼び出しに置き換えて、できあがり!

1 'RFID-RC522 1/2 2 A=#700:POKEA,48,181,80,35,27,2,28,70,91,28,27,4,36,4,1,34,18,3,164,24,0,37,128,33,0,34,8,66,0,208,4,50,154,97,2,34,154,96,34,104 3 POKE#728,0,42,0,208,109,24,73,8,242,209,40,70,48,189 10 OUT4,0:WAIT4:OUT1,1:OUT4,1 20 LET[0],#2400,#2600,#4826,#5480,#56A9,#5803,#5AE8,#2A40,#223D 30 FORJ=0TO8:N=[J]:GSB@SPIW:NEXT 40 N=#28:GSB@SPIR:IF N&3!=3 N=#2800|N|3:GSB@SPIW 50 @LOOP:?"."; 55 LET[0],#2400,#2600,#4826 60 FORJ=0TO2:N=[J]:GSB@SPIW:NEXT 70 N=#1C:GSB@SPIR:N=#1C00|N&#7F:GSB@SPIW 90 LET[0],#200,#87F,#1480,#1226,#1A07,#20C 100 FORJ=0TO5:N=[J]:GSB@SPIW:NEXT 110 N=#1A:GSB@SPIR:N=#1A00|N|#80:GSB@SPIW 120 N=#8:GSB@SPIR:IF N&1 GOTO@LOOP 130 IF N&#30=0 GOTO120 140 N=#C:GSB@SPIR:IFN&#13?"ERR";N:GOTO@LOOP 150 N=#14:GSB@SPIR:IFN!=2GOTO@LOOP 160 N=#12:GSB@SPI2R 170 N=#18:GSB@SPIR 190 ?"!":LRUN FILE()+1 500 @SPIW:OUT1,0:U=USR(A,N>>8):U=USR(A,N):OUT1,1:RTN 510 @SPIR:OUT1,0:U=USR(A,N|#80):N=USR(A,0):OUT1,1:RTN 520 @SPI2R:OUT1,0:N=N|#80:U=USR(A,N):N=USR(A,N)<<8|USR(A,0):OUT1,1:RTN SAVE0 NEW 1 'RFID-RC522 2/2 10 N=#1C:GSB@SPIR:N=#1C00|N&~#80:GSB@SPIW:N=#1A00:GSB@SPIW 30 LET[0],#200,#87F,#1480:FORJ=0TO2:N=[J]:GSB@SPIW:NEXT 50 N=#1293:M=2<<4:GSB@SPI2W:N=#1A00:GSB@SPIW:N=#20C:GSB@SPIW 110 N=#1A:GSB@SPIR:N=#1A00|N|#80:GSB@SPIW 120 N=#8:GSB@SPIR:IFN&1GOTO@END 130 IFN&#30=0GOTO120 140 N=#C:GSB@SPIR:E=N:IFE&#13GOTO@END 150 N=#14:GSB@SPIR:IF N!=5 GOTO@END 160 M=N:N=#12:GSB@SPIAR:FORI=0TOM-1:?HEX$([I],2);:NEXT:? 170 N=#18:GSB@SPIR 190 @END:LRUNFILE()-1 'ASM 500 @SPIW:OUT1,0:U=USR(A,N>>8):U=USR(A,N):OUT1,1:RTN 505 @SPI2W:OUT1,0:U=USR(A,N>>8):U=USR(A,N):U=USR(A,M):OUT1,1:RTN 510 @SPIR:OUT1,0:U=USR(A,N|#80):N=USR(A,0):OUT1,1:RTN 530 @SPIAR:OUT1,0:N=N|#80:U=USR(A,N) 540 FORJ=0TOM-1:[J]=USR(A,N):NEXT 550 J=J+1:[J]=USR(A,0):OUT1,1:RTN SAVE1 LRUN0

* RC522の初期化とカード認識と、ID読み込みで2ファイル使います(上記はFILE0とFILE1使用)

高専インターン2日目は企画づくりとチーム決定、4名ずつ4チームが決定です!
チームとタイトルの二日目 - jigintern2017の日記

全国から集まった高専生、お土産も多彩!お返しに IchigoJamハーフキット!

鯖江市市民主役事業、中学校の先生向けプログラミング研修では、はんだづけからのパソコンづくりと、プログラミングづくり体験を実施。 興味持った子供が通える「Hana道場」が鯖江のいいところ!

未来の高専生!? 夏休み中の小学生で賑わうHana道場
Ichigoチョコ越前がにロボコンテストコース、片道攻略!

どんなロボットでも歓迎、小学生向け越前がにロボコン、エントリー締切は8月末!

54byteのスーファミコントローラドライバ、IchigoJam BASICとマシン語でつなぐ極上のコントローラ

2017/08/16
#IchigoJam #asm #game 

IchigoJamにスーファミコントローラがつながりました!
個人的コントローラランキング、ナンバーワンのスーファミコントローラ、konashiでiPhoneにつないだこともありました。

接続に便利だった、Raspberry Piのスーパーファミコン化プロジェクトのコントローラ変換器!(official site)

こちら先日のコミケC92で入手! (スーファミコスプレな @ichigonosaatan さぁたん)

配線は本の記述とはちょっと違っていて、CLKの上にある3.3V、P/Sの下にあるGNDを使っていました。
スーファミのコントローラ3.3Vでも動くようです!

ファミコンもスーファミも、コントローラとの通信はYMF825と同じ、おなじみSPI。
ファミコンは8bit、スーファミはボタンが増えた分、上位8bitが追加されて16bitでの通信となります。

ひとまず、下記のようにつないで、IchigoJam BASICで動作確認。
OUT1 P/S(LATCH)
OUT2 CLK
IN1 1PAD

10 OUT1,1:OUT2,1 20 GSB@SPIR:?BIN$(N,16):CONT 100 @SPIR:OUT1,0:N=0:FORI=0TO15:OUT2,0:N=IN(1)<<I|N:OUT2,1:NEXT:OUT1,1:RTN

これだけで動きました!感動!

ただ、ゲームなどに使うには動作が遅すぎるので、マシン語でSPIテクニックを使って、高速化します。

@SPIR PUSH {LR,R4} R3=#50 ' R3=#50010000 GPIO1 R3=R3<<8 R4=R3 ' R4=#50000000 + (1<<(10+2)) IN(1) R4=R4<<16 R3=R3+1 R3=R3<<16 R2=1 R2=R2<<12 R4=R4+R2 R2=0 [R3+`0001]L=R2 ' OUT1,0 R1=0 @LOOP R2=0 [R3+`0010]L=R2 ' OUT2,0 R2=[R4]L ' IN(1) R2=R2>>10 R2<<=R1 R0=R0+R2 R2=2 [R3+`0010]L=R2 ' OUT2,1 R1+=1 R1-16 IF !0 GOTO @LOOP @END R2=1 [R3+`0001]L=R2 ' OUT1,1 POP {LR,R4}

マシン語入門その4を参考にIN1を調べるとピンの名前はPIO0_10、GPIO0のベースアドレスが#50000000と分かります。

できあがった、マシン語のスーファミコントローラドライバ(ファミコンにも使えます)を組み合わせたテストプログラムがこちら

1 POKE#700,16,181,80,35,27,2,28,70,36,4,91,28,27,4,1,34,18,3,164,24,0,34,90,96,0,33,0,34,154,96,34,104,146,10,138,64,128,24,2,34 2 POKE#728,154,96,1,49,16,41,244,209,1,34,90,96,16,189 10 OUT1,1:OUT2,1 20 N=USR(#700,0):?BIN$(N,16):CONT

マシン語は一度メモリに書き込んでおけばOKなので、メインプログラムを広々使っていろいろつくれますね!

BASICとマシン語の動作速度の違いが分かる動画がこちら!

IchigoJamでスーファミコントローラを読む(BASICとマシン語でSPI)

スーファミコントローラ接続、真の狙いは、FM音源モジュールYMF825Boardと合わせた楽器づくり!

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