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

アセンブラを使って楽しよう IchigoJamでまなぶ ARMマシン語入門その8 / Let's Use Assembler! Learning ARM Machine Language on IchigoJam

2017/05/15 23:55:00
#ARM #asm #IchigoJam 

ちょっと大きなプログラムをマシン語で作っていくとき、変更するたびに、ジャンプ先のアドレスを計算するのが面倒になってきます。そんな時便利なのがアセンブラというツール。いままでやってきた対応する命令を2進数コードにする作業(ハンドアセンブル)を自動化します。
"Assembler" is useful tool to make pretty big program written in machine language. Numbers of address to jump are calculated automatically!

マシン語入門その6でつくった、画面に大きく文字を表示するプログラムをアセンブラを使ってやってみました。
For example, BIG SCREEN program on part 6.

10 POKE#700,240,181,148,70,0,38,15,24,9,35,27,2,201,24,184,93,192,0,18,24,0,36,19,93,128,37,24,70,40,64,0,208,1,32,8,112,1,49,109,8 20 POKE#728,247,209,24,49,1,52,8,44,241,209,24,57,3,32,48,64,3,40,0,208,224,57,98,70,1,54,12,46,227,209,240,189 RUN OK A=USR(#700,"+IchigoJam+!"):WAIT120


"asm15 - ARM Cortex-M0 Assember for IchigoJam"

ふたつある同じレジスタ上の足し算は、 R1=R1+1 と R1+=1 と区別する形に変更したので注意!
Notice! I modified the code R1=R1+1 and R1+=1

やってみよう! Challenge
- 任意の場所に大きな文字を表示するプログラムをつくろう (BIG CHARs on any position)
- ハーフグラフィクスを使った文字表示プログラムをつくろう (middium chars using half graphics)

- 連載、IchigoJamではじめる、ARMマシン語入門
1. はじめてのマシン語
2. ハンドアセンブルで超速計算!
3. マシン語メモリアクセスで画面超速表示!
4. マシン語でLEDを光らせよう!
5. 楽しさ広がるマルチバイトメモリアクセスとスタック
6. マシン語使いこなしTIPS
7. カジュアルに使うインラインマシン語
8. アセンブラを使って楽しよう

How to divide on IchigoJam Assembly

2017/04/28 23:55:00
#IchigoJam #asm #ARM #english 

About the machine language on IchigoJam, you cant't find how to divide (割り算@ja) on the ARM Cortex-M0 command table. It's right. ARM Cortex-M0 has no commands of division. Instead you can use the function to divide.

IchigoJam BASIC command "USR" pass an address of function to divide as the register R3 after IchigoJam 1.2b31. (IchigoJam-FAN to download the latest version 1.2b45)

asm: R1=3 → 00100 001 [num]
asm: GOTO R3 → 010001110 [R3] 000
BASIC: PRINT 100 / 3 → 33

If you want to use the number as remainder (R1), call it!

[0]=`00100 001<<8 + 3 [1]=`1011010 100000000 [2]=`010001111 0011 000 [3]=`0100011000 001 000 [4]=`1011110 100000000 ?USR(#800,100) 1

asm: R1=3 → 00100 001 [num]
asm: PUSH {LR} → 1011010 100000000
asm: CALL R3 → 010001111 [R3] 000
asm: R0=R1 → 0100011000 [R1] [R0]
asm: POP {PC} → 1011110 100000000
BASIC: PRINT 100 % 3 → 1

Enjoy programming with the simple machine language!

links
- Cortex-M0 ARMマシン語表(抜粋)
-
はじめてのマシン語 - IchigoJamではじめるARMマシン語その1
- IchigoJam-FAN on Facebook

バーチャルマシンにディスプレイを接続、avmで動かすIchigoJamマシン語

2016/10/01 23:55:00
#IchigoJam #js #ARM #avm 

決められた手順(プログラム)通りに、ひたすら高速に計算するだけの機械、CPU。
これに手足顔をつなぐことで、ゲーム機、家電、パソコン、ロボットになります。

前回つくった、ソフトウェアによるARM Cortex-M0風CPUシミュレーション。
これに人間の顔にあたる、ディスプレイをつなげてみました。


avm with display
[RUN]ボタンをおすと、レジスタを忙しく変化させながら、健気に計算しまくる様子をのぞけます。

プログラムやデータ、計算した結果を記憶する機能を担う「メモリ」。特定の場所(アドレスと言う)を表示すると決めれば、それが顔になります。今回接続したディスプレイは、IchigoJamと同じ仕様、アドレス0から256コ分のキャラクターパターン、16進数で900から32x24の768byteが表示するキャラクターコードにしています。

メモリが潤沢にあるパソコン上の仮想コンピューターなので、6.2Mbyteをディスプレイ用のメモリにして、1920x1080のフルHD、1画素にRGB256階調(3byte)対応に改造することも可能です。(参考、IchigoJamのメモリマップ

サンプルとして設定済みのプログラムは、IchigoJamではじめるマシン語その5「大きな文字を256倍速表示」で生成したマシン語です。 コンピューターへの理解を深める、マシン語学習のお供にぜひどうぞ!(deleyが1以上の時、JavaScriptのコンソールには、実行した命令を表示します。)

VMとしては不完全なので、C言語などで開発したARMマシン語を貼り付けても「not supported op」と出てスキップされます。必要に応じて改造ください。

楽しく制するマシン語、ARMマシン語学習用VM on JavaScript

2016/09/27 23:55:00
#js #ARM #avm 

イマドキのBASICとしてIchigoJamが紹介サれている今月の「日経ソフトウェア」で見かけたマシン語の話題。 ドラゴンクエストのゲームデザイナー、堀井雄二氏はNEC PC-6001のBASICでプログラムを始め、速度を求めてZ80マシン語へ。ハンドアセンブルでマシン語プログラムを作ったそう。 「矢沢久雄のソフトウェアの基礎Q&A」では、基本情報技術者試験で使われる仮想マシン語CASLIIのススメ。 Z80ハンドアセンブルした小学生時代、CASLIIがJavaVMと似てると思った高専生時代が懐かしい。

私の一押しは、32bit CPU、ARM Cortex-M0のマシン語。IchigoJamで使っているLPC1114で使え、コンパクトで強力かつ、iPhoneなどスマホでも動きます。 (でも、本気で動かすなら64bit対応のARM64マシン語!)


連載、ARMマシン語入門と合わせて使えるシミュレーター「avm」をつくってみました。フラグなどがいい加減で、まだ表示がないので、連載その2までの対応です。

サンプルのマシン語プログラムは、10から1までをループしながら足し算するプログラム。たかだか100円ちょっとのCPUですが、54サイクル、1.12μ秒(約100万分の1秒)で計算するパワーをフルに使い切る感こそ、マシン語の醍醐味!

JavaScriptでつくったシンプルなバーチャルマシン(VM)「avm」、どうぞいろいろ改造してお使いください!
IchigoJamで学ぶARMマシン語入門」と合わせてどうぞ!

iPhoneインラインアセンブラ入門、64bit ARMマシン語はじめのいっぽ

2016/08/17 23:55:00
#ARM #swift 

IchigoJamもiPhoneも同じARMのCPU、IchigoJamでマシン語を覚えたらiPhoneでも使ってみましょう。今回の対象は、64bit化したARM64(ARMv8)対応のiPhone5s以降です。ネットや書籍での資料には32bit時代のものも混在しているので注意が必要です。(iPhone Wikipedia)。

Swiftにはインラインアセンブラ機能はまだないようなので、Objective-CでGameをテンプレートに選び、次の行を viewDidLoad の [super viedDidLoad]; の後に追加します。

__asm__ volatile ("mov x0, x0");

※__asm__ はインラインアセンブラ、volatile で最適化を停止
エミュレーター向けだとコンパイルエラーになります。(IntelがARMライセンス取得とのことなので、MacBookへのARMv8組み込みにも期待!まずはApple-Aの生産から?詳しい解説記事


iPhoneでARM64マシン語、動きました!
(3Dの飛行機はサンプルのままで、今回のアセンブラでの動作とは無関係です)

mov x0, x0 は、レジスタX0の内容をレジスタX0に入れる(つまり、ほぼ何もしない)というマシン語を生成します。やっかいなことにこのコードはMacのiPhoneエミュレーターでは動きません。iPhoneエミュレーターはARMのCPUまでは動かしてくれないようです。実機向けにコンパイルすると動きます。(ARM64では64bitになったレジスタをRではなくXで呼ぶようになった様子)

Objective-Cでの変数との足し算をやってみます。

long num = 1; __asm__ volatile ( "mov x1, #1 \n\t" "add %[n], %[n], x1 \n\t" : [n] "+r" (num) : : "x1" ); NSLog(@"res: %ld\n", n);

コンソールに結果として 2 と表示されます。mov x1,#1 でレジスタX1に1を入れ、add命令で%[n]というコンパイラ任せなレジスタX?にX1の値を加えます。IchigoJamマシン語入門では X1=1 と表記していました。

最初のコロンの後 [n] "+r" (num) で、Objective-Cの変数numを%[n]というレジスタに割り当てて、読み書き"+"するよと指定しています。

三番目のコロンの後の "x1" で、インラインアセンブラ内で X1 レジスタを使用すると宣言して、前後のプログラムと干渉しないようにコンパイラに指定します。

これで基本はOKですね!
より詳しい解説は、こちら「ARM GCC Inline Assembler Cookbook」など参照ください

せっかくなので、アセンブラならでは機能を使った便利な関数を作ってみます。

- (unsigned long)rbit:(unsigned long)n { __asm__ volatile ( "rbit %[n], %[n] \n\t" : [n] "+r" (n) ); return n; }

rbitというのは、64のbit列を反転する命令です。普通に計算すると結構手間ですが、マシン語なら1クロック、0.1nsecで計算します!(参照、Arm64(ARMv8) Assembly Programming (08) 分岐命令

iPhone(ARMv8)とIchigoJam(ARMv6-M)との比較です。

IchigoJamのCortex-M0のThumb命令とも互換性あるiPhone6sですが、浮動小数やSIMD命令など性能をフルに活かすならARM64マシン語プログラミングへのステップアップがオススメです!レジスタもたくさんあるので作るのも楽!

参考
- Arm64(ARMv8) Assembly Programming (00)(とっても詳しいRAM64解説)
- 連載、IchigoJamではじめる、ARMマシン語入門
- 連載、iPhoneゲームづくりからはじめる、Swift入門

掛け算もインクリメントも1クロック、BASICでカジュアルに使うインラインマシン語とツール紹介 - IchigoJamではじめるARMマシン語その7

2016/08/16 23:55:00
#IchigoJam #ARM 

じっくり取り組むマシン語も楽しいですが、手軽で便利なマシン語ならではの技を紹介します。

CPUには足し算、引き算、メモリアクセスなど基本的な機能の他に、CPUによってそれぞれ固有な機能があります。現代のパソコンやスマホに使われる高性能なCPUには、3Dグラフィックスや、音声、映像などの処理の高速化のために、4つの計算を同時に行うなどのSIMD命令が含まれます。ほとんどのスマホで使われているARMアーキテクチャー、Cortex-AにはNEONというSIMD機能が搭載されています。

電源が限られるモバイルにおいて、いかに無駄な電力消費を抑えつつ、サクサク軽快なアプリを提供するかが重要です。C、JavaScript、Swiftでは、CPU固有の機能を表現する方法がないので、マシン語を使って、コンピューターの性能をフルに引き出しましょう。誰かがつくった機能(ライブラリ)を使わせてもらうのもいいですが、自分でも作ってみたくもなるでしょう。(参考「iPhoneでのピクセル処理をNEON(ベクタ演算)を使って4倍高速化する」)

IchigoJamが使っている低電力CPU、LPC1114は、ARM Cortex-M0という、Cortex-Aと命令に互換性があるサブセット(一部)です。SIMD命令はありませんが、BASICやCでは扱えない特別な演算があるので、今回はそれらをカジュアルに使います。

Cortex-M0 マシン語表(抜粋)」に、特殊演算を追記しました。

※bic:ビットクリア、asr:符号付き右シフト、ror:右ローテート
※rev:byteオーダー反転、rev16:byteオーダー反転(2byteずつ)、revSH:符号付き16bitを反転32bit化
※abc:キャリー付き足し算、sbc:キャリー付き引き算

IchigoJam BASICには当てはまる演算子がないために、関数のような書き方にしていますが、これらの計算はすべて、通常の計算と同様、1サイクルで処理できます。IchigoJamの場合、48MHzで動作させているので1サイクルは約20ナノ秒で計算は終了します(iPhone6sは最大1.84GHzなので約40倍高速な0.1nsec)。

bic:指定したビット位置のみをクリアする。普通に書くと Rd = Rd & ~Rm と、2回の演算が必要。
ror:指定した数だけ右にビットシフトして、はみ出た分は上位ビットにセットする。
rev16:16bitの上位8bitと下位8bitを入れ替える(上位32bitも同様に)

I2Cで外部センサーから取得したビッグエンディアン(=最初に上位8bitがある)なデータの読み取りに便利そうな rev16 を実際使ってみます。

[0]=`1011101001 000 000 'R0=rev16(R0) [1]=#4770 ?USR(#800,1) 256 ?HEX$(USR(#800,#3412)) 1234

#4770は呼び出し元に戻るRETURNのマシン語です。(Z80でいう#C9)
同じコードをIchigoJam BASICで書くと、下記のように少し長くなるので、繰り返し使う場合に有利です。

N=#3412 ?N<<8&#FF00+N>>8

マシン語をいれておくメモリとして、PCG領域を借りて、下記のように書くこともできます。このように、別のプログラムでいろいろな便利な関数を用意しておき、メインのプログラムを呼び出すとメモリを有効に使えます。

10 POKE#700,#40,#BA,#70,#47:P=#700 20 ?HEX$(USR(P,#CDAB));HEX$(USR(P,#3412))

Cortex-M0 マシン語表(抜粋)」にサイクル数を追加しました。ほとんどの命令が1サイクルで終了することが分かります(LPC1114は掛け算も1クロック)。実行時間が正確に計算できるのもマシン語のいいところです!

ハンドアセンブルでコツをつかんだら、アドレス計算も自動でやってくれるARMアセンブラ搭載、Mac/Windows/Linux対応IchigoJam用ツール「IJUtilities」が便利です。C言語からIchigoJam BASIC用のコードを生成する「rohiniku/IchigoJam_bin2poke」の逆アセンブル機能を使った解析も勉強に便利!

ARMマシン語は、スマホでもそのまま活かせる究極の高速化テクニック。自分の書いたコードが実際どういうマシン語になるかだいたい想像できる程度には押さえておきましょう。

C言語やJavaScriptでお馴染みの「i++」という iに1足す演算子が、Swift3ではなくなってしまいます。MSXでZ80マシン語で1足す命令(INC)や1引く命令(DEC)を知っていたため、ごく自然に受け入れて今でもよく使っているだけにさみしいものがあります。Z80では1足す専用の命令、INCを使えば足し算命令ADDよりサイズが節約できました(機械語の手帳 ステート数表)。ただ、近年使われるよくARMは、1足すのも2足すのも255足すのも、速度もサイズも一緒。演算子削減の一因かもしれません。

ゲーム、スマホ、ロボット、クラウド、IoT、AIなど、奥深いプログラミングの世界も第一歩から!
福井新聞主催、PCN共催「福井県小中学生プログラミング・フェス2016」参加者募集中!

- 連載、IchigoJamではじめる、ARMマシン語入門
1. はじめてのマシン語
2. ハンドアセンブルで超速計算!
3. マシン語メモリアクセスで画面超速表示!
4. マシン語でLEDを光らせよう!
5. 楽しさ広がるマルチバイトメモリアクセスとスタック
6. マシン語使いこなしTIPS
7. カジュアルに使うインラインマシン語

ハンドアセンブルで大きな文字を256倍速表示!マシン語使いこなしTIPS - IchigoJamではじめるARMマシン語その6

2016/08/15 23:55:00
#IchigoJam #ARM 

Twitterで蘇る懐かしい記憶。
実家の本棚探ってたら小学生の頃書いたZ80の機械語のノート出てきた。」 by @AoVAさん
そう、当時の中高校生が使いこなしていたZ80マシン語は小学生の憧れ、高速ゲームを夢見て、フリーズと戦った!
※フリーズ=暴走、リセットするしかない状態、マシン語を使うとよく起きる

ということで、ARMマシン語入門、その6はちょっと実用的なプログラムをTIPSと共に紹介します。

キャラクターパターンデータを使って、1文字を8x8のテキストキャラクターを使った8倍サイズにするBASICのプログラムはこんな感じ。

12 P="BIG SCRNTEST" 15 CLT:GOSUB 100 30 WAIT 120:?TICK():END 100 FOR I=0 TO 11 110 C=PEEK(S+I) 120 FOR J=0 TO 7 122 N=PEEK(C*8+J) 125 A=#900+I&3*8+(I>>2*8+J)*32 130 FOR K=0 TO 7 140 POKE A+K,N&(1<<(7-K))<>0 150 NEXT 160 NEXT 170 NEXT 180 RETURN

32x24の画面に、8x8の文字は12文字入ります。一文字ずつCで取り出すループ、文字コード*8から8byte分あるキャラクターパターンを取り出すループと、1ビットずつ表示するループの三重ループ構造でできます。描画に242tick(約4秒)もかかってしまうので、ゲームに使うのは厳しそう・・・。

このようにマシン語でいきなり作り始める前に、BASICで考え方(アルゴリズム)が間違ってないか、実際に動かして確認するといいです。(2進数のビット演算には慣れておきましょう

では、早速マシン語で高速化します!
ARMマシン語対応表(PDF版)」を片手に、BASICの変数の代わりにレジスタを使ってつくっていきます。この時、いきなり全部つくろうとせず、ループの内部の細かい部分から順に動作を確かめながらつくるのがコツです。問題は切り分ける!

1. 画面の左上にパラメータ(R0)として渡した数を表示しよう
2. 0ならCHR$(0)そうでなければCHR$(1)を表示しよう
3. 渡したパラメータの下位8bitでパターンを表示しよう(上位bitが左上になるように)
4. キャラクターコードを渡してキャラクターパターンを表示させよう
5. キャラクターコードが12コ連続してかかれたメモリ位置(=アドレス、C言語で言うポインタ)を渡して12コ表示しよう

つくりかたですが、いきなり2進数にしてしまうと読みづらいので、読みやすいプログラム(=アセンブリ言語)で先に書いて、変換(=ハンドアセンブル)するのがおすすめです。

'BIG SCREEN PROGRAM 'R0:param, address of 12 characters 'R1:virtual memory offset(RAM) 'R2:virtual memory offset(ROM) PUSH {LR,R4,R5,R6,R7} R12=R2 'save to R12 R6=0 'offset 0-11 R7=R1+R0 'real memory address of 12 characters R3=9 R3=R3<<8 R1=R1+R3 @LOOP0 R0=[R7+R6] R0=R0<<3 R2=R2+R0 R4=0 @LOOP1 R3=[R2+R4] R5=#80 @LOOP2 R0=R3 R0&=R5 IF 0 GOTO @ELSE1 R0=1 @ELSE1 [R1]=R0 R1+=1 R5=R5>>1 IF !0 GOTO @LOOP2 R1+=24 R4+=1 R4-8 IF !0 GOTO @LOOP1 R1-=24 R0=3 R0&=R6 R0-3 IF 0 GOTO @ELSE2 R1-=224 @ELSE2 R2=R12 R6+=1 R6-12 IF !0 GOTO @LOOP0 @END POP {PC,R4,R5,R6,R7}

レジスタはR0からR3とR12以外を使う場合は、呼び出し元(この場合、IchigoJamの動き)を壊してしまう恐れがあるので、PUSH/POPを使って退避しておきます。この時LR(リンクレジスタ、戻り先のアドレスが入っている)をまとめてPUSHしておき、POPするタイミングでPC(プログラムカウンタ、現在実行中のアドレス)に戻すと、RET(=#4770)の代わりになって便利です。

今回使用したレジスタは破壊してOKなR12を含めて、R7までに収まったのでPUSH/POPは一組で済みましたが、足りなくなった場合は、適宜PUSH/POPをループ前に使いましょう。その都度、レジスタの使いみちを簡単にメモしておくと便利です。


ハンドアセンブルは、IchigoJamの2進数表記とビット演算などを使って少し楽できます。

10 [0]=`1011010 1 11110000 11 [1]=#4600+`1 0010 100 12 [2]=`00100 110<<8+0 14 [3]=`0001100 000 001 111 16 [4]=`00100 011<<8+9 18 [5]=`00000 01000 011 011 20 [6]=`0001100 001 011 001 22 [7]=`0101110 110 111 000 30 [8]=`00000 00011 000 000 40 [9]=`0001100 000 010 010 60 [10]=`00100 100<<8+0 70 [11]=`0101110 100 010 011 80 [12]=`00100 101<<8+#80 90 [13]=`0100011000 011 000 100 [14]=`0100000000 101 000 102 [15]=`11010000<<8+(2-2)&#FF 104 [16]=`00100 000<<8+1 106 [17]=`01110 00000 001 000 110 [18]=`00110 001<<8+1 120 [19]=`00001 00001 101 101 130 [20]=`11010001<<8+(-7-2)&#FF 140 [21]=`00110 001<<8+24 150 [22]=`00110 100<<8+1 160 [23]=`00101 100<<8+8 170 [24]=`11010001<<8+(-13-2)&#FF 180 [25]=`00111 001<<8+24 190 [26]=`00100 000<<8+3 200 [27]=`0100000000 110 000 205 [28]=`00101 000<<8+3 210 [29]=`11010000<<8+(2-2)&#ff 220 [30]=`00111 001<<8+(224) 225 [31]=#4600+`0 1100 010 230 [32]=`00110 110<<8+1 240 [33]=`00101 110<<8+12 250 [34]=`11010001<<8+(-27-2)&#ff 260 [35]=`1011110 1 11110000 RUN A=USR(#800,"IchigoJamASM"):WAIT120

GOTOなどのジャンプ先は、命令の数を相対的に数えます。例えば2つ先なら2、2つ戻るなら-2。その数を-2した数を5桁または11桁の2進数に変換します(例、13コ前に飛ばす場合、(-13-2)&#FF)。命令を追加、変更、削除したときにアドレスを計算し直す必要があるので注意!

PUSHとPOPの数が合わない、ループから抜け出さないなど、どこか間違った場合、保護する機能はないので、高確率でフリーズします。実行前には保存しておきましょう。 フリーズしても、リセットか電源入れ直しですぐに復帰するのがIchigoJamのいいところ!(MSX時代は、暴走時の謎のディスクアクセスに怯えました)

動作が確認できたら、BASICのプログラムに簡単に使えるように、短いコードにしておくのも便利です。(LRUNでつなげてももちろんOKです)

?"1 POKE#700,";:FOR I=0 TO 31:?PEEK(#800+i);",";:NEXT:?CHR$(8) ?"2 POKE#720,";:FOR I=0 TO 36*2-1-32:?PEEK(#820+i);",";:NEXT:?CHR$(8)

アドレスをすべて相対的に使っているため配置変更可能(=リロケータブル)です。このように#800(配列)の領域から#700のPCG領域へ移しておくと、BASICで配列が使えて便利です。

BASICと速度を比べてみましょう。

1 POKE#700,240,181,148,70,0,38,15,24,9,35,27,2,89,24,184,93,192,0,18,24,0,36,19,93,128,37,24,70,40,64,0,208 2 POKE#720,1,32,8,112,1,49,109,8,247,209,24,49,1,52,8,44,241,209,24,57,3,32,48,64,3,40,0,208,224,57,98,70,1,54,12,46,227,209,240,189 10 FOR I=0 TO 12*4-1:POKE#800+I,RND(256):NEXT 12 P="BIG SCRNTEST" 15 FOR S=#800 TO #800+12*3:IF !BTN() GOSUB 100 ELSE A=USR(#700,S) 17 NEXT 20 S=P:IF !BTN() GOSUB 100 ELSE A=USR(#700,S) 22 WAIT 10 30 GOTO 15 100 FOR I=0 TO 11 110 C=PEEK(S+I) 120 FOR J=0 TO 7 122 N=PEEK(C*8+J) 125 A=#900+I&3*8+(I>>2*8+J)*32 130 FOR K=0 TO 7 140 POKE A+K,N&(1<<(7-K))<>0 150 NEXT 160 NEXT 170 NEXT 180 RETURN

ボタンでBASICとマシン語の速度差が体感できます!マシン語だと1tick(1/60秒)かかりません!
1行と2行だけ流用すると、他のプログラムでも大きな文字表示、使えます。

作るのに手間がかかるけど、動作は高速なマシン語。
作るのは簡単・高速だけど、動作は遅いBASIC。
いろいろなプログラミング言語がある理由はここにあります。

面倒なアドレス計算や表からのピックアップを自動化したものをアセンブラといいます。

また、数式など分かりやすいプログラミング言語から、マシン語の生成してくれるソフトのことをコンパイラといって、C言語はその代表。 IchigoJam BASICは、BASIC言語のコマンドに合わせて対応するマシン語を順に呼び出すインタープリタ。 Ruby、JavaScript、Swift、Javaなど最近の言語はバーチャルマシンといって仮想的なマシンのマシン語を使ったり、適宜コンパイルしたりと、両方のいいとこ取りをしています。

マシン語が分かったら、IchigoJam BASICで実際にアセンブラやコンパイラを作って、プログラミング言語の自作にも挑戦してみてください! ARMマシン語は、Android/iPhoneでも使えます。他のマシン語も似たようなものなので、一つ使えるようになっておけば怖いものなし!(実際、小学生の頃のZ80マシン語の知識が活きました)

日本産の世界に広がるプログラミング言語、Rubyに続こう!

- 連載、IchigoJamではじめる、ARMマシン語入門
1. はじめてのマシン語
2. ハンドアセンブルで超速計算!
3. マシン語メモリアクセスで画面超速表示!
4. マシン語でLEDを光らせよう!
5. 楽しさ広がるマルチバイトメモリアクセスとスタック
6. マシン語使いこなしTIPS
7. カジュアルに使うインラインマシン語

- ARMマシン語表(PDF版)

楽しさ広がるマルチバイトメモリアクセスとスタック - IchigoJamではじめるARMマシン語その5

2016/08/11 23:55:00
#IchigoJam #ARM 

IchigoJam BASICで扱える数は、メモリ節約のため16bitの整数(-32768〜32767)としていますが、CPUは32bitのLPC1114。マシン語を使えば、プラスマイナス約21億まで使った高い精度で高速に計算ができます。

その3では1byte単位のメモリアクセスをやりましたが、ARMマシン語には、IchigoJamの変数をマシン語で扱うのに便利な2byte単位や、32bitの大きな数をそのまま読み書きできる4byte単位のメモリアクセスも用意されています。

ARMマシン語表(メモリアクセス)

※[]の後のWだと2byte単位、Lだと4byte単位で読み書き。u5/2などの表記は2で割った数を指定という意味。

これを使って、IchigoJamの変数AとBを足した値をCにいれるマシン語プログラムをつくってみます。 (R1:IchigoJam BASIC上の仮想アドレスを実アドレスに変換するオフセット)

R0=8 R0=R0<<8 R0=R0+204 R0=R1+R0 '仮想メモリ #800+204 の変数Aの実アドレス位置を計算 R2=[R0+0]W '変数Aの16bitの数をR2へ入れる R3=[R0+2]W '変数Bの16bitの数をR3へ入れる R2=R2+R3 [R0+4]W=R2 'R2を変数Cへ入れる RET

これを「マシン語表」を見ながらハンドアセンブルして、実行します

[0]=`00100 000 00001000 'R0=8 [1]=`00000 01000 000 000 'R0=R0<<8 [2]=`00110 000<<8 + 204 'R0=R0+204 [3]=`0001100 000 001 000 'R0=R1+R0 '仮想メモリ #800+204 の変数Aの位置 [4]=`10001 00000 000 010 'R2=[R0+0]2 '変数Aの16bitの数をR2へ入れる [5]=`10001 00001 000 011 'R3=[R0+2]2 '変数Bの16bitの数をR3へ入れる [6]=`0001100 011 010 010 'R2=R2+R3 [7]=`10000 00010 000 010 '[R0+4]2=R2 'R2を変数Cへ入れる [8]=#4770 'RET =HEX$(`0100011101110000) A=100 B=555 R=USR(#800,0) ?C 655

うまくいきました!

R0からR3までの4つのレジスタだけではちょっと窮屈ですね。そんなとき便利なのがスタックです。メモリに書類を積むように一端保存しておき、必要になったら上から順番にレジスタに戻します。積むことをPUSH(プッシュ)、戻すことをPOP(ポップ)と呼びます。


ARMマシン語表(スタック操作)

※ひとまず LR、PC には 0 を指定して使ってください

PUSH {R4,R5,R6,R7} と、スタックに保存しておけば、R4からR7までを思う存分に使ってもOK。RETする前に、POP {R4,R5,R6,R7} としましょう。 (R4〜R7を保存しないといけない理由

[0]=`1011010 0 00010000 'PUSH {R4} [1]=`00100 100 11111111 'R4=255 [2]=`0001100 100 000 000 'R0=R0+R4 [3]=`1011110 0 00010000 'POP {R4} [4]=#4770 'RET ?USR(#800,100) 355

全部PUSHしておいてもいいですが、1レジスタに付き4byteのメモリと約20ナノ秒(48MHzの1周期)の時間が無駄になるので、必要なだけPUSH/POPするようにしましょう。また、重ねてPUSHすることで、どんどん途中の数を保存しておくこともできます。ただし、PUSHした数とPOPした数が合わないと暴走やフリーズの原因になるので注意しましょう。

やってみよう
1. PUSHしてPOPせずにRETするとどうなるかやってみよう
2. A+B*Cを計算してDにいれるマシン語プログラムをつくってみよう
3. A+B*Cを計算して[0]にいれるマシン語プログラムが2度目には動かない原因を探ってみよう
4. A*Bの数をCとDの2つの変数に結果をいれるプログラムをつくってみよう
5. 変数X,Yの場所に4x4のキャラを表示するプログラムをつくり、BASICと速度を比べてみよう

- 連載、IchigoJamではじめる、ARMマシン語入門
1. はじめてのマシン語
2. ハンドアセンブルで超速計算!
3. マシン語メモリアクセスで画面超速表示!
4. マシン語でLEDを光らせよう!
5. 楽しさ広がるマルチバイトメモリアクセスとスタック
6. マシン語使いこなしTIPS
7. カジュアルに使うインラインマシン語

マシン語でLEDを光らせよう! - IchigoJamではじめるARMマシン語その4

2016/08/08 23:55:00
#KidsIT #IchigoJam #ARM 

やりたいことが遅くでできない時、速いCPUに変えるのは簡単ですが、その分コストアップするので製品化する際の値段に直接響きます。 IchigoJamではじめるARMマシン語、待望(?)のその4、公開です!
8ビットマイコン時代に逆戻り? アセンブリ言語が人気上昇 - ITmedia ニュース

1列に並んだLEDをすばやく振ると文字や絵が浮かび上がるものをバーサライターと呼びます(海外ではPOV=残像)。

4つのLEDをIchigoJamのOUT1〜OUT4につないで・・・

こんなプログラムを打ち込んで、振ってみましょう!(動画 on Vine

10 LET[0],`0110,`1001,`1001,`0110:N=4 20 FOR I=0 TO N:OUT[i]:OUT0:WAIT1:NEXT 30 WAIT 5 40 GOTO20

10行目のデータとデータの数(N)を変更するとパターンを変えられます。

この1列のLEDをモーターでぐるぐる回転させて、その上に文字や絵を浮かび上がらせたい場合、BASICではちょっと速度が足りないかもしれません。 そんな時、CPUパワーをフルに使えるマシン語を使います!

IchigoJamのCPU、LPC1114の説明書(ユーザーマニュアル)を開きます。(LPCマイコン情報:LPC1100 (X)L Cortex-M0搭載-低消費電力内)
LPC1114FN28とFDH28のピン配置で、OUT1〜OUT4は、PIO1_0〜PIO1_3であることがわかります。

続いて、メモリーマッピングを見るとそのピンの操作はGPIO PIO1として、#50010000にマッピングされていることがわかります。

GPIOの項目を見ると、#50010000のアドレスから書き換えたいピンをbitに変更して2bitずらしたところを足したメモリに書き込めばいいことがわかります。

つまり、OUT1〜OUT4の状態を変更するプログラムを擬似的に表すと

[#50010000+`111100]=R0

となります。

ただ、32bitのアドレスを値で指定してメモリを直接書き込む命令はないため、前回のマシン語表を見て、分解します。

R3=#50 R3=R3<<8 R3=R3+1 R3=R3<<16 R3=R3+`00111100 [R3]L=R0 RET

これをマシン語に変換します。

R3=#50 `00100 011 01010000 R3=R3<<8 `00000 01000 011 011 R3=R3+1 `00110 011 00000001 R3=R3<<16 `00000 10000 011 011 R3=R3+`00111100 `00110 011 00111100 [R3]L=R0 `01100 00000 011 000 RET `0100011101110000

できたマシン語を打ち込みます。
16bitの2進数をIchigoJamのメモリ#700から順番に書く、簡易モニターを使って打ち込んでみます。

10 A=#700 20 ?"AD:";HEX$(A) 30 INPUT N 40 ?"VAL:";HEX$(N,4) 50 POKE A,N:A=A+1 60 POKE A,N>>8:A=A+1 70 GOTO 20

できたら、呼び出してみましょう

?USR(#700,1) OK ?USR(#700,15) OK ?USR(#700,0) OK

OKと出ずにフリーズしてしまったら、それは残念ながらどこか打ち間違えて、暴走してしまったことになります。 あきらめて、本体の電源を切ってやり直しましょう。

(追記)当初、計算にレジスタR4を使っていましたが、ARMのABI(Application Binary Interface = 関数呼び出し規約)にて、破壊して使って良いレジスタはR0-R3までと分かり、R3に変更しました。(日本語解説、32ビットへの誘い

- やってみよう
マシン語でPOVをつくってみよう
LEDやOUT5,6を使ってもっと大きなPOVをつくってみよう
IN1の入力をマシン語で読み取って、モーターで回りながら上を認識させてみよう(ヒント、GPIO0を読みだすと入力になる)

- 連載、IchigoJamではじめる、ARMマシン語入門
1. はじめてのマシン語
2. ハンドアセンブルで超速計算!
3. マシン語メモリアクセスで画面超速表示!
4. マシン語でLEDを光らせよう!
5. 楽しさ広がるマルチバイトメモリアクセスとスタック
6. マシン語使いこなしTIPS
7. カジュアルに使うインラインマシン語

マシン語メモリアクセスで画面超速表示! - IchigoJamではじめるARMマシン語その3

2015/10/25 23:55:00
#IchigoJam #KidsIT #event #ARM 

ARMマシン語第三弾、超高速計算を画面表示に活かしてみましょう!
※今回以降はIchigoJamのバージョン1.1を使用します(開発版はグループのファイルからダウンロード可能

コンピューターの記憶には2種類あります。
データを保存しておく本棚と、作業用の机をイメージしてください。
本棚から必要なデータを机に出して、机の上であれこれ計算してつくったデータをまた本棚に戻したりします。

前回紹介したレジスタが机に相当します。
レジスタは一度に使える量は限られます。(ひとまず、R0〜R3の4つのみを使ってください)

もうひとつの記憶、本棚に相当するのがメモリ(RAM)です。
こどもパソコンIchigoJamは、4KB(4キロバイト=4096byte 約4千文字分)のメモリがあります。
※私のパソコンのメモリ、4GB(4ギガバイト=4,294,967,296byte 42億文字入る!)と比べて、100万倍の1!

今回、マシン語表に新たにメモリアクセスを追記しました。
これがデータが詰まった本棚からとってきたり、書き換えたりするためのマシン語です。

値 = [メモリの場所] ... メモリから値を読み出します
[メモリの場所] = 値 ... メモリを書き換えます

IchigoJamは、メモリの一部を画面に表示用に使っているので、そこを書き換えると画面を書き換えることができます。

HELP MEM MAP #000 CHAR #700 PCG #800 VAR #900 VRAM #C00 LIST #1002 KEY

HELPコマンドでメモリの位置を確認することができます。
画面用のメモリは、VRAM(ブイラム、ビデオ用のラムということ)が#900からなので、こんなBASICのプログラムを書くと、キャラクター一覧が画面上部に順番に表示されます。

FOR I=#900 TO #9FF:POKE I,I:NEXT

つらつらと書いていく様子が目に見えますね。
では、これをマシン語にしてみましょう。

IchigoJam ver 1.1 から、R0に渡されたパラメータ、R1にBASICで使うメモリの位置の実メモリ位置、R2にキャラクターマップの実メモリ位置がセットされるようになりました。 今回はR1のみを使います。

R3=9
R3=R3<<8
[R1+R3]=R3
R3=R3+1
R2=R3>>8
R2-10
IF !0 GOTO -4
RET

これをハンドアセンブル(マシン語表からひとつずつ2進数列に変換すること)します。

00100 011 00001001 ← R3=9
00000 01000 011 011 ← R3=R3<<8
0101010 011 001 011 ← [R1+R3]=R3
00110 011 00000001 ← R3+=1
00001 01000 011 010 ← R2=R3>>8
00101 010 00001010 ← R2-10
11010001 11111010 ← IF !0 GOTO -4
0100011101110000 ← RET

マシン語表を見ながら順番に書いていくだけなので簡単ですね!
* R3+=1 とは R3=R3+1 という意味です。後述の表記では3bit(0〜7)までですが、+=を使うと8bit(0〜255)まで表記できます。

GOTO命令だけがちょっと特殊なので、注意が必要です。
4つ分命令を戻りたいときは、更に-2した-6を、2進数8bit補数表現にします。

?BIN$(-4-2,8) 11111010

このように、IchigoJamで計算すると便利です。

では、マシン語をメモリに書き込んで実行してみましょう。前回はPOKE文で上のメモリマップでいう#700、キャラクターパターンの領域に書き込んでいましたが、今回は配列の領域#800を使って楽します。 上位8bitと下位8bitに分けずに、16bitそのまま書き込めるので楽です。

10 [0]=`00100 011 00001001 20 [1]=`00000 01000 011 011 30 [2]=`0101010 011 001 011 40 [3]=`00110 011 00000001 50 [4]=`00001 01000 011 010 60 [5]=`00101 010 00001010 70 [6]=`11010001 11111010 80 [7]=`0100011101110000 90 CLS:A=USR(#800,0)

実行すると一瞬にして、画面に全キャラクターコードが表示されます!

配列領域を使っているので、配列を使ったプログラムと混ぜる時には要注意です!

?BIN$(PEEK(#800),8),BIN$(PEEK(#801),8)

このように、ちゃんと入れ替わって#800からのメモリに入っていることを確認してみましょう。
(下位から順にいれる方式をリトルエンディアン、上位から入れる方式をビッグエンディアンといいます、現在リトルエンディアンが主流!)

ミッション
- 1. 画面全部をキャラクターコードで埋めてみよう
- 2. USRコマンドで渡したキャラクターコード(R0)で画面全体を埋めてみよう
- 3. 画面を市松模様で埋めるマシン語プログラムを背景に、BASICのゲームをつくってみよう

IchigoJamで使えるマシン語表(基本+1byteメモリアクセス編)

※GOTOに指定する値は、飛ばしたい差分から更に-2した数を指定する

- 連載、IchigoJamではじめる、ARMマシン語入門
1. はじめてのマシン語
2. ハンドアセンブルで超速計算!
3. マシン語メモリアクセスで画面超速表示!
4. マシン語でLEDを光らせよう!
5. 楽しさ広がるマルチバイトメモリアクセスとスタック
6. マシン語使いこなしTIPS
7. カジュアルに使うインラインマシン語

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