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

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

2017/09/24 23:55:00
#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まとめて埋めて高速化 (32byte 1356cycle)

R2=9 R2=R2<<8 R1=R1+R2 R2=R0 R2=R2<<8 R2=R2+R0 R2=R2<<8 R2=R2+R0 R2=R2<<8 R2=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を使って高速化 (42byte 381cycle)

PUSH {LR,R4,R5,R6,R7} R2=9 R2=R2<<8 R1=R1+R2 R2=R0 R2=R2<<8 R2=R2+R0 R2=R2<<8 R2=R2+R0 R2=R2<<8 R2=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. マシン語、ループ展開 (92byte 251cycle、転送部分220cycle)

PUSH {LR,R4,R5,R6,R7} R2=9 R2=R2<<8 R1=R1+R2 R2=R0 R2=R2<<8 R2=R2+R0 R2=R2<<8 R2=R2+R0 R2=R2<<8 R2=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編 (90byte 250cycle、転送部分214cycle)
IchigoJam-FANにて、PUSHを使った更に速い方法が発見されました!(Thanks Amanagi-san)
転送部分のみで214cycle、方法11と仕様を合わせても90byte/250cycleと、2byte減って1cycle/21nsec高速!

PUSH {LR,R4-R7} R2=#C R2=R2<<8 R1=R1+R2 R2=R0 R2=R2<<8 R2=R2+R0 R2=R2<<8 R2=R2+R0 R2=R2<<8 R2=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の方法

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

2017/09/17 23:55:00
#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 CALL @RDVRM E=A A>>=1 A|=E CALL @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 23:55:00
#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 23:55:00
#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と合わせた楽器づくり!

YMF825で楽器づくり「FM音源キーボード」マシン語で高速SPI、IchigoJamでまなぶ ARMマシン語入門その9

2017/08/15 23:55:00
#IchigoJam #music #asm 

FM音源チップ、YMF825、IchigoJam BASICで鳴ったので、次は楽器づくり!
問題は、BASICでは遅いこと。音を鳴らすための2byteのSPI送信5回に、0.73秒もかかっているので、ゆっくりチャイムを鳴らすくらいしか使えません。
* SPIとは、クロックに合わせて信号を送受信するシンプルな通信方式 (SPI on Wikipedia)


FM音源キーボード on IchigoJam デモ動画

おや!?小気味よく鳴ってますね!これがマシン語パワーです!
復習を兼ねて、OUTポートをマシン語で使う実験をしてみます。(参考、マシン語でLEDを光らせよう

LEDが接続されている端子は、PIO1_5、アドレスとしてはPIO1のベースアドレス#50010000に、2進数の`10000000(= 1&<&<(5+2))を加えた場所に書き込めばOK!

@LED1 R3=#50 ' R3=#50010000 R3=R3<<8 R3=R3+1 R3=R3<<16 R2=`10000000 R3=R3+R2 R2=R2>>2 [R3]L=R2 ' GPIO1_5 <- 1 RET

asm15アセンブラを使うか、ハンドアセンブルして、できたマシン語コードを動かしてマシン語でLED1!

POKE#700,80,35,27,2,91,28,27,4,128,34,155,24,146,8,26,96,112,71 ?USR(#700,0)

次はBASICでつくったSPI送信をマシン語化します。

@SPIW:OUT4,0:FORI=0TO15:OUT2,0:OUT3,N>>(15-I)&1:OUT2,1:NEXT:OUT4,1:RTN

まずは分解!

OUT4,0 FORI=0TO15 F=N>>(15-I)&1 OUT2,0:OUT3,F OUT2,1 NEXT OUT4,1 RTN

ひとつずつマシン語化すれば、できあがり!

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

アセンブラasm15を使って2byte送信SPIマシン語バイナリができました!
送信したい16bitの数値を、USRコマンドの第二パラメータにいれるだけ!(マシン語にはレジスタR0として渡される)

POKE#700,80,35,27,2,91,28,27,4,0,34,26,98,1,33,201,3,0,34,8,66,0,208,4,50,154,97,2,50,154,97,73,8,246,209,8,34,26,98,112,71

準備ができたので、早速楽器づくり、まずはIchigoJamのボタンを使った単音楽器で実験!
前回のYMF825の初期化プログラムを動かし、音がなる状態にしてからNEW、次のプログラムを入力。
*マシン語化した初期化プログラム、後述します

1 'FM BTN 10 A=#700:POKEA,80,35,27,2,91,28,27,4,0,34,26,98,1,33,201,3,0,34,8,66,0,208,4,50,154,97,2,50,154,97,73,8,246,209,8,34,26,98,112,71 20 T=#1465 30 IF !BTN() CONT 40 U=USR(A,#0B00):U=USR(A,#0C54):U=USR(A,#0D00+T>>8):U=USR(A,#0E00+T&#FF):U=USR(A,#0F40) 50 IF BTN() CONT 60 U=USR(A,#0F00) 70 GOTO 30

ボタンを押したら鳴り始め、離したたらキーオフ!
反応速度もいい感じ!いろんなボタンをつなげて遊べそうですね!
*時間を測ってみると、1回の送信でTICKで1、約1/60秒、100倍速い!

次は、キーボードで楽器キーボードをつくってみます。
キーボードのZXCがドレミ、SDなどで半音にも対応します。

1 'FM KEYBOARD 10 A=#700:POKEA,80,35,27,2,91,28,27,4,0,34,26,98,1,33,201,3,0,34,8,66,0,208,4,50,154,97,2,50,154,97,73,8,246,209,8,34,26,98,112,71 100 FORI=0TO15:U=USR(A,#0B00+I):U=USR(A,#0F30):U=USR(A,#1071):U=USR(A,#1101):U=USR(A,#1208):U=USR(A,#1300):U=USR(A,#0C54):NEXT 200 LET[0],357,378,401,425,450,477,505,535,567,601,637,674 210 M="ZSXDCVGBHNJM,L." 220 K=INKEY():IF!KCONT 230 N=0 240 IF PEEK(M+N)=K GOTO300 250 N=N+1:IF N=15 GOTO 220 260 GOTO240 300 ?N:T=[N%12]:B=4+N/12:T=T&#7F+T>>7<<11+B<<8 310 U=USR(A,#0B00+N):U=USR(A,#0F00): 320 U=USR(A,#0D00+T>>8):U=USR(A,#0E00+T&#FF):U=USR(A,#0F40) 330 GOTO 220

キーは離されたタイミングが取得できないので、キーが押された時に、キーオフ(310行)してから、キーオン(320行)するようにしています。

ついでに、初期化コードもマシン語で高速化!

1 'FM INIT 10 OUT1,0:WAIT1:OUT4,1:OUT1,1 13 A=#700:POKEA,80,35,27,2,91,28,27,4,0,34,26,98,1,33,201,3,0,34,8,66,0,208,4,50,154,97,2,50,154,97,73,8,246,209,8,34,26,98,112,71 14 S=#728:POKES,80,35,27,2,91,28,27,4,128,33,0,34,8,66,0,208,4,50,154,97,2,50,154,97,73,8,246,209,112,71 15 'INIT 20 LET[0],#1D01,#020E,-1,#0001,#0100,#1AA3,-1,#1A00,-30,#0204,-1,#0204,-1,#0200,#197C,#1B3F,#1400,#0301,#08F6,-21,#0800,#09FB,#0A00,#01740,#1800,0 22 FORJ=0TO99:N=[J]:IF!N J=99:GOTO26 24 IF N<0 WAIT -N ELSE U=USR(A,N) 26 NEXT 30 'SETCH 31 LET[0],#0F30,#1071,#1101,#1208,#1300 32 FORJ=0TO4:U=USR(A,[J]):NEXT 40 'SETTONE 41 U=USR(A,#08F6):WAIT1:U=USR(A,#0800) 42 LET[0],7,#81,1,#43,0,#E7,#FF,#9D,0,#10,#40,#20,#33,#E2,#73,0,#50,#40,#10,#41,#D3,#5B,0,#10,#41,#20,#63,#D4,2,1,#10,#40,#80,3,#81,#80 43 M=36 50 @SPIAW:OUT4,0:FORK=0TOM-1:U=USR(S,[K]):NEXT:OUT4,1

配列をSPIで送信する @SPIAW の内部、8bitのSPI送信もマシン語化しました(アドレス#728=S)

@SPI1W R3=#50 ' R3=#50010000 R3=R3<<8 R3=R3+1 R3=R3<16 R1=#80 @LOOP R2=0 R0&R1 'F=N>>(7-I)&1 IF 0 goto @SKIP R2+=4 @SKIP [R3+`110]L=R2 ' OUT2,0:OUT3,F R2+=2 [R3+`110]L=R2 ' OUT2,1 R1=R1>>1 IF !0 goto @LOOP @END RET

FM音源音色エディタもマシン語化!

1 'FM EDITOR 5 CLS 10 ?" 1 BO 3:";[40] 20 ?" 2 LFO 3:";[41] 30 ?" 3 ALG 7:";[42] 40 LET[80],"SR 15","XOF 1","KSR 1","RR 15","DR 15","AR 15","SL 15","TL 63","KSL 3","EAM 1","DAM 3","EVB 1","DVB 3","MUL15","DT 7","WS 31","FB 7" 50 FORJ=0TO1:FORI=0TO16:LCJ*15,3+I:?DEC$(4+I+J*17,2);" ";STR$([80+I]);":";[43+I+J*17]:NEXT:NEXT 60 INPUT"ID :",I 70 INPUT"VAL:",V:[39+I]=V 75 GSB@TESTTONE 80 GOTO 5 100 @TESTTONE 110 LET[0],7,#81,[40],[41]<<6+[42] 120 FORJ=0TO1:P=43+J*17 130 LET[4+J*7],[P]<<4+[P+1]<<3+[P+2],[P+3]<<4+[P+4],[P+5]<<4+[P+6],[P+7]<<2+[P+8],[P+9]<<4+[P+10]<<5+[P+11]+[P+12]<<1,[P+13]<<4+[P+14],[P+15]<<3+[P+16] 132 NEXT 141 U=USR(A,#08F6):WAIT1:U=USR(A,#0800) 143 M=36:GSB@SPIAW 150 T=#1465 160 U=USR(A,#0F00):U=USR(A,#0B00):U=USR(A,#0C54):U=USR(A,#0D00+T>>8):U=USR(A,#0E00+T&#FF):U=USR(A,#0F40) 180 RTN 1010 @SPIAW:OUT4,0:FORK=0TOM-1:U=USR(S,[K]):NEXT:OUT4,1:RTN

YMF825初期化コード実行後に動かし、いい音色ができたら、ボタン楽器や、キーボード楽器で演奏しよう!

Enjoy to create original musical instruments with FM!
オリジナル楽器作りを楽しもう!

links
- YMF825 x IchigoJamで鳴らすFM音源チャイム、BASICでつくるYMF825Board用FM音源エディタ (ハードウェア準備、接続方法)
- YMF825Board GitHubPage へようこそ!
- ヤマハ製YMF825使用FM音源LSIモジュール: 組立キット 秋月電子通商 電子部品 ネット通販
- ヤマハFM音源LSI YMF825搭載モジュール YMF825Board - SWITCH-SCIENCE

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

アセンブラを使って楽しよう 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. アセンブラを使って楽しよう
9. マシン語で高速SPI
10. マシン語を制するもの時間を制す
11. 画面をイチゴで埋め尽くす12の方法

ARMマシン語でつくる32bit大きな数計算ライブラリ / 32bit Integer Library on IchigoJam

2017/05/08 23:55:00
#IchigoJam #asm #english 

メモリが4KBしかないIchigoJam、節約のため変数はすべて16bit。低い限界を楽しめる設計です。 もちろんプログラミングでその限界は超えられます。今回はマシン語を使って超える方法の紹介。
How to exceed the 16bit limit of IchigoJam!

@CALC32 PUSH {LR,R4,R5,R6} R6=8 R6=R6<<8 R6=R1+R6 R5=#F<<2 R4=R0 R0=R4>>2 R0&=R5 R0=[R6+R0]L R1=R4<<2 R1&=R5 R1=[R6+R1]L R2=R4>>12 R2-0 ' plus IF !0 GOTO @SKIP1 R0=R0+R1 GOTO @END @SKIP1 R2-1 ' minus IF !0 GOTO @SKIP2 R0=R0-R1 GOTO @END @SKIP2 R2-2 ' multi IF !0 GOTO @SKIP3 R0*=R1 GOTO @END @SKIP3 R2-3 ' division IF !0 GOTO @SKIP4 PUSH {R4} GOSUB R3 POP {R4} GOTO @END @SKIP4 R2-4 ' division(remain) IF !0 GOTO @SKIP5 PUSH {R4} GOSUB R3 POP {R4} R0=R1 ' GOTO @END @SKIP5 @END R4=R4>>6 R4&=R5 [R6+R4]L=R0 POP {LR,R4,R5,R6}

"32bit calc library on asm15 (CALC32)"

マシン語呼び出しのパラメーターで、計算種類、配列位置で、結果格納、計算する数2つを指定します。32bit = 4byte なので、配列は[0]と[1]など、2つずつ使います。コンパイルした結果がこちら。

10 POKE#700,112,181,8,38,54,2,142,25,60,37,4,70,160,8,40,64,48,88,161,0,41,64,113,88,34,11,0,42,1,209,64,24,19,224,1,42,1,209,64,26 20 POKE#728,15,224,2,42,1,209,72,67,11,224,3,42,3,209,16,180,152,71,16,188,5,224,4,42,3,209,16,180,152,71,16,188,8,70,164,9,44,64,48,81 30 POKE#750,112,189 RUN

例えば、1234*5678 (=7006652)を計算するには、このように使います。

[0]=1234:[2]=5678 U=USR(#700,#2201):'[4]=[0]*[1] [6]=10000 ?DEC$(USR(#700,#3523),4)DEC$(USR(#700,#4423),4) 7006652

結果の表示上、9999万9999まで表示します。マイナスの数はどうなるか、やってみましょう! links
- IchigoJam
- マシン語でつくるプログラマブル学習リモコン
- レゴテクニックシリーズをIchigoJamと赤外線LEDで制御する(マシン語) / Control Lego Technic by IchigoJam and IR LED
- はじめてのマシン語 - IchigoJamではじめるARMマシン語その1

DMM 4K対応、プログラマブル学習リモコン by IchigoJam / Programmable IR receiver and sender

2017/05/07 23:55:00
#IchigoJam #maker #asm #english 

DMM.make 4Kディスプレイの入力切り替えが面倒なので、IchigoJamで学習リモコンを作ってみました。
I made programmable IR sender by IchigoJam.


ハードウェア設定 (hardware setup)
IR LED - OUT1
IR Reciever - IN1 (赤外線受光モジュール)

10 POKE#700,112,181,114,182,8,34,18,2,138,24,0,40,54,208,80,35,27,3,1,51,27,3,1,36,228,4,202,38,0,33,0,240,40,248,1,49,33,66,30,209 20 POKE#728,29,104,0,45,247,209,36,9,0,32,0,33,0,240,29,248,1,49,33,66,19,209,29,104,0,45,247,208,17,82,2,48,176,66,12,208,0,33,0,240 30 POKE#750,16,248,73,28,33,66,6,209,29,104,0,45,247,209,17,82,2,48,176,66,229,209,0,33,17,82,2,48,64,8,98,182,112,189,100,37,210,53,1,61 40 POKE#778,253,209,112,71,80,35,27,2,1,51,27,4,4,51,1,36,0,38,17,90,0,41,234,208,28,96,0,240,21,248,30,96,0,240,18,248,1,57,247,209 50 POKE#7A0,2,48,17,90,0,41,222,208,0,0,0,0,0,240,8,248,0,0,0,0,0,240,4,248,1,57,245,209,2,48,228,231,154,37,1,61,253,209,112,71 200 IF BTN()=0 CONT 210 A=#BF00 220 B=#E11E:GSB300:N=USR(#700,0):WAIT60 230 B=#E21D:GSB300:N=USR(#700,0):WAIT30 240 B=#BE41:GSB300:N=USR(#700,0) 250 GOTO200 300 LET[0],346,169 310 FORI=0TO15:[2+I*2]=25:[3+I*2]=18+43*(1<<I&A!=0):NEXT 320 FORI=0TO15:[34+I*2]=25:[35+I*2]=18+43*(1<<I&B!=0):NEXT 330 LET[66],25,0:RTN

配列に送信用のデータを作成(300行)し、マシン語(10-50行)で38kHzの赤外線LED点滅信号として送信。ボタンが押されたら、あらかじめ調べたコードを順番に送信。これでワンボタンで入力切り替えができます!アンプ連動やセンサーで自動でONとかにも!
It makes IR data on the array (line 300) and send via IR LED blinking. I did it just 1 pressing when switch the input!

こちらがリモコンコード受信用のプログラムです。上のプログラムを一度実行したあと、一度 NEW でプログラムを消して、下記を入れることで、送信&受信テストができます。
This is the IR code receiver program. You can get the code after run the abobe program, NEW command and enter this program.

100 INPUT"1:SEND 2:RECV ?",N 110 IF N=1 N=USR(#700,0):GOTO 100 120 N=USR(#700,1) 130 FOR I=0 TO N-1 STEP 2:?[I];" ";[I+1];" ";:NEXT:? 140 N=0:FORI=0TO15:N=N|([3+I*2]>37)<<I:NEXT:?HEX$(N) 150 N=0:FORI=0TO15:N=N|([35+I*2]>37)<<I:NEXT:?HEX$(N) 160 GOTO 100

家のリモコンで動くもの全部、IchigoJam BASIC プログラミング可能に!
You can program your all devices have a IR receiver by IchigoJam BASIC!

links
- IchigoJam
- レゴテクニックシリーズをIchigoJamと赤外線LEDで制御する(マシン語) / Control Lego Technic by IchigoJam and IR LED
- はじめてのマシン語 - IchigoJamではじめるARMマシン語その1

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

日本人が創ったCPUの歴史、MacのCPU Intel 64 マシン語はじめのいっぽ

2016/08/19 23:55:00
#asm 

今使ってるMacBook ProのCPUは、Intel Core i5 2.7GHz コア数:2、64bitの汎用レジスタが15個ある64bit CPU、Intel 64というマシン語が使える。

Macのコンソールに定番の「Hello World!」と表示させるマシン語のプログラムは、このようなアセンブリ言語を使って作る。

SECTION .data MESSAGE db `Hello World!\n` MESSAGE_LEN equ $-MESSAGE SECTION .text global start start: mov rax, 0x2000004 ; syscall 4: write mov rdi, 1 ; fd = stdout mov rsi, MESSAGE ; buffer mov rdx, MESSAGE_LEN ; size syscall mov rax, 0x2000001 ; syscall 1: exit mov rdi, 0 ; retcode syscall

アセンブリ言語をアセンブラというソフトを使ってマシン語を生成することをアセンブルと呼ぶ。

nasm-2.12.02/nasm -f macho64 hello.s ld -o hello hello.o ./hello

アセンブラは、NASMというオープンソースなソフトを使う。
Macに入っているバージョンは 0.98.40 と古くIntel 64に非対応だったので、最新版 2.12.02 をダウンロード。

画面の表示は、raxなどレジスタに画面表示用のコマンド番号や、データのメモリの位置、文字数をセットしてシステムコール(syscall)というOS側に処理を依頼することで実現。プログラムの終了もシステムコールを使ってOSに伝える。

CPUは高速に2進数のbitをあれこれいじる機械。いじり方によって足し算になったり掛け算になったり、比較したり、次に実行するプログラムを変えたりする。ARMマシン語入門で、机と表現したレジスタと、本棚をイメージすると近いRAM(メモリ)を使う設計自体は、世界初の商用マイクロプロセッサ Intel 4004(開発は、日本人、嶋正利さん!)から全く変わっていない。

Intel 4004は、45命令、レジスタは4bit、計算用のAレジスタとR0-R15の16レジスタ
Intel 8008は、68命令、レジスタは8bit、A,B,C,D,E,H,LとZ80とほぼおなじ構成
Intel 8086では、レジスタが16bitになり、AX,BX,CX,DX,SP,BP,SI,DIという構成(SI/DIはセグメント)

Intel 64はその直系で、レジスタが64bit、互換性を持ちつつ拡張された RAX,RBX,RCX,RDX,RSP,RBP,RSI,RDI にR8からR15の8レジスタが追加されている。SIMD命令などで命令数は数百(〜千オーバーかも?)と膨大だが、レジスタでいじってメモリなどに書くという基本は変わらない。

IchigoJamで使っているCortex-M0は、55命令、レジスタは32bit、R0-R15という4004に似たシンプルな設計。最新の64bit版ARM、ARM64もその延長線上にある。

エスケープシーケンスとシステムコールを使うとコンソールの画面で8色の色が使える。


座標をエスケープシーケンスで渡すためにはレジスタを10進数に変換する必要があるので、一度マシン語でつくってみると楽しい。楽しみを奪うといけないので、ソースは公開はまた後日。

PCでブートするIchigoJam PCをベースに、64bitをフルに使う特殊OSを作ってみるのもありかもしれない。

参考リンク
- Intel® 64 and IA-32 Architectures Software Developer Manuals (大元、Intelの資料)
- x64 アセンブリーの概要 | iSUS
- Tips IA32(x86)命令一覧 (32bit版だかイメージはつかめる)
- よく使うASM命令ベスト100位に説明つけてみた - おなかすいたWiki!

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