* OSECPU-ASKA入門 #0004
-(by [[K]], 2013.06.24)
** (0) はじめに
-以下の記事はver.0.50のWindows版を前提にしています。他の版を使っている場合は適宜読み替えてください。
--たとえば osecpu050d.zip とかのことです
~
-もくじ
--[[page0036]]: #0000
--[[page0037]]: #0001
--[[page0038]]: #0002
--[[page0039]]: #0003
--[[page0044]]: #0004
** (1) 関数の作り方、呼び出し方
-今回は予定とは違った順番なりますが、関数の話を書きます。
-与えられた二つの数字を加算して結果を返す関数を作って呼んでみたいと思います。
-まずは関数名を決めます。・・・funcにしますね。
-じゃああとは成り行きで作ってみます。
#include "osecpu_ask.h"
#define L_func LOCAL(0)
LOCALLABELS(1);
#define func(_r, a, b) R30=a; R31=b; CALL(L_func); _r=R30
// main
do {
func(R00, 2, 3);
}
beginFunc(L_func);
do {
int32s a:R30, b:R31, r:R30;
r = a + b;
}
endFunc();
-これを普通に実行しても何をやっているかよくわからないので、以下のように verbose:1 を付けてアプリを実行してみてください。
promt>osecpu app0051.ose verbose:1
--このようにすると、実行後に、R00~R03の値を16進数で表示させることができます。
--ちゃんと5になっていることが確認できます!
~
-さて、それでは一つずつ説明していきます。
-まず do { ... } ですが、これの実体は1度だけ実行するfor文です。それは結局こんなのを書かなくても同じことなのですが、これがあれば変数宣言がスコープの外に出てしまう心配がありません。
--C言語なら単に { ... } と書くところですよね。ASKAはおバカなのでまだそれができないのです。どうもすみません。毎度ですが、おもいやりと優しさでお願いします。
-関数を作るときは、"L_"を頭につけた定数を#defineする必要があります。こういうのも本当は自動でやって隠してくれたら分かりやすいのですが、現状はASKAがおバカで・・・以下略。
-そして#defineの内容はLOCAL(0)とかLOCAL(1)とか、そういうものを使います。番号はシリアルナンバーみたいなもので、まあ適当でいいのですが、あまり大きな数字は指定しないでください。同じ番号を二度指定してはいけません。0以上の整数でお願いします。
-LOCALLABELS(?);は、LOCAL(?)で付けた番号の最大値+1をASKAに教えてやるための構文です。これがないとASKAは内部でラベル番号をうまく管理できなくなってしまいます。
-さて次はこれです:
#define func(_r, a, b) R30=a; R31=b; CALL(L_func); _r=R30
-これは、関数呼び出しをかっこよく見せるための#defineです。
--OSECPUでは引数はR30~R3Bを使って渡します。そして結果をR30~R3Bを使って返します。
--これに逆らってもいいのですが、その場合はいろいろと面倒になるかもしれません。
--註:C言語などとは違って、複数の値を返せます。これはちょっと面白いですよね。
-関数funcの中身ですが、この中ではR30とR31しか使っていません。しかし、この中で他のレジスタを自由に使うことができます。
-そしてR00~R1Fに関しては、いろいろ使って適当な値を代入してしまったとしても、呼び出し元に影響を与えることはありません。安心して使ってください。
** (2) 1桁の数字を表示できる関数の例
#include "osecpu_ask.h"
#define L_putDec LOCAL(0)
LOCALLABELS(1);
#define putDec(i) R30=i; CALL(L_putDec)
// main
do {
int32s i:R00;
for (i = 0; i != 10; i++) {
putDec(i);
}
}
beginFunc(L_putDec);
do {
int32s i:R30;
junkApi_putchar(i + '0');
i += '0';
junkApi_putchar(i);
}
endFunc();
-もはやあまり説明の必要はないと思いますが、そういえば junkApi_putchar() は新出ですね。
-これは一文字表示関数です。
-ここでの関数の例は、引数はとるけど値は返さないというタイプの例にもなっています。
** (3) 4桁の数字を表示できる関数の例
#include "osecpu_ask.h"
#define L_putDec LOCAL(0)
LOCALLABELS(1);
#define putDec(i) R30=i; CALL(L_putDec)
// main
do {
int32s i:R00;
for (i = 0; i != 10000; i++) {
putDec(i);
junkApi_putConstString(' ');
}
}
beginFunc(L_putDec);
do {
int32s i:R00;
i = R30; // できるだけR00を使いたいのでいったん引き取る.
// R00は高速に演算できるレジスタです.
junkApi_putchar(i / 1000 + '0'); i %= 1000;
junkApi_putchar(i / 100 + '0'); i %= 100;
junkApi_putchar(i / 10 + '0'); i %= 10;
junkApi_putchar(i + '0');
}
endFunc();
-0が0000と表示されるとか、12が0012と表示されてしまうのが少々不自然ではありますが、printf("%04d", i);の結果だと思えば、まあそんなものですよね。
-関数の中でR00を使っていますが、mainの動作には影響していません(確認)。
** (4) %dみたいな数字を表示できる関数の例
#include "osecpu_ask.h"
#define L_putDec LOCAL(0)
LOCALLABELS(1);
#define putDec(i) R30=i; CALL(L_putDec)
// main
do {
int32s i:R00;
for (i = 0; i != 1000; i++) {
putDec(i);
junkApi_putConstString(' ');
}
}
beginFunc(L_putDec);
do {
int32s i:R00, flag:R01, j:R02, ii:R03;
i = R30;
flag = 0;
if (i < 0) {
junkApi_putConstString('-');
i *= -1;
}
for (j = 1000000000; j >= 10; j /= 10) {
ii = i / j;
i %= j;
if (!(flag == 0 & ii == 0)) {
flag = 1;
junkApi_putchar(ii + '0');
ii += '0';
junkApi_putchar(ii);
}
}
junkApi_putchar(i + '0');
i += '0';
junkApi_putchar(i);
}
endFunc();
-これなら結構普通ですね。
--まあでも(3)みたいな表示もゲームなどでは重宝したりしますが。
** つづく
-[[page0045]]につづく
* こめんと欄
#comment