見出し画像

【リ】ORANGE pico をリセットするコード

#クリエイターフェス 3日目、テーマは「リ」である。

ORANGE pico をいじっていて、実行するとリセットがかかるプログラムをいくつか見つけた。
そこで、今回はこれらのリセットを行うプログラムを紹介する。
今回は、Ver 1.06 (ver() = 106) を対象とする。


リセットを行うプログラム

rnd

print rnd(0)
?rnd(0)

rnd 関数は、ランダムな値を返す関数である。
公式のコマンド一覧には

ランダムな値を返します。 rnd(数値式)

ORANGE BASIC コマンド一覧

としか書かれておらず、数値式の意味は書かれていない。
実験をすると、正の整数を渡すと0以上その数未満の値が返ると推測できた。
そして、0を渡したところ、リセットがかかった。
-1 を渡した場合は、1187274473 や -1978214028 など、様々な値が返るようである。

? は print コマンドの省略形である。
短く、リセットがかけやすいコードである。

sprite

sprite 1,200,50,999,0
sprite 1,200,50,9191,0

sprite コマンドは、スプライトの表示・移動・反転・非表示を行うコマンドである。
左から4番目 (1-origin) の引数はパターン番号であり、公式のコマンド一覧では以下の説明になっている。

パターン番号は1000~1133を指定します。パターン番号に負の値を設定すると、メモリー配列のアドレスから始まるパターンを読み込みます。(-8000を指定すると、8000番地から始まるユーザー設定パターンになります。)

ORANGE BASIC コマンド一覧

この範囲外の値を指定してみると、小さい側は範囲を 1 だけ外れた 999 でリセットがかかった。
大きい側はしばらくはリセットはかからず、エラーにもならずに適当な絵が表示された。
9190 を指定したときはリセットはかからず、9191 を指定するとリセットがかかった。

配列アクセス

10 dim a(1)
20 print a(-1000000)

まず配列を確保し、大きな負の添字にアクセスする。
大きな正の添字へのアクセスは Subscript out of range エラーになったが、大きな負の添字へのアクセスはエラーにならず、適当な値が帰ってきた。
さらに、起動直後の状態で添字を色々変えて実験を行った結果、-27852 ではリセットがかからず、-27853 ではリセットがかかった。
このしきい値は配列の確保状況で変わる可能性があるため、-1000000 などの余裕をもった値を指定した方がより確実にリセットをかけることができるだろう。

gput

gput 0,0,720,0,0

gput コマンドは、メモリー配列のデータに基づく正方形パターンを描画するコマンドである。
左から3番目 (1-origin) の引数は幅 (ピクセル数) であり、8の倍数でなければならない。
アドレスを0に設定して実験を行った結果、幅 712 ではリセットがかからず、720 ではリセットがかかった。

gget

gget 0,0,448,0

gget コマンドは、グラフィック画面内の指定した正方形領域に描画されている内容をメモリー配列に取得するコマンドである。
左から3番目 (1-origin) の引数は幅 (ピクセル数) であり、8の倍数でなければならない。
アドレスを0に設定して実験を行った結果、幅 328 を指定すると表示されている文字の上の部分が一部切れた。
幅を増やすと文字が切れる量が増え、352 で画面が真っ暗になった。
これは表示だけの変化のようで、入力したプログラムの実行はできるようである。
幅 440 でも同様に暗転し、幅 448 に設定するとリセットがかかった。

以下は、gget コマンドの実行後画面に表示される文字の一部が切れた様子である。

gget 0,0,328,0 の実行後の様子
gget 0,0,336,0 の実行後の様子
gget 0,0,344,0 の実行後の様子

play

play "T0R"

play コマンドは、文字列またはメモリー配列で指定したMMLを演奏するコマンドである。
テンポに 0 を指定し、音符 (休符) を再生させると、リセットがかかった。
音符 (休符) なしの play "T0" では、リセットはかからなかった。

uart

uart 1,0,0

uart コマンドは、UART通信のモードやボーレートを設定するコマンドである。
ボーレート (左から3番目 (1-origin)) を 0 に設定すると、リセットがかかった。

lpt

lpt 1,0

lpt コマンドは、使用するプリンタの設定を行うコマンドである。
左から2番目 (1-origin) の引数はボーレートであり、0 を指定するとリセットがかかった。

フリーズさせるプログラム

今度は、リセットには至らないが、処理が停止し、電源の入れ直しやMCLRピンへのLOWの入力などによるリセットを行わないと復帰できそうな状態になるプログラムを紹介する。

adc

print adc(1)

adc 関数は、指定したポートの電圧を読み取る関数である。
公式のコマンド一覧では

使用前に一度ioctrl文でアナログモードにしておく必要があります。

ORANGE BASIC コマンド一覧

と書かれており、これを無視して ioctrl 文の実行前に (たとえば起動直後に) adc 関数を使用したところ、フリーズしてしまった。
UARTからのCtrl+CやEscの入力、PS/2キーボードからのEscキーの入力を行っても反応しなかった。

pause

pause &H7FFFFFFF

pause コマンドは、指定した時間 (ミリ秒) の間待つコマンドである。
このコマンドで待っている間は、UARTからのCtrl+CやEscの入力、PS/2キーボードからのEscキーの入力により待ちをキャンセルすることはできないようである。
このコマンドで32ビット符号付き整数の最大値を指定することで、約25日間待たせることができると考えられる。
約25日後には復帰するかもしれないが、どうしても保存したい大事なプログラムやデータを保存していなかった、などの事情がなければ諦めてリセットするのが賢明だろう。

beep

beep 0,&H7FFFFFFF

beep コマンドは、指定した音階の音を指定した時間 (ミリ秒) 鳴らすコマンドである。
pause コマンドと同様に、UARTからのCtrl+CやEscの入力、PS/2キーボードからのEscキーの入力によるキャンセルはできないようである。
よって、pause コマンドと同様に、32ビット符号付き整数の最大値を指定することで、リセットしたり電源を切ったりしない限り約25日間音を鳴らし続けさせることができると考えられる。

play

play "T1L1[[[[[[[[RRRRRR]]]]]]]][[[[[[[[RRRRRR]]]]]]]][[[[[[[[RRRRRR]]]]]]]][[[[[[[[RRRRRR]]]]]]]][[[[[[[[RRRRRR]]]]]]]][[[[[[[[RRRRRR]]]]]]]][[[[[[[[RRRRRR]]]]]]]][[[[[[[[RRRRRR]]]]]]]][[[[[[[[RRRRRR]]]]]]]][[[[[[[[RRRRRR]]]]]]]]"

play コマンドは、文字列またはメモリー配列で指定したMMLを演奏するコマンドである。
[] を用いると指定の範囲を2回繰り返しさせることができ、実験の結果8重までネストできるようである。
まず、テンポを1bpm、デフォルトの音符を全音符に設定し、音符をたくさん並べることで、再生時間を稼ぐことができる。
今回のコマンドの場合、全休符が 6×256×10=15360 個配置され、約17時間分となる。
そして、この play コマンドも、UARTからのCtrl+CやEscの入力、PS/2キーボードからのEscキーの入力によるキャンセルはできないようである。
pause コマンドや beep コマンドの約25日間に比べたら実現できる停止時間は短いが、諦めてリセットしようと思うには十分な時間だろう。

まとめ

今回発見したリセットを行うプログラムは、入力の十分な検証を行っていないため、入力によってはゼロ除算や範囲外のメモリへのアクセスを起こしてしまうのであると考えられる。
コマンドによるリセットは有用な場面もあると考えられるが、プログラムのバグなどにより意図せずに行ってしまうと編集中のプログラムの消失などの被害に繋がる。
実行速度は多少犠牲になるかもしれないが、しっかりと入力の検証を行い、不正な入力でもリセットがかからないようにしていただきたい。


この記事が気に入ったらサポートをしてみませんか?