森田和郎さんとループアンロールとスタックポインタによる画面クリアとか

公開:2014-04-06 07:40
更新:2017-07-29 13:17
カテゴリ:ハードウェア

そういえば森田和郎さんって今どうしているんだろうと思ってWikipediaを見たらお亡くなりになっていてびっくりした。57歳とはまだ若いのに。。

もちろん森田和郎さんと直接面識があるわけではないが、私にとってすごく影響を受けた人のひとりであることは間違いない。

昔「テクノポリス」という雑誌があり、1980~1986年ごろまでは硬派な記事が内容の半分くらいを占めていた。その後硬派な記事はなくなり読まなくなってしまったが。その中で森田さんがZ80マシン語講座なる記事を書いていた。内容は当時遅いと言われていたPC88でアセンブラを使って如何に高速に処理を行うかという内容であった。その中でよく覚えているのは高速画面クリアルーチンである。

PC88のN-Basicの画面消去処理は目で見えるほど遅くこれを如何にアセンブラを使って速くするかというものであった。内容は「ループ・アンロール」と「スタック・ポインタによる画面クリア」というテクニックであった。

ループ・アンロールは、ループ命令を省略したり、ループ命令を実行する回数を減らすために、ループ内に記述している命令を複数回展開するテクニックである。例えば


for(int i = 0;i < 10;++i)
{
  func();
}

というようなループ処理をループ・アンロールすると


  func();
  func();
  func();
  func();
  func();
  func();
  func();
  func();
  func();
  func();

こうなる。現代のCPUではキャッシュ機構が備わっているので逆に過度のループ・アンロールは処理速度の低下を招くので必ずしも最適化テクニックとは呼べないのであるが、キャッシュ機構のなかったZ80ではこの手法が処理速度向上に有効であった。だがメモリ容量が少ない(ユーザーが使えるメモリは最大32Kbyte程度)ので過度なループ・アンロールは使えない。

画面クリアはビデオメモリのすべてに0を代入する処理である。これはループ処理となるのでループ・アンロールが有効である。さらに通常の代入命令では遅いしコードサイズも増えるので、森田さんはスタックポインタ操作のためのPUSH命令を使ってコードサイズを抑えつつ高速に画面クリアする方法を編み出した。ふつう画面クリアコードを書くとこんな感じになる。PC88はRGB3プレーンあり16KB×3プレーンをクリアする必要があるがそのあたりは端折る。

LD BC,4000H
LD DE,C000H
XOR A
LBL: LD (DE),A ; 7 クロック DEC BC ; 4 JRNZ LBL ; 7 or 12

これをPUSH命令を使って書き直すとこんな感じになる。

DI
LD (MEM),SP 
LD SP,FFFFH
LD BC,2000H
LD DE,0
LBL:
PUSH DE  ; 11
DEC BC   ; 4
JRNZ LBL ; 7 or 12
LD SP,(MEM)
EI

PUSH命令を使うと2バイト単位でクリアできるため、ループ回数が半分になり1バイトあたりの必要クロック数が減少(18クロック→11クロック)する。これをさらにループアンロールするのである。

DI
LD (MEM),SP 
LD SP,FFFFH
LD BC,200H
LD DE,0
LBL:
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
PUSH DE  ; 11
DEC BC   ; 4
JRNZ LBL ; 7 or 12
LD SP,(MEM)
EI

最適化するとループ内の総クロック数は最初は294,917クロックであったものが、最適化後は95,749クロックとなり3倍程度の高速化となる。私はこの記事を読んで「最適化」というものを知ったのである。

このような記事は当時でも珍しかったと思うし、こういうテクニックを惜しげもなく披露する森田さんの人間性に感心したものであった。

このようなテクニックとビデオ・メモリのプレーンとパレット機能により、当時PCでは無理といわれていた縦スクロールシューティングゲームにチャレンジしたのが森田さんである。作品は「アルフォス」をという名前で実際に発売された。

このなめらかなスクロールは驚異的である。おそらくビデオ・プレーン+パレットの重ね合わせのほかに部分書き換えとかを使って最適化しているのではないかと思う。私が持っていたX1では実際に「ゼビウス」が発売されたが、スクロールはPCGを使った4ドット単位のものでカクカクしており、とてもこのアルフォスのスクロールの滑らかさには及ばない。画面の綺麗さではX1には及ばないけれども。

たしか電波新聞社の「マイコン」でこの移植版ゼビウスで使われているテクニックの解説記事がコード付きであったかと思うけれども、そこでもループ・アンロールのテクニックはふんだんに使われていた。でもビデオ・メモリがI/O空間にマップされているので使用できるZ80の命令に限りがありグラフィックに対する最適化の幅がPC88に比べて狭かったように思うので、ビデオ・メモリのスクロールはX1では難しいと思っていた。でもそれを実現した方がいたのは驚いたが。

解説記事:http://homepage3.nifty.com/ae85fcmxs/02-info-retro01.html

このビデオ・メモリのプレーンとパレット機能によるスクロール画面の重ね合わせテクニックはその後いろいろなゲームで使われている。ザナドゥとかもそうである。

このスクロールに対する森田さんのこだわりは相当なもので、とうとう8色カラーでスクロールするゲームを作ってしまった。それがリグラスというゲームであった。

もし森田さんがいなかったら遊べるレベルのパフォーマンスのアクションゲームはPC88では出てこなかったかもしれないね。