デグレファクトリー

未来の技術で高度なバグを埋め込むソフトウェア製作所

Script700, Script700 SE は、保存しただけでは演奏できない SPC を可能な限り演奏させるようにする SPC の拡張規格です。

ほとんどの曲は SPC700 (サウンド CPU) の処理だけで演奏を行っていますが、ごく一部の曲では 65C816 (メイン CPU) とデータをやりとりしているものがあり、その場合は SPC700 の動作だけでは演奏できません。

そこで、この SPC700 と 65C816 の間で行われるデータ交換の作業を実機と同じように行うことで、そのような特殊な SPC でも演奏可能にするため、Script700 が考案されました。

改良版 SNESAPU.DLL は、41568k 氏が立案された Script700 規格と、木下氏が立案された Script700 SE 規格のコマンドと構文に互換性があり、独自拡張の命令を加えた Script700 互換機能を搭載しています。

この資料では Script700 互換機能で対応している Script700 コマンドの仕様と記述方法などについて説明しています。

独自の Script700 動作エンジンを使用しているため、同じ Script700 コマンドでも、他のプレイヤーと仕様や動作が異なることがあります。

Script700 互換機能に搭載されているすべてのコマンドに対してのサポートをデグレファクトリーで行っております。 本家立案者の方へのご質問はご遠慮ください。

Script700 はテキストベースのスクリプト言語です。

SPC ファイルとは別に Script700 のファイルを作成して SPC ファイルと同じフォルダ内に置くことで、プレイヤー側がそれを読み取り Script700 が機能します。

SNES SPC700 Player では、以下の優先順位に従って Script700 ファイルを探します。

  1. (SPC ファイル名).700

  2. (SPC ファイル名).7se

  3. 65816.700

  4. 65816.7se

例えば、sample.spc ファイルに対しての Script700 ファイルは sample.700 として保存します。

Script700 のファイルには、SPC700 とデータをやりとりするための手順 (プログラム) を記述します。

以下に、定期的 (16,384 クロック経過ごと) にポート 0 の値を 1 ずつ加算する例を示します。

    m   0   w0      ; work[0] に出力ポート 0 の値を代入
:0  w   16384       ; 16,384 クロック待機        ←────┐
    a   #1  w0      ; work[0] に 1 を加算                  │
    m   w0  0       ; 入力ポート 0 に work[0] をセット     │
    bra 0           ; 無条件でラベル :0 へ移動   ─────┘

Script700 が正常に機能しているかは、表示機能のあるプレイヤー側で確認してください。

SNES SPC700 Player の場合、[設定] - [情報表示] - [Script700 デバッグ] を選択 → ウィンドウ左下の「UsedSize」が 000000 以外 で表示されていれば、Script700 が正しく認識されていることを示します。

正しく認識されていない場合、ファイル名が間違っていないか、ファイルの記述内容が正しいか確認してください。

Script700 互換機能で扱う Script700 ファイルは、以下の 3 つの領域で構成されます。

  1. スクリプト領域

    SPC700 にデータを送る、受け取る、計算するなどといったプログラムを記述する場所です。

    Script700 では「スクリプトゾーン」、Script700 SE では「スタンダードコマンド領域」に相当します。

  2. 拡張コマンド領域

    DSP の処理に割り込みを行い、制御を変更します。

    具体的には、特定の音を消す、音色を変更する、音程を変更することができます。

    Script700 では「拡張コマンドゾーン」、Script700 SE では「スタートアップコマンド領域」に相当します。

  3. データ領域

    スクリプト領域で使用したいデータ (数値) が比較的大量にある場合、ここにまとめてデータを記述することができます。

    16 進数の数値を文字列として記述します。 この領域のみ、ファイルの最後まで続きます。

    Script700 では p コマンドで読み込める外部ファイルに相当します。

各領域は e コマンドによって区切られます。

m   #0  0           ┐
e                   │スクリプト領域
                    ┘
m   20              ┐
e                   │拡張コマンド領域
                    ┘
0007CBA380AD4E52    ┐
79A3C4E7BB524042    │データ領域
                    ┘

データ領域を除き、基本的に最初はコマンド、続いてコマンドに対するパラメータを、1 つ以上の半角スペース、または、タブ文字で区切って記述します。

《コマンド》  《パラメータ1》  《パラメータ2》 ...

コマンド、パラメータ、データ領域ともに、大文字・小文字の区別はありません。

Script700 互換機能では、パラメータの数値指定は 10 進数と 16 進数の両方を表記できます。 16 進数の場合は、先頭に 0x または $ を付けてください。

#0xFF   #$FF

複数のコマンドを記述する場合は、改行 (CR, LF, CRLF のいずれか) で区切ります。

《コマンド1》  [《コマンド1のパラメータ》 ... ]
《コマンド2》  [《コマンド2のパラメータ》 ... ]

改行コードを使わず、複数のコマンドを続けて記述することもできます。

《コマンド1》  [《コマンド1のパラメータ》 ... ]  《コマンド2》  [《コマンド2のパラメータ》 ... ]

bxx コマンドのジャンプ先となる場所を指定します。

:[LABEL]

パラメータ

  1. [LABEL]

    ラベル番号。 0~1023 の数字を記述します。

    このラベル番号はデータ領域と共有です。 重複指定しないよう注意してください。

指定したクロック数 (2,048 kHz) だけ Script700 の動作を停止させます。 ただし、処理高速化のため、Script700 互換機能では、待機時間の精度は 1/32 です。

Script700 が有効の場合、Script700 の動作を停止させている間だけ SPC700, DSP などのエミュレーション動作を行います。 したがって、w コマンドを使用せずに無限ループ処理を実装すると、演奏が停止しますので注意してください。

特定のポートの入出力があるまで待機する場合は、wi, wo コマンドが便利です。

w  [TIME]

パラメータ

  1. [TIME]

    待機時間。 パラメータグループ 3 から選択して記述します。

指定したパラメータ [SRC] の値を、パラメータ [DEST] にコピーします。

m  [SRC]  [DEST]

パラメータ

  1. [SRC]

    コピー元。 パラメータグループ 1 から選択して記述します。

  2. [DEST]

    コピー先。 パラメータグループ 2 から選択して記述します。

指定したパラメータ [CMP1], [CMP2] の値を記憶しておき、後で bxx コマンドの条件分岐や動的ポインタ機能で使用します。

bxx コマンドや動的ポインタを使用する直前で記述してください。

c  [CMP1]  [CMP2]

パラメータ

  1. [CMP1]

    比較値 1。 パラメータグループ 1 から選択して記述します。

  2. [CMP2]

    比較値 2。 パラメータグループ 1 から選択して記述します。

指定したパラメータ [SRC/DEST] の値を、パラメータ [VAL] で演算し、結果を [SRC/DEST] にコピーします。

a  [VAL]  [SRC/DEST]          ; DEST = SRC + VAL
s  [VAL]  [SRC/DEST]          ; DEST = SRC - VAL
u  [VAL]  [SRC/DEST]          ; DEST = SRC × VAL
d  [VAL]  [SRC/DEST]          ; DEST = SRC ÷ VAL (符号考慮あり)

パラメータ

  1. [VAL]

    演算に使用する値。 パラメータグループ 1 から選択して記述します。

  2. [SRC/DEST]

    演算の元となる値、かつ、演算結果のコピー先。 パラメータグループ 2 から選択して記述します。

指定したパラメータ [SRC/DEST] の値を、パラメータ [OP] で指定された演算方法でパラメータ [VAL] で演算し、結果を [SRC/DEST] にコピーします。

否定演算のみ、[SRC] の否定結果を [DEST] にコピーします。

n  [VAL]  +  [SRC/DEST]       ; DEST = SRC + VAL
n  [VAL]  -  [SRC/DEST]       ; DEST = SRC - VAL
n  [VAL]  *  [SRC/DEST]       ; DEST = SRC × VAL
n  [VAL]  /  [SRC/DEST]       ; DEST = SRC ÷ VAL (符号考慮あり)
n  [VAL]  \  [SRC/DEST]       ; DEST = SRC ÷ VAL (符号考慮なし)
n  [VAL]  %  [SRC/DEST]       ; DEST = SRC MOD VAL (余りを取得。 符号考慮あり)
n  [VAL]  $  [SRC/DEST]       ; DEST = SRC MOD VAL (余りを取得。 符号考慮なし)
n  [VAL]  &  [SRC/DEST]       ; DEST = SRC AND VAL (論理積)
n  [VAL]  |  [SRC/DEST]       ; DEST = SRC OR VAL (論理和)
n  [VAL]  ^  [SRC/DEST]       ; DEST = SRC XOR VAL (排他的論理和)
n  [VAL]  <  [SRC/DEST]       ; DEST = SRC << VAL (左シフト)
n  [VAL]  _  [SRC/DEST]       ; DEST = SRC >> VAL (右シフト, 符号考慮あり)
n  [VAL]  >  [SRC/DEST]       ; DEST = SRC >> VAL (右シフト, 符号考慮なし)
n  [SRC]  !  [DEST]           ; DEST = NOT SRC (否定)

パラメータ

  1. [VAL] / [SRC]

    演算に使用する値。 パラメータグループ 1 から選択して記述します。

  2. [OP]

    演算オペレーション。 指定可能なオペレーションは上記の一覧を参照。

  3. [SRC/DEST] / [DEST]

    演算の元となる値、かつ、演算結果のコピー先。 パラメータグループ 2 から選択して記述します。

直前で実行された c コマンドで記憶された条件値を比較して、比較結果が条件に一致する場合、パラメータ [GOTO] に指定されたラベルへジャンプします。

bra  (#)[LABEL],w[WORK]       ; 無条件でジャンプ
beq  (#)[LABEL],w[WORK]       ; [CMP1] = [CMP2] ならジャンプ
bne  (#)[LABEL],w[WORK]       ; [CMP1] ≠ [CMP2] ならジャンプ
bge  (#)[LABEL],w[WORK]       ; [CMP1] ≦ [CMP2] (符号考慮あり) ならジャンプ
ble  (#)[LABEL],w[WORK]       ; [CMP1] ≧ [CMP2] (符号考慮あり) ならジャンプ
bgt  (#)[LABEL],w[WORK]       ; [CMP1] < [CMP2] (符号考慮あり) ならジャンプ
blt  (#)[LABEL],w[WORK]       ; [CMP1] > [CMP2] (符号考慮あり) ならジャンプ
bcc  (#)[LABEL],w[WORK]       ; [CMP1] ≦ [CMP2] (符号考慮なし) ならジャンプ
blo  (#)[LABEL],w[WORK]       ; [CMP1] ≧ [CMP2] (符号考慮なし) ならジャンプ
bhi  (#)[LABEL],w[WORK]       ; [CMP1] < [CMP2] (符号考慮なし) ならジャンプ
bcs  (#)[LABEL],w[WORK]       ; [CMP1] > [CMP2] (符号考慮なし) ならジャンプ

パラメータ (以下のいずれか)

※ v2.15.2 以降 (r コマンドのみ v2.12.0 以降) で使用可能

最後に bxx コマンドが実行された場所へジャンプして、その次のコマンドから動作を再開します (最大 63 ステップ)。

これにより、特定のプログラムを異なる場所から呼び出すサブルーチンを記述することができます。

r

初期状態では bxx コマンドが実行されるたびに戻り先が記憶されますが、r0 コマンドで戻り先の記憶を停止させることができます。

これにより、サブルーチン内の繰り返し処理で、戻り先が上書きされてしまうことを防止できます。

r0

戻り先の記憶を再開する場合は r1 コマンドを記述します。

r1

なお、r コマンドで直前のジャンプに戻った場合、自動的に r1 コマンドが実行され、戻り先の記憶が再開されます。

いずれのコマンドも、パラメータはありません。

f0 コマンドが実行されてから入力ポートに設定された値をすべて反映します。

入力ポートへの反映は i1, i2, i3, i0 の順に行い、最後に出力ポート o0 と入力ポート i0 の値が同じになるまで待機します。 この動作により、演奏中に動的なポート書き込みを要求される場合においてコード量を削減することができ、かつ、パラレルポート経由による SHVC-SOUND や G.I.M.I.C 接続時にはデータ転送を高速化します。

待機したクロック数 (2,048 kHz) は [CMP1] に格納されます。 m #? w0c #? w0 コマンドで結果を代入したり別の値と比較したりすることができます。

f

初期状態では入力ポートへの書き込みは即時反映されますが、f0 コマンドで入力ポートへの値の書き込みをキャッシュし、即時反映を行わなくします。

同じ入力ポートへの書き込みは上書きされます (2 回以上書き込みは行われません)。

f0

入力ポート書き込みの即時反映を再開する場合は f1 コマンドを記述します。

f1

なお、f コマンドで入力ポートへの書き込みを反映した場合、自動的に f1 コマンドが実行され、入力ポート書き込みの即時反映が再開されます。

いずれのコマンドも、パラメータはありません。

※ v2.19.0 以降で使用可能

SPC700 が入出力ポートの読み書きを行うまで待機します。

パラレルポート経由による SHVC-SOUND や G.I.M.I.C 接続時は、割り込みをサポートしていないため、動作しません。

wi コマンドは入力ポートの値を読み取るまで、wo コマンドは出力ポートに値を書き込むまで Script700 の動作を停止させます。 この動作により、SPC700 がポートを読み書きした直後に Script700 の動作を再開させることができ、遅延を可能な限り削減できます。

待機したクロック数 (2,048 kHz) は [CMP1] に格納されます。 m #? w0c #? w0 コマンドで結果を代入したり別の値と比較したりすることができます。

wi  [PORT]
wo  [PORT]

パラメータ

  1. [PORT]

    ポート番号 (0~3)。 パラメータグループ 3 から選択して記述します。

    i[PORT]o[PORT] を指定した場合は、ポートの値から 4 で割った余りを使用します。

    純粋なポート番号を指定する場合は、先頭の識別子を省略するか、固定数値を記述してください。

※ v2.19.0 以降で使用可能

SPC700 の処理が指定したプログラムカウンタに到達した場合、SPC700 と DSP の処理を停止します。

プレイヤーが対応していない場合は動作せず、コマンドが存在しない扱いとなります。

パラレルポート経由による SHVC-SOUND や G.I.M.I.C 接続時は、割り込みをサポートしていないため、動作しません。

Script700 から停止状態を復帰する方法はありません。 プレイヤー側で解除してください。 ブレイクポイントにより SPC700 の処理が停止中、仕様上 Script700 の動作も停止します。

bp  [RAM]

パラメータ

  1. [RAM]

    SPC700 が使用する RAM の場所 (0~65535)。 パラメータグループ 3 から選択して記述します。

    r(b/w/d)[RAM] を指定した場合は、RAM から取得した値から 65536 で割った余りを使用します。

    純粋なアドレスを指定する場合は、先頭の識別子を省略するか、固定数値を記述してください。

スクリプトの実行を中止して処理を終了します。

q

パラメータはありません。

何も行いません (ウェイトもかかりません) が、コマンドとして認識します。

nop

パラメータはありません。

他の Script700 が書き込まれたテキストファイルを取り込みます。

プレイヤーが対応していない場合は動作せず、コマンドが存在しない扱いとなります。

#i のネストは動作しません。 取り込まれた (#i に指定された) ファイル側では #i は動作せず、コマンドが存在しない扱いとなります。

#i   "[FILE]"
#it  "[FILE]"

パラメータ

  1. [FILE]

    SPC ファイルからの相対パス。 ファイル名は必ず "" で囲んでください。

    なお、拡張子の制限はありません (.700/.7se 以外でも読み込みます)。

補足説明

コマンドで指定されたファイルを読み込み、コマンドが記述された場所に内容をコピーします。

この動作は Script700 の初期化時に行われ、コマンドに到達してから読み込むことはありません。 したがって、コマンドを実行する側のスクリプトから読み込まれたスクリプト内のラベルなどを使用することができます。

以下の 2 つの Script700 ファイルがあるとします。

; hogehoge.700

m  #0  w0
bra  1
#i  "append.700"
bra  1
; append.700

1:
a  #1  w0
r

これは次のように記述された 1 つの Script700 ファイルを読み込んだ場合と同じです。

; hogehoge.700

m  #0  w0
bra  1

; append.700

1:
a  #1  w0
r

bra  1

スクリプト領域を終了します。 これ以降は拡張コマンド領域となります。

Script700 と Script700 SE の両方に互換性を持たせる場合は、e → :: の順に続けて記述してください。

e
::

パラメータはありません。

スクリプト領域で使用可能なパラメータの一覧です。

パラメータグループ 1 に指定可能なパラメータは、以下の通りです。

#[NUM],i[PORT],(o)[PORT],w[WORK],r(b)[RAM],rw[RAM],rd[RAM],x[XRAM],d(b)[DATA],dw[DATA],dd[DATA],l[LABEL],
#?,i?,(o)?,w?,r(b)?,rw?,rd?,x?,d(b)?,dw?,dd?,l?

このグループでは、パラメータの先頭にある記号を省略した場合、o[PORT] と同じ扱いとなります。

パラメータグループ 2 に指定可能なパラメータは、以下の通りです。

[#[NUM]],(i)[PORT],o[PORT],w[WORK],r(b)[RAM],rw[RAM],rd[RAM],x[XRAM],d(b)[DATA],dw[DATA],dd[DATA],[l[LABEL]],
[#?],(i)?,o?,w?,r(b)?,rw?,rd?,x?,d(b)?,dw?,dd?,[l?]

このグループでは、パラメータの先頭にある記号を省略した場合、i[PORT] と同じ扱いとなります。

また、リテラル (#[NUM], #?) を指定した場合は無視されます。

パラメータグループ 3 に指定可能なパラメータは、以下の通りです。

(#)[NUM],i[PORT],o[PORT],w[WORK],r(b)[RAM],rw[RAM],rd[RAM],x[XRAM],d(b)[DATA],dw[DATA],dd[DATA],l[LABEL],
(#)?,i?,o?,w?,r(b)?,rw?,rd?,x?,d(b)?,dw?,dd?,l?

このグループでは、パラメータの先頭にある記号を省略した場合、#[NUM] と同じ扱いとなります。

改良版 SNESAPU.DLL に搭載されている Script700 互換機能の最も重要な特徴が動的ポインタ機能です。

各パラメータで、数値指定の代わりに ? を使用することで、読み込む・書き込む場所を動的に変化させることができます。

ただし、bxx コマンドでは ? を使用できません。 代わりに w[WORK] を使用できます。

; (1) [通常の指定]
m   w0  w1          ; work[1] = work[0]

; (2) [動的ポインタで指定]
c   #0  #1          ; CMP1 = 0, CMP2 = 1
m   w?  w?          ; work[CMP2] = work[CMP1]

; (1) と (2) は同じ効果です。 c コマンドのパラメータ 1 と
; パラメータ 2 に指定された値 (0 と 1) が ? と置き換わります。

; 以下のような書き方をすれば、ネスト処理が可能です。

; work[work[1]] = work[work[0]]
c   w0  w1
m   w?  w?

; work[work[work[1]]] = work[work[0]]
c   w0  w1
c   #?  w?          ; #? は [CMP1] そのままの値 (=w0)
m   w?  w?

; data[data[port[work[0]]]] = 1
c   #?  w0          ; パラメータ 1 は #? 以外でも OK ですが、
c   #?  ?           ; #? は最も処理数が少なく、消費バイト数も 1 バイトで
c   #?  dd?         ; 最も効率が良いため、推奨します。
m   #1  dd?

指定した波形番号だけ音を消します。 再度指定でミュートを解除します。

m  [SOUND],!

パラメータ

  1. [SOUND]

    波形番号。 0~255 の数字を記述します。

    !

    すべての音色番号を対象

指定した波形番号を置き換えます。

c  [SOUND],!  [CHANGE]

パラメータ

  1. [SOUND]

    変更前の波形番号。 0~255 の数字を記述します。

    !

    すべての音色番号を対象

  2. [CHANGE]

    変更後の波形番号。 0~255 の数字を記述します。

指定した波形番号の発音周波数を指定した分だけずらします。

d  [SOUND],!  [RATE]

パラメータ

  1. [SOUND]

    波形番号。 0~255 の数字を記述します。

    !

    すべての音色番号を対象

  2. [RATE]

    発音周波数の変更値。

    正の数を指定すると周波数が上がり、負の数を指定すると周波数が下がります。

指定した波形番号のボリュームを指定した分だけ増減します。

v  [SOUND],!,vl,vr,el,er,l,r,lr  [VOLUME]

パラメータ

  1. [SOUND]

    波形番号。 0~255 の数字を記述します。

    !

    すべての音色番号を対象

    vl

    マスター音量 (左) を対象

    vr

    マスター音量 (右) を対象

    el

    エコー音量 (左) を対象

    er

    エコー音量 (右) を対象

    l

    vl + el

    r

    vr + er

    lr

    l + r

  2. [VOLUME]

    音量の変更値。 分母を 65536 とした分子の数を 0 以上で記述します。

    32768 で通常の半分、131072 で通常の倍の音量になります。

他の Script700 が書き込まれたテキストファイルを取り込みます。

#i   "[FILE]"
#it  "[FILE]"

動作仕様はスクリプト領域と同じです。

拡張コマンド領域を終了します。 これ以降はデータ領域となります。

e

パラメータはありません。

l[LABEL] パラメータの元となる場所を指定します。

:[LABEL]

動作仕様はスクリプト領域と同じです。

他の Script700 が書き込まれたテキストファイルを取り込みます。

#i   "[FILE]"
#it  "[FILE]"

動作仕様はスクリプト領域と同じです。

任意のバイナリデータが書き込まれたバイナリファイルを取り込みます。

#ib  "[FILE]"

#i コマンドとの違いはバイナリとして取り扱うのみで、その他の動作仕様はスクリプト領域と同じです。

データ領域では、コマンド以外はすべてバイナリデータをテキストで記述します。

データ領域で記述された数値は、スクリプト領域で d パラメータを使用することで読み込むことができます。

6F9147EB 107A7FCD 9813E7CA 9E7F1A4E     ; 0x10 バイト
F1F131F0 EF1EB341 A674AC45 31DBBE1F     ; 0x20 バイト
46FBE1BB F11EBA11 111FEF20 CF220E9A     ; 0x30 バイト
0041BB25 30EDFFBA 01012ECE 3300EF20     ; 0x40 バイト

; なお、データ領域は空白や改行は無視されるので、以下のような書き方でも
; 問題ありません。 好みで記述してください。

6F 91 47 EB 10 7A 7F CD 98 13 E7 CA 9E 7F 1A 4E
6F9147EB107A7FCD9813E7CA9E7F1A4E
6 F 9 1 4 7 E B 1 0 7 A 7 F C D 9 8 1 3 E 7 C A 9 E 7 F 1 A 4 E

本家 Script700 の p コマンド、bt0 コマンド、p パラメータは非対応です。 データ領域を利用することで代用できますが、同じコマンドは使えません。

本家 Script700 SE の f コマンド、fc コマンドは非対応です。 代用できるコマンド、機能はありません。

改良版 SNESAPU.DLL では、Script700 コマンドを DLL 内部のコンパイラに通すことでテキストからバイナリに変換し、実行時は変換後のバイナリデータを使用します。

バイナリデータを保持するメモリ容量は 1MB の制限があるため、容量を超えるスクリプトは実行できません。

バイナリメモリの使用量は SNES SPC700 Player の Script700 デバッグ機能で確認することができます。 100000 表示 (16 進数) が最大です。

なお、バイナリ変換前のテキストスクリプトは 16MB まで読み込むことができます。

m コマンドなどでデータ領域を書き換えることができますが、シーク時の動作は保証されません。

常に変化する値を格納する場合は必ずユーザワークメモリを使用して、データ領域は読み取り専用としてください。

コマンドを解析中、対応していないコマンド、パラメータなどが見つかった場合、その行にある残りのコマンドはすべて無視され、次の行の解析に移ります。

この仕組みを利用して、コマンドの対応状況による分岐や、コメントの記述を行うことができます。

s   w0  w1  bra 1
; s コマンドに対応していない場合、"bra 1" は実行されずここに来ます。
:1
; s コマンドに対応している場合、"bra 1" が実行されてここに来ます。

; 存在しないコマンドが出てきた場合、それより右の文字は無視されるので、
; コメントを記述することができます。
n   #1  -   w0      ; work[0]--    【推奨】
n   #1  +   w0      // work[0]++
n   #4  *   w0      ' work[0] *= 4
n   #4  /   w0      # work[0] /= 4

強制的に次の行へ進むケースは以下の通りです。

何らかの理由でコマンドの実行ができない場合は処理がスキップされ、改行の有無にかかわらず次のコマンドを実行します。

d   #0  w0  bra 1
; work[0] /= 0 (0 による除算) は単純に無視され "bra 1" が実行されるため
; ここには来ません。
:1
; 必ずここにジャンプします。

無視されるケースは以下の通りです。