IchigoJam Advent Calendar 2019 - Day 12
C言語 Advent Calendar 2019 - Day 12

ふうせん🎈 Fu-sen. です。

さて、次は IchigoJam で C 言語をする事にしましょう!

IchigoJam

今年 IchigoJam は誕生 5 周年。

IchigoJam S

そして、メイン OS である IchigoJam BASIC は
2019年12月6日に IchigoJam 1.4.1 が公開されました。
1.4 系の初リリースになります。

IchigoJam S

これにいろいろ新機能が付いたのですが、
その一つに API が搭載された、というのがあります。
今らしく API と記載しますが、BIOS コール とか
ファンクションコール とか記載した方が分かる人には分かるでしょうか?

元々 IchigoJam BASIC では POKE で書き込んで、
USR でマシン語を実行する事はできたのですが、
この API 搭載により、幅が広がったのです。

でも、自分にはどうも ARM のマシン語がピンとこない。😫
困っていたら、こんな物が出てきまして……

C language for IchigoJam!!
……そう IchigoJam で C 言語による開発環境が公開されたのです。
これならできるかも、やってみましょう!!


C 言語を行うために必要なもの

次が必要になります。

ビルド方法によっては他も必要ですが、今回はこれだけあれば OK です。👌
Qiita は開発者の溜まり場なので、
Windows を使っていても、自然と make は何かで使える状態になっているかもしれません。
WinGW とか、Chocolatey とか、MSYS2 とか、……


IchigoJam で「はじめの一歩」といえば……

さて、通常プログラミングではじめの一歩は Hello World なのですが、
IchigoJam BASIC では L チカなのです。

10 LED 1
20 WAIT 60
30 LED 0
40 WAIT 60
50 GOTO 10

BASIC に触れていなくても何となく行っている事が分かるのではないでしょうか?
LED を点灯→1 秒待つ→LED を消灯→1 秒待つ→先頭(10)へ移動する
この繰り返しです。

このまま C 言語にすれば良いんですよね。💻カタカタ…

でも、他の C 言語のようにはいかず。IchigoJam BASIC の容量が小さいんですね。
そのためヘッダファイルは独自に作られた std15.h を使用します。
次が用意されています。

  • uint32_t rnd(uint32_t n)
    0 以上・n 未満の乱数を返します。
  • uint32_t sin(uint32_t n)
    n 度の sin 値を 256 倍で返します。
    cos が存在しませんが、90 度ずらした値が cos になります。
  • void putc(uint32_t n)
    n のキャラクター 1 文字を出力します。
    キャラクターコード、または ‘文字’ として具体的な文字を出力可能です。
  • void putnum(uint32_t n)
    符号付き 16 ビットの数値 n を出力します。
  • void putstr(const char* p)
    ポインタ p にある文字列を表示します。
    キャラクターコード 0 までが文字列として有効です。
  • uint32_t inkey()
    入力されたコードを返します。BASIC の INKEY に同じです。
  • void cls()
    画面をクリアします。BASIC の CLS に同じです。
  • void locate(uint32_t x, uint32_t y)
    カーソルの位置を x,y へ移動します。BASIC の LOCATE に同じです。
  • uint32_t scr(uint32_t x, uint32_t y)
    座標 x,y にあるキャラクターのコードを返します。BASIC の SCR に同じです。
  • void pset(uint32_t x, uint32_t y)
    座標 z,y に仮想グラフィックの点を置きます。BASIC の PSET に同じです。
  • void scroll(uint32_t n)
    1 文字分スクロールします。n の値は BASIC の SCROLL に同じです。
  • void wait(uint32_t n)
    n/60 秒ウェイトを入れます。n=60 で約 1 秒です。BASIC の WAIT に同じです。
  • void out(uint32_t x, uint32_t y)
    ポート OUTx に値 y を設定します。BASIC の OUT x,y に同じです。
  • uint32_t in()
    IN ポートの値を得ます。BASIC の IN() に同じです。
  • void pwm(uint32_t x, uint32_t y, uint32_t z)
    アナログ出力を行います。BASIC の PWM に同じです。
  • uint32_t ana(uint32_t n)
    ポート INn のアナログ入力を得ます。BASIC の ANA に同じです。
  • void uputc(uint32_t n)
    シリアルへ送出を行います。
  • void memclear(uint8_t* dst, int len)
    番地 dst から長さ len バイトを 0 クリアします。
  • void memcpy(uint8_t* dst, const uint8_t* src, int len)
    番地 src から番地 dst へ len バイトコピーします。BASIC の COPY に同じです。
  • uint32_t flash1(uint32_t cmd, uint32_t startsector, uint32_t endsector)
    uint32_t flash2(uint32_t cmd, uint8_t* src, uint8_t* dst, uint32_t len)
    フォント・キーボード配列を変更するための API として使われています。
  • void ws_led(uint32_t countrepeat, const uint8_t* data, uint32_t gpiomask)
    フルカラー LED WS2812B の状態を変化します。BASIC の WS.LED 相当です。
    gpiomask には出力ポートとして次が使用できます。
    GPIO_OUT1・GPIO_OUT2・GPIO_OUT3・GPIO_OUT4・GPIO_LED
  • void enable_irq()
    割り込みを許可します。ビデオ画面上は表示になります。
  • void disable_irq()
    割り込みを禁止します。ビデオ画面上は非表示になります。

……以上です。……はい、これしかありません 😆😫😲

それでも十分に C 言語へ置き換えできます。

#include <std15.h>

__attribute__ ((section(".main")))
int main(int param, int ram, int rom, int (*divfunc)()) {
  while(1)
  {
    out(7, 1);
    wait(60);

    if (inkey() == 27){
      break;
    }

    out(7, 0);
    wait(60);

    if (inkey() == 27){
      break;
    }
  }
}

LED という API は用意されていないのですが、
LED 1 と OUT 7,1、LED 0 と OUT 7,0 が同じ命令です。
out は API に存在していますので、out に置き換えます。

あとは無限ループ状態を while(1) にしていますが、
マシン語ではプログラム中断ができなくなるので、
inkey() による Esc キー(=コード 27)によって
ループから脱出するようにしています。

ではビルドを行いますが……
c4ij には Mac と Windows の BIN2BAS があるのですが、
Mac 向けで Makefile が書いてあります。
だから ./bin2bas だと Mac の実行ファイルを実行してしまうんですね。
Windows の場合は c4ij(-master) 下のファイル bin2bas を削除するか、
Makefile の ./bin2bas を ./bin2bas.exe に変更します。

Makefile の BIN2BAS 部分

ではシェルを起動します。
自分は Windows 10 なので、コマンド プロンプト か PowerShell なのですが、
これらでは動作に問題があるため、Git Bash が良いようです。
Qiita 使いなら GitHub とか使ってますよね? Git は当然インストールしていますよね?
そうであれば、エクスローラのファイルがない空白部分を右クリックで
Git Bash Here が出てきます。

エクスローラの右クリック

では、c4ij のフォルダ部分で Git Bash を起動し、make します。

make poke

ビルド結果

POKE だけの BASIC プログラムが最終的に出力されれば成功です。
でも途中に警告が出ているかもしれないので、よく見てみて下さいね。

最終的に完成したマシン語コードは BASIC の POKE のみですので、
末尾に USR を付けて実行します。

10 POKE#700,112,181,216,38,214,37,202,36,51,136,1,33,7,32,152,71,43,136,60,32,152,71,35,136,152,71,27,40,10,208,51,136
20 POKE#720,0,33,7,32,152,71,43,136,60,32,152,71,35,136,152,71,27,40,232,209,0,32,112,189
30 U=USR(#700)

では、IchigoJam に転送して……BASIC と同じ実行で OK です。

RUN

光って

消えて

LED が点滅しています! 成功しました~~~!! 👏パチパチ…


でも、やっぱり Hello World

でも個人的にはやっぱり Hello World も出してみたい!
std15.hを調べてみると文字列を出力する putstr があるのですが、
putstr("Hello World\n"); ではうまくいかなかったのです。😭
どうやら、ソースにある文字列からはダメそう。

ならば、仮想 RAM 上に文字列を置いて、これを表示させてみれば?
こんなコードにしました。

#include <std15.h>

__attribute__ ((section(".main")))
int main(int param, int ram, int rom, int (*divfunc)()) {
  putstr((uint8_t*)(ram + 0x0f00));
}

仮想 RAM の #F00 以降を API で表示します。
ここはプログラム領域内(#C00~#FFF)ですが、頭 #C00 から入るので、
後ろの #F00 以降は空いています。ここを文字列のデータとして使おうという作戦です。

マシン語プログラムは #700 からに転送、
文字列は #F00 から転送で、putstr の仕様から末尾は 0 で終わらせる必要があります。
更に補足する事があれば、IchigoJam BASIC は 10 が改行ってところでしょうか。
この状態で #700 から実行です。

10 POKE#700,240,35,27,1,200,24,200,35,16,181,27,136,152,71,0,32,16,189
20 POKE#F00,72,101,108,108,111,32,87,111,114,108,100,10,0
30 U=USR(#700)

これで上手くいくかな? いざ実行!

RUN

Hello World 出力成功!

やった~~~! 成功しました~~~!! 👏パチパチ…


C 言語で一番最初に作ったもの

でも、これはこの記事のために新たに作ったもので、
c4ij ではじめて作ったのは、風船 というプログラムです。

10 CLS:CLV:CLP
20 X=RND(31)
30 LOCATE X,23:PRINT CHR$(232)
40 WAIT 7
50 LOCATE X,23:PRINT CHR$(242);
60 GOTO 20

🎈🎈🎈

ふうせん🎈 Fu-sen. の代表的 IchigoJam プログラムです。🎈😍←風船大好き

#include <std15.h>

__attribute__ ((section(".main")))
int main(int param, int ram, int rom, int (*divfunc)()) {
  cls();

  for (;;) {
    int x = rnd(31);

    locate(x, 23);
    putc(232);
    putc(10);

    if( inkey() != -1 ) break;

    wait(7);

    locate(x, 23);
    putc(242);
  }

  return 0;
}

#700 は PCG 部分で、風船のキャラクターを変えてしまうため、
配列の領域 #800 からにしてあります。
Makefile の BIN2BAS を変更する必要があります。

#BIN2BAS = ./bin2bas.exe # default 0x700
BIN2BAS = ./bin2bas.exe --startaddress 2048 # 0x800 for expcg
10 'Balloons C-Language
20 POKE #800,248,181,204,35,27,136,152,71,192,39,206,38,59,136,31,32
30 POKE #810,152,71,196,36,23,33,51,136,5,0,152,71,35,136,232,32
40 POKE #820,152,71,35,136,10,32,152,71,202,35,27,136,152,71,67,28
50 POKE #830,11,209,214,35,8,48,27,136,152,71,51,136,40,0,23,33
60 POKE #840,152,71,35,136,242,32,152,71,224,231,0,32,248,189
70 CLP:U=USR(#800,0)

こんな感じに IchigoJam で C 言語を使用できる状態になりました。
BASIC では速度が遅い、でもマシン語で作るのは……という時は
C 言語を試してみて下さい。


IchigoJam Advent Calendar 2019

IchigoJam Advent Calendar 2019 | Qiita


C言語 Advent Calendar 2019

C言語 Advent Calendar 2019 | Qiita