X1turbo Agency

X1turbo Agency ブログ

8bitコンピュータ X1turboの探求サイト

X1turbo Agency

X1/turbo 開発年表を作ってみた

X1/turbo 開発年表を作ってみた

「X1の日」を書く内にX1/turboの企画時期やどんな流れで作られたのかが気になってきました。
そこで見聞きした範囲でX1/turboの開発年表を作ってみました。

個人が見聞きした内容をまとめているだけで、
間違いもありますので、ハハ、コヤツめでスルーするか、
想い出補完に利用したり、X1/turboの戦略や時代背景を調べたり、
こんな資料があるぞと教えて頂けると助かります。

X1/turbo 開発年表 (2026/01/04)

2025年 MI68にてパネルとして用意したものに追記しています。

PDF版

考察トピックについて

年表(左)の「考察トピック」は、調べる内に出てきた考察をまとめたものです。
画面に映っている開発資料の後半に付けておいたので会場でご覧になった方もいると思います。
こちらはまとめ直して載せていこうと思います。

X1の日について

「X1の日」と称して、以下の日々達を X1/turboの勝手記念日としてアナウンスしています。

  • 8/1 X1C (CZ-801C)
  • 8/2 X1D (CZ-802C)
  • 8/3 X1Cs (CZ-803C)
  • 8/4 X1Ck (CZ-804C)
  • 8/5 X1turbo/II (CZ-85xC)
  • 8/6 X1turbo model40 (CZ-862C)
  • 8/7 X1turboIII (CZ-870C)
  • 8/8 X1turboZ/II/III(CZ-88xC)
  • 8/11,8/12 X1F (CZ-811C)
  • 8/20 X1G (CZ-820C)
  • 8/30 X1Twin (CZ-830C)
  • 10/1 X1/turbo/Zの日

X1turbo MI68 RTYPEデモ 制作解説

2025 MI68にRTYPEデモ 制作解説

RTYPEの技術解説は以前書いたものと大きくは変わってないんですよね。
作りこみは増えたんですが、システム的には以前と大きくは変更なしです。
最適化は今後の課題として、画面構成が判りにくいので構造図を載せておきます。

X1turbo RTYPE 画面構造の構成図

以前の技術解説

技術解説についてはこちらを見て頂ければと思います。

x1turbo-agency.hatenablog.jp

2025 MI68 参加まとめ

MI68 出展者ハンドブック

2025年 MI68に参加を行いました

以前展示でお邪魔した事がありましたが、今回は出展をやってみようと思い立ち、まずは申込みから開始。
展示内容は当時はまだ決めていなくて、いくつか進めていたネタが形になるかどうか検討を重ねていました。
他の出展者さんの展示物のレベルの高さから、参加をかなり迷っていたのですが、
まぁ今でもX1turboをいじってる人もいるんだなぐらいで思ってもらえればと考え直したのでした。

出展内容確定

検討の結果、最近作り進めていた「X1turbo用 New RTYPEデモ」で行く事に決定。
(なんで「New」なのかというと最近作ったからぐらいの意味)
以前のバージョンからデモ展示に必要な以下の要素を追加しました。

  • ボス
  • タイトル
  • 不具合修正
  • 処理の高速化
  • 背景の星
  • ゲームオーバー
  • 敵のバリエーション
  • スコア
  • ステージクリア

最初は描画の不具合修正とサウンドドライバの軽量化。
ボスをビジュアルのメインに持ってくることにしたので、ボスの作りこみを進めます。

反射レーザーをX1turboで再現したかったので作りこんでましたが、
意外と時間がかかる事が判ったので残念ながら見送りにしました。
ここも今後の課題ですね…。

ボス制作

RTYPE BOSS

画面比率に合わせてグラフィック素材作成。
ボスはとにかくパーツが多いです。挙動を調査して再現。
しっぽの挙動は計算で行うには調査時間も処理時間も足りないので一つ一つパーツの座標を拾ってデータ化しました。
ボスのしっぽがちゃんと計算どおり動いた時は嬉しかったです。パーツが20個もあります。破格です。
ゲームをプレイしてみると判りますが、このしっぽはプレイヤーを攻撃する働きも持っていますが、
プレイヤーの攻撃に対しての防御にもなっています。波動砲もレーザーも通さない。
この攻撃と防御が組み合っているしっぽがうねうねと動く様子、生き物として組み立てられた動きを
見ていると当時の企画者の意図をようやくくみ取れたようで嬉しかったです。

BOSS しっぽ座標の取得

タイトル

RTYPE タイトル

タイトル部分のRTYPEの文字が右側から移動してきてニュっと広がる所。
ここがX1turboで実現できるかずっと妄想してました。

この「自分の愛機で実行できるか?」を知りたい気持ちは何年経っても消えないです。
色数が減ったり、FPSが下がってガタガタになっても再現できるかどうかに興味あります。

タイトルのレイアウト

上記はタイトルのレイアウトイメージです。
テキストのレイアウトはEXCELを使います。
EXCELはデータのまとめや、レイアウトや容量計算、データ作成も行う必須ツールです。
1980年代当時にはなかったツールですがめちゃ便利に使っています。

動作テスト

基本的に会場ではデモを繰り返し流す事にしているので、
実機で安定して動くかどうか、検証のために長時間のエージングテストを行います。
以下の点などを中心にチェックを進めます。

  • 読込みに失敗しないか?
  • メモリを破壊したりしないか?
  • ループデモでプレイヤーの動きが変にならないか?
  • サウンドの再生で不具合は出ないか?
  • 初期化を忘れていないか?(これはよくある。ありすぎる)

不具合とひたすらに対処

繰り返しテストしていると、サウンドドライバが特定の状況で音がおかしくなる事が判り、
キーロガーのシステムを用意して、自動的に不具合が再現できる環境を整えて原因が特定できました。
このシステムは描画不具合を調べる際にも活躍してくれたので重宝しています。
また、FM音源をずっと再生しているとノイズが乗る事があったので、手持ちのボードを交換してなんとかなりました。
ここはハードウェアの検証を今後も続ける必要があります。

設置テストとバックアップ

仮の机を用意して配置物のテスト。
どの辺りに何を置くかや導線なども確認しておきます。
ここで実際に電源を入れて、動きなども一通り見ておいた方が良いです。
途中機材が故障した場合のバックアップでノートPCにエミュ環境を用意しておきました。
この心配を始めるともう1台 X1turboがあった方が…とかになって来るのでほどほどにしておきましょう。

ポスターと資料作成

今回、「X1の日」で作成したX1シリーズの年表を用意しました。
X1の日は勝手に「X1の日」と名付けた日を毎年ポストしていく試みです。
一応毎年モチーフを決めてポストしてます。

ここで各機種をふりかえりながらポストしていくのですが、だんだん
X1の生い立ちやどういう背景で作られたか知りたくなってきたのでシリーズの年表を作成しました。
裏付けがとりにくいので妄想の域は出ないのですがイメージをつかんでいきます。
それに一度作って公開しておくと「いやここは違うよ」という意見が出てくる可能性もあります。
こちらは今回のMI68で変更する箇所があったので、それを反映したバージョンを今後公開してみます。
この資料制作、イベント開始ぎりぎりまでかかりました。
印刷用紙やインクの予備も用意して、ひたすらプリンタに頑張ってもらいました。

X1/turbo 開発年表

※ 修正前なので解像度低いのを上げてます
※ 左上のトピックはX1/turboの考察をまとめたもので結構量があります。公開できる所までまとめたいトコロ。

ワンオペ

今回はワンオペで取り組むつもりだったんですが、ワンオペはしんどいよーと
アドバイス頂けたので、その方に助っ人に入って頂き、本当に助かりました。
他にも色んなアドバイスを頂いたので今後に活かしていきたいと思います。

イベント当日

秋葉原 UDX

会場について、事前に送っていた荷物を受け取り、その後設営開始ぃ。
しかし、当初考えていたよりもスペースが狭いです。
荷物の箱を置いておく場所がありません。X1turboを2台持ってこなくて良かった。
今回は人数が少ないのでなんとかなりましたが今後の課題ですね。
設営準備完了をポスト。これ前回は忘れてました。

設営完了

ディスプレイスタンドでX1turboが良く見えないので後半から位置をずらしてます。
基本的にループデモが展示と案内をやってくれるので、あとは来て頂いた方に色々と解説を行いました。
ホントはもう一つ資料があったのですが、なぜか帰宅後に見つかりました。次回使おう。

イベント開始

色々な方に来て頂いてX1の話が出来て良かったです。
デモと名前を付けているのですがプレイアブルだったので色々説明が足りなかったですね。
おみやげもいただいてしまって恐縮至極。
前回も思いましたが、他のブースを見に行けるバランス感覚が大事ですね。

おわりに

イベント終了後に全体的な流れや準備、制作の部分のふりかえりを行いました。
今後に活かせるといいですね。はい。
毎回思いますが、やはり当時の実機が動いているという説得力が強いです。
すでに実行環境はEMMやHDDベースですが、このフロッピーディスク
付いている実機イメージは大事だなと思いました。

まさか自分がイベントに出展する側になるとは全然考えていませんでした。
機会を与えて頂いた方々、ありがとうございます。

おまけ:モチベーションの上げ方

制作を進める上でモチベーションの上げ方は課題ですね。

  • スケジュールを引いたりイメージを固めるのも有効。
  • youtubeTwitter(新 X)を落としておくのもめちゃ有効です。
  • サントラが重要です。制作中はRTYPEのサントラをずっと聞いてます。

あと最近、制作物のことを考えるのが一番有効だと思ってます。
モチベーション上げは対象物をずっと頭に入れておく事が最強かと思います。

X1/turbo用 NDP プレイヤー

X1/turboでNDPを再生したい

X1用NDPプレイヤー

NDPとは?

NDPとは、なるとさんの制作された MSXサウンドエンジンとその環境です。
MSX用のPSGプレイヤーと合わせて、Windows用のエディタとMMLコンパイラ環境が提供されており、
PSGサウンドの表現力を向上させています。
詳しくは以下のサイトをご覧ください。

NDP - PSG Driver for MSX

X1でNDPを再生したい

MSXのPSGを強化しているNDPですが、MSXサウンドチップとX1は同じ AY-3-8910が使われています。 差はあれどもしかしたら NDPがX1でも再生できるかもしれない?というのが注目している理由でした。
そして、先日NDPのリリースが開始、環境をダウンロードしてみるとサウンドエンジンのソースまで
公開されていて、改変もOKという豪華っぷり。
ソースを見ていると、PSGレジスタにセットする所と周期を合わせて呼ぶ事ができればなんとかなりそうです。
とりあえず実装すると、サウンドを鳴らす事ができました。

LSX-Dodgers用のプレイヤーを作ってみた

NDPのサウンドエディタはMSX用のbsave形式のNDPファイルを出力します。
これを持ってきて再生する環境はと言えば、まずは LSX-Dodgers用がよさそうです。
というわけで、LSX-Dodgers X1/turbo用 NDPプレイヤーです。

ダウンロード

  • v12.102
    • X1 NDPプレイヤー(v12.102)
      • 管理をgithubに移行しました。
      • 音程データ,ハードウェアエンベロープデータ修正
        • 更にhex125(293)さんから頂いたデータルを修正したバージョンです。
        • 高音域でもずれが少なくなるように調整されています。
      • オリジナルMSX NDPクライアントの v1.0.2の変更分を反映しました。
      • バージョン番号を変更しました。
        • 前半がX1NDPバージョン、後半が参照したMSX NDPクライアントバージョンです。
      • 非turboのX1でもFM音源ボード搭載時は FM音源のCTCを使用するようにしました。
  • v1.1
  • v1.0

使い方

プレイヤー実行ファイル x1ndp.com
X1用 LSX-Dodgers環境に実行ファイルと再生用のNDPファイルを転送してください。

使い方

コマンドラインから以下の形式で実行してください。

x1ndp [NDPファイル名]

NDPファイルを読込んで再生を開始します。
曲が終わったら終了するようにしていますが、statusが停止状態にならないので原因を調べてみます。
途中で何かキーを押すと終了します。

説明

  • 現在はNDPファイルをそのまま再生しているのみです。
  • 起動時にX1とturboを判定しています。
  • X1の場合は、VSyncによる判定で60fpsの制御を行っています。
    • Twitter上で教えて頂いたCRTC設定を変更して 60fpsにしています。
    • プログラム終了時に元に戻しています。
  • X1turboの場合は、CTCによるタイマーで判定して 16.70msecの制御を行っています。

その他

プレイヤーを作っただけなので、中身の調整は今後進めてみます。

謝辞

PSGの可能性を広げる、NDP環境を構築・公開してくださった @naruto2413 さん
素晴らしいツールと環境の公開、ありがとうございます。

X1turboでHDDを使用する

X1turboとHDD

1985年当時 X1turbo用HDDは10MB。価格は10万円。
ここから価格も下がりながら大容量時代へと進みますが、8bit 64KBのメモリ空間はHDDを扱うには小さく、
また大容量コンテンツはFDでは枚数も多くなり、載せずらかったという面もあったと思います。

しかし、X1turboはその中でも HDDが接続できる数少ない8bitPCです。
大容量HDDデバイスで X1turboの可能性を探ってみます。

HDDデバイスとLSX-Dodgers

X1turbo DISK BASICでは HDDの容量は10MB程度なのですが、
今回、使用している ArdSCSino X1turboは、
SCSI(SASI)デバイス(HDD) を arduino で再現するハードウエアです。
MSX-DOS互換の LSX-Dodgersでは独自ドライバの拡張で
512MBという大容量にアクセスが可能です。

ボード上にマイクロSDカードスロットを持っているので、
イメージファイルを書込んだマイクロSDカードをセットします。

X1turbo用 HDD増設ボード ArdSCSino

ここではHDDイメージのセットアップの手順をまとめます。

HDDイメージ作成

エミュレータや ArdSCSino用に HDDイメージとして .vhdファイルを作成します。

HDDイメージ .vhd

Windows上で .vhdファイルを作成します。
以下の LSX-Dodgersページに .vhdファイルの作成手順がありますのでそちらを参照してください。

github.com

HDDサイズ 512MBを指定する場合はアロケーションユニットサイズ は 8192を指定します。
この .vhdファイルはWindows側でマウントしてファイルを読書きする事ができます。

イメージファイルの指定

エミュレータのHDDイメージ指定では拡張子に .vhd が表示されないですが指定が可能です。

エミュレータでのHDDイメージファイルの指定

  • ArdSCSino ボード

ArdSCSinoでは説明には .hds の例がありますが、
.vhdファイルを以下のファイル名にしてイメージファイルとして、
SDカードにコピーしても認識してくれます。

  • ドライブ0:hd00_256.vhd
  • ドライブ1:hd01_256.vhd
  • ドライブ2:hd10_256.vhd
  • ドライブ3:hd11_256.vhd

HDDマウント

HDDのマウントは、LSX-Dodgersの HDDコマンドから行います。 ドライブレターは A~Hドライブが指定可能です。

例:

  • HDD0をHドライブにマウントする
    • hdd 0
  • HDD0をHドライブに、HDD1をCドライブにマウントする
    • hdd 0
    • hdd 1 0 c

スクリーンショット

DIRコマンドでアクセス

これで超次元的な容量が使えるようになりました!

X1turbo 40周年 RTYPEデモ

X1turbo版 RTYPE風デモ EMMスクロールについて

X1turbo 40周年記念 RTYPE風デモについて

1984年にX1turboが登場して、2024年に40周年を迎えました。
それを記念して、RTYPE風デモを作ってみました。
このページではそれらの技術解説を行います。

youtu.be

滑らかなスクロールを実現するには

永らく、X1turboでRTYPEを実現する方法を考えていましたが、
複雑なBGを滑らかにスクロールする方法はなかなか思いつきませんでした。
当初、PCGでテストしましたが滑らかにスクロールするにはPCGの数が足りません。
重ね合わせやPCG+グラフィックでタイリングする方法も試しましたが表現力に難ありでした。

検証を行っていたデカール方式…きびしい…


4枚の画面を切り替える

ある時にヒントになったのは、シフトした画像を切り替える事でスクロールさせる方法でした。
Twitterでちまちまさんから教えて頂いた、イナブキさんのトピックでした。

x1c.imawamukashi.com

この時のスクロールネタを元に、グラフィック画面のスクロールを試してみました。
X1turboは320x200のグラフィック画面を4枚確保できるので、2ドットずつシフトしたBGを
切り替える事ができれば実現できそうです。


サンプルを組んでみたら滑らかなスクロールが実現できました!
長年夢見ていたX1turboでのRTYPEのBGスクロールに一歩近づきました。

youtu.be

EMMスクロール

問題点はシフト画面を作る時のCPU負荷が高い事でした。
また約850キャラ分の画面チップをメモリ上に載せるとそれだけでメモリが満杯になりました。
そこで、EMM上にあらかじめシフトしたBGデータを置いて、それをDMAで転送して描画する事で、
大きくて複雑なBGを描画してスクロールする方法を考えました。
ちょうどAX-5というバンクメモリ+EMMボードを入手する機会を得たので、これを活用すれば実現できそうです。

スクロール画面描画と表示

  • GRAMをページごとに切り替えて、4枚表示した所で CRTCの表示位置を+1して画面を+8ドット移動しています。

  • EMMから読みだす1列分の情報をSTRIPデータと呼んでいます。
  • STRIPデータは先頭にスクリーン参照INDEXを持ち、空白部分とグラフィック部分から構成されています。
  • スクリーン情報はグラフィック部分への参照を持っています。
  • GRAMへの転送・描画ページと、表示しているページを分けることでティアリングが起きないようにしています。

転送と参照

EMMからデータを読込んで展開しながら描画を行う事ができました。
しかし、ゲームに使用するためにはキャラクタなどがGRAMを書き換えた時、消去時にまた元に戻す必要があります。
つまり、一度描画に使用したグラフィックデータは、そのまま保持しておく必要があります。
また、描画や消去時にデータのコピーが多く発生すると、それだけでCPU負荷があがってしまいます。
そのためには、転送データをコンパクトに抑え、画面位置からグラフィックデータへ低コストで参照できる機構が必要です。
解決方法として、画面上の列単位のリングバッファを用意して、直近の40列への参照を持つ構造にしました。
描画用と参照用のデータ構造図を次に載せておきます。

EMMデータ構造図

EMM上のデータ構造と描画フローを説明します。

  • STRIPデータはDMAでEMMから転送されます。
  • このSTRIPデータを展開しながらGRAMに描画を行います。
  • STRIPデータは40列分のリングバッファに転送し、画面上のスクリーンからグラフィック部分を参照できるようになっています。
  • STRIPデータのリングバッファは、バンクメモリ(0-3)に割当てています。
  • バンクメモリを切り替えることで、同一のアドレスにバッファを割当てる事ができます。
  • 画面にキャラクタを描画して、それの消去時に、グラフィックデータから書き戻しています。

EMMデータ構造図

この画面上の位置とスクリーン情報は、X1の特殊なGRAMの配列を活用しています。
X1のGRAMは以下のような並びで使いにくいとされていましたが、
Y方向の(0-7)をリセットすると、画面上の位置を0~1023のメモリに割り当てる事ができます。
この値とスクリーン情報を参照することで、画面上の位置とSTRIPデータを関連づけています。
仮想画面とGRAM,TEXTをリンクできるのは重宝するテクニックでした。

GRAM アドレス

PCGを使った2重スクロール

背景のスクロールをGRAMで行っているため PCGを遠景に使用して2重スクロールを行っています。
PCGよりもGRAMの優先を上げているので遠景として表示する事ができます。
PCGを使うことで遠景部分のキャラクタの重ね合わせを行わずに済むため処理負荷を軽くする事ができます。
(実のところ、2重スクロールよりも負荷を下げるのが目的です)

PCGは少しずつずらしたキャラを定義、そのスクリーンデータをEMM上に配置して DMAでテキストVRAMに転送します。
ハードウェアスクロールを使用しているので 1列ループする所はCPUで転送しています。

ステージの途中でPCGを少しずつ定義することで、フェードインぽい効果を付けています。
この時も青プレーンのみ転送する事で負荷を軽くしています。

遠景のキャラクタ(PCG)

ビットラインバッファ

ビットラインバッファは書込まれているデータがあるかどうかを、ラインに対応したビットをOn/Offすることで判定を行います。
ビットラインバッファの配置アドレスは、0f800h とORすることで算出します。
アドレスは固定になりますが、メインメモリの 0f000-0ffffh の4KBをビットラインバッファに割り当てます。
4ページ使用しているので4KB使用します。
この方法のメリットは、GRAMのアドレスからビットラインバッファへのアドレスを求める事ができることです。
ビットラインへのアドレス計算を別に持つ必要が無いため高速に扱えます。
画面消去時も、GRAMアドレスからビットラインバッファへのアドレスを算出することができます。

ビットラインバッファでの描画とプレーン数最適化による描画コスト削減

ビットラインバッファを参照して描画エリアにすでに描画されているかを判定して、
ビットが立っていない場合は直接書込みます。 ビットが立っている場合は重ね合わせ処理を行います。

書込み時に1,2,3プレーン数ごとに処理を分けます。
1プレーン書き込みを行う時は、BRGプレーンに分けて3色の描画処理。
2プレーン書込みを行う時は、BR,BG,RGの3パターンに分けます。
こうすることで、描画負荷を下げながら色数を増やす事ができます。
3プレーン書込みは、BRGプレーン全部に対して書込みを行うので一番処理が重いですが、
それよりも重ね合わせ処理の方が重いのです。

同時アクセスモードによる消去処理

X1の固有の処理として、同時アクセスモードを使用して3プレーンを同時にクリアできます。
描画時に描画アドレスとタイプをストックして消去に使用します。
描画アドレスをストックしておけば、そこからビットラインバッファアドレスを求める事が出来ます。
消去の際にビットラインバッファをチェックして一度消去した場所はスキップするようにしています。

座標系を固定小数点 9:7 にすることで高速化

X1 SGLは画面サイズは 320x200を使用しています。
横 320は8bitで収まらないため、16bitを使用した場合、計算用に固定小数点 8bitを加えると、24bit必要になります。
そこで、X1 SGL内の座標系は、X座標を 1byteで表現することで高速化を行います。
固定小数点 9:7 の16bitで計算を行い、当たり判定やクリッピングなどを1byteのみで判定しています。

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
XH XH XH XH XH XH XH XH XH XL XL XL XL XL XL XL

0-319の座標は、上位byteでは 0~159で表現されます。
9bit分なので1bitを下位バイトに持たせています。
この方法のメリットは以下の通りです。

  • 24bitではなく16bitの計算で収まる。
  • 表示座標を求める時は、1bit シフトして下位byteの最上位ビットと合わせて行います。
  • 固定小数点が7bit使える。(大抵は 4bitもあれば十分)
  • 移動スピードが2の倍数の時は上位byteのみ計算する。
  • キャラクタ同士やBGの当り判定は 8bitで計算を行って高速化できる。

その他

Z80でのテーブルジャンプ

キャラクタの制御を行う際、状態遷移をテーブルジャンプ等で実現しますが、
以下のようにフルで実装すると割と重い処理になります。

  ld a,(proc_no)
  add a,a
  ld l,a
  ld h,0
  ld bc,table_adrs
  add hl,bc
  ld a,(hl)
  inc hl
  ld h,(hl)
  ld l,a
  jp (hl)

table_adrs:
  dw proc0_label
  dw proc1_label

処理が重いので、軽いテーブルジャンプ処理が欲しくなります。
そこで以下自己書き換えを使用したテーブルジャンプの方法です。

proc_value0 equ ( proc0_label - table_jump )
proc_value1 equ ( proc1_label - table_jump )

  ld a,(proc_no)
  ld (table_jump-1),a
  jr table_jump
table_jump:

proc0_label:

proc1_label:

これは状態を示すコードに、JR命令の相対値をそのまま使うダイナミックな方法です。
jr命令の届く範囲だけですが、もし遠くに飛ぶ必要がある時は、JP命令と組合せます。

Windows10環境での USB-CVRS9の認識について

Windows10環境での USB-CVRS9の認識について

他のユーザさんから情報を頂きましたので紹介しておきます。
サンワサプライのUSB-シリアルアダプタ、USB-CVRS9が Windows10環境で認識されない件の解決方法です。

USB-CVRS9

USB-CVRS9をWindows10環境で使用した時に、認識がされず、
X1turbo Remote Monitorでの動作も出来ない件が発生することがあります。
この症状は USB-CVRS9がWindows10では非対応なため発生します。
解決方法は、Windows8のドライバをインストールすると解決するということです。

もし同じような症状で悩んでいる方がいらっしゃったら参考にして頂ければと思います。
情報をご連絡頂きましてありがとうございます。

Windows8ドライバ

X1turbo DMA バイト転送/バースト転送の負荷計測

X1turbo用 DMA負荷計測について

X1turboには Z80 DMAが搭載されています。
Z80 DMAのバイトモードと比較のためバーストモードについて探求しました。

実機側の処理負荷は走査線位置を表示して計測します。
この画像では、赤い線がDMA処理負荷、青い線がCPU処理負荷を示しています。
それぞれが同じ処理負荷ですが、DMA実行中はCPU処理が遅くなるため、青い線が太くなります。

Z80DMA バイト転送

バイトモードは、CPUとDMAの両方がバスを使用して転送を行います。
X1turboでFDを読込ながらBGMを鳴らす場合もこれを使用しています。
DMAの転送中でもCPUの処理が行えます。

Z80DMA バースト転送

バースト転送は、DMA転送が終了するまでバスをDMAが占有します。
その間はCPUは他の事ができなくなります。

サンプルプログラム

DMAテスト用プログラムを作成して検証を行います。

毎フレーム CPUで処理を実行し、並列にDMAバイト転送を行います。
バイト転送の転送先/転送元の種類を変更して、CPUの処理終了時間を実測します。

  • 転送種類

    • メインメモリ, GRAM,EMM
  • 計測時の画面モード

    • 15KHz / 24KHz
  • 実行環境

実行結果

  • 転送量 06c0h
  • M: メモリ / G: GRAM / E: EMM / T: TEXT
バイト転送計測比較

CPUとDMAが並列に実行しているモードです。
比率はDMAが動作していない時との処理時間の比率です。

バースト転送計測比較

DMAが優先して実行しているモードです。
比率は最速のメモリ間転送時の処理時間の比率です。

実行結果から分かった事

バイト転送
  • DMA実行時、CPUの実行スピードは 1/3 ~ 1/4 まで低下する。
  • 実機ではエミュに比べると転送 30%程度遅い。
バースト転送
  • GRAMからの読出しはあまり影響がないが、GRAMへの書込みは30%程度遅くなる。
    • CPUのアクセス速度では表面化しにくい?
  • GRAM間コピーはそれ以上に遅く、15KHz,24KHz転送時に差があり、24KHz で 50%、15KHzで 70%程度遅くなる。
  • 例えば、GRAMに描画データを載せて、DMAでGRAMへ転送すると想定以上に遅くなる。

まとめ

DMA転送の処理計測を行って特性を調べることが出来ました。
この辺りが判ると更に高速化、効率化を行う事が出来ます。

処理負荷を下げるには、「対象を明確にして不明点を無くすこと」が有効です。
Z80のシステムでも、64bit のマルチコアの最適化でも、そこは変わらないです。

X1用ゲームライブラリ SGL

X1 SGLとは?

X1 SGLとは X1/turbo用のゲームにおける性能を引き出す事を探求したライブラリです。

きっかけ

X1はハードウェアスプライトの機構を持っておらず、描画時にチラついたり、描画負荷の重さからプレーン数を減らして色数が少なくなる事も多いです。
Newグラディウスデモを制作時に、これらを改善するべく自分なりにライブラリを作ったらどうなるか?というのを探求してみました。
このページでは主に今まで分散していたSGL記事をまとめたものです。
その中でも、ソフトウェアスプライトでの取り組みを説明します。

問題点

ソフトウェアスプライトを実現するために問題点をピックアップしてみます。

X1では重ね合わせの処理が重い

ソフトウェアスプライト処理は、X1ではGRAMのデータを ANDを取ってORを使ってはめ込む重ね合わせ処理を行います。

重ね合わせ処理

バンク切り替えは不要なものの、I/O空間にGRAMがあるため比較的遅いI/O命令でのアクセスが必要です。
しかもそれらをRGB 3プレーンに対して処理を行うため、非常に重い処理になります。
この処理を軽減するためには、できるだけ重ね合わせを行わないことがポイントになります。
必要な時だけ重ね合わせを行って、それ以外は単純に書込みだけを行えば処理を軽減できます。
そこで重ね合わせを制御する機構としてビットラインバッファという制御ワークを用意します。
下の図はそのイメージ図です。

ビットラインバッファ

このビットラインバッファのアドレスはライン単位になっており、bitが各ラインが書込み済みかどうかを示しています。
X1のGRAMは変則的な並びですが、描画時にも処理を8ラインをひとまとめにすることで効率化を図っています。
ビットラインバッファを画面消去時もすでに消去済みかどうかをチェックして、2重に消去しないことで処理を軽減します。

描画プレーン数を減らして処理速度を改善する

描画プレーン数を減らす事で高速化を行いますが、出来るだけ表現力を上げる工夫をしてみます。
以下の様にパレットを設定します。

パレットセット

1プレーン描画では以下の色を描画します。
負荷が最も軽いため、数が多く登場するキャラクタに使用します。

単体プレーンのパレット

2プレーンの組み合わせを、Blue + Red,Blue +Green,Red + Greenと分けることで、少ないプレーン数で色数を増やしています。

  • 青色系統のキャラクタ (白/水色/青)
  • 赤色系統のキャラクタ (白/黄色/赤)
  • その中間 (白/水色/赤)

2プレーンパレットの組み合わせ

ちらつき軽減のためにダブルバッファを使用する

描画中の様子が見えてしまうとチラツキが発生します。
チラツキへの対処はダブルバッファが有効です。
X1は320x200x8色の描画ページを2枚持つことができます。これを活用してダブルバッファを実現します。
ページは、0000-07ffhのアドレスを分割して、0000h-03ffh, 0400h-07ffhの2ページで切り替えます。
この2ページを表示ページと描画ページに分けます。
表示ページを表示している間に、裏で描画ページに対して書込みを行います。
これをVSyncのタイミングで、表示と描画を切り替えます。 ダブルバッファは結構強力な機能です。3D用アプリケーションにも活用できると思います。

実装の詳細について

ビットラインバッファ

ビットラインバッファは書込まれているデータがあるかどうかを、ラインに対応したビットをOn/Offすることで判定を行います。
ビットラインバッファの配置アドレスは、0f800h とORすることで算出します。
アドレスは固定になりますが、メインメモリの 0f800-0ffffh の2KBをビットラインバッファに割り当てます。
この方法のメリットは、GRAMのアドレスからビットラインバッファへのアドレスを求める事ができることです。
ビットラインへのアドレス計算を別に持つ必要が無いため高速に扱えます。
画面消去時も、GRAMアドレスからビットラインバッファへのアドレスを算出することができます。

ビットラインバッファでの描画とプレーン数最適化による描画コスト削減

ビットラインバッファを参照して描画エリアにすでに描画されているかを判定して、
ビットが立っていない場合は直接書込みます。 ビットが立っている場合は重ね合わせ処理を行います。

書込み時に1,2,3プレーン数ごとに処理を分けます。
1プレーン書き込みを行う時は、BRGプレーンに分けて3色の描画処理。
2プレーン書込みを行う時は、BR,BG,RGの3パターンに分けます。
こうすることで、描画負荷を下げながら色数を増やす事ができます。
3プレーン書込みは、BRGプレーン全部に対して書込みを行うので一番処理が重いですが、
それよりも重ね合わせ処理の方が重いのです。

同時アクセスモードによる消去処理

X1の固有の処理として、同時アクセスモードを使用して3プレーンを同時にクリアできます。
描画時に描画アドレスとタイプをストックして消去に使用します。
描画アドレスをストックしておけば、そこからビットラインバッファアドレスを求める事が出来ます。
消去の際にビットラインバッファをチェックして一度消去した場所はスキップするようにしています。

座標系を固定小数点 9:7 にすることで高速化

X1 SGLは画面サイズは 320x200を使用しています。
横 320は8bitで収まらないため、16bitを使用した場合、計算用に固定小数点 8bitを加えると、24bit必要になります。
そこで、X1 SGL内の座標系は、X座標を 1byteで表現することで高速化を行います。
固定小数点 9:7 の16bitで計算を行い、当たり判定やクリッピングなどを1byteのみで判定しています。

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
XH XH XH XH XH XH XH XH XH XL XL XL XL XL XL XL

0-319の座標は、上位byteでは 0~159で表現されます。
9bit分なので1bitを下位バイトに持たせています。
この方法のメリットは以下の通りです。

  • 24bitではなく16bitの計算で収まる。
  • 表示座標を求める時は、1bit シフトして下位byteの最上位ビットと合わせて行います。
  • 固定小数点が7bit使える。(大抵は 4bitもあれば十分)
  • 移動スピードが2の倍数の時は上位byteのみ計算する。
  • キャラクタ同士やBGの当り判定は 8bitで計算を行って高速化できる。

描画用データ

キャラクタデータは事前にビットシフトを計算して展開します。
容量を多く必要としますが、高速に描画することが可能です。
容量を減らしたい場合は、2ドット単位のデータにしたり、プレーン数を減らす事で調整を行います。

画像の変換は自前のコンバートツールを使っています。
高速化のためにクリップ情報などを事前に計算しています。

コンバート例:

 ; データテーブル
 en1_p0_c2:
  db 0fch ; Pivot(x) -4
  db 0f8h ; Pivot(y) -8
  db 8 ; データ数
  dw en1_p0_c2_0 ; 0
  dw en1_p0_c2_1 ; 1
  dw en1_p0_c2_2 ; 2
  dw en1_p0_c2_3 ; 3
  dw en1_p0_c2_4 ; 4
  dw en1_p0_c2_5 ; 5
  dw en1_p0_c2_6 ; 6
  dw en1_p0_c2_7 ; 7
  
 en1_p0_c2_0:
 ; Xoffset: 0
 ; Mask: [G R]
 ; OutSizeX: 16 OutSizeY: 16
  
  db 183 ; clipy(byte) 200-sizey-1
  db 020h ; DrawType (Plane: RG SizeY: 16)
  db 39 ; clipx(right) 40-sizex+1
  db 63 ; clipx(left) 64-sizex+1
  db 2 ; sizex(byte)
  db 48 ; sizey(pitch)
  
 ; 0
  db 0ffh, 000h, 000h
  db 0ffh, 000h, 000h
  db 0feh, 001h, 000h
  db 0e8h, 017h, 000h
  db 0c8h, 037h, 001h
  db 0c8h, 037h, 000h
  db 085h, 07ah, 010h
  db 082h, 07ch, 011h
  db 0c2h, 03ch, 019h
  db 0c1h, 03eh, 00ch
  db 0e2h, 01dh, 000h
  db 0fch, 003h, 000h
  db 0f0h, 00fh, 002h
  db 0f8h, 007h, 001h
  db 0fch, 003h, 000h
  db 0ffh, 000h, 000h

デモ Balls / GitHub

SGLで16x16スプライトを描画するデモ「Balls」を作ったので、
X1用Ballsの実行ファイル(X1用)を置いておきます。
X1/turbo用なのでX1でも実行できると思います。

youtu.be

2019/07/06 ソースファイルをgithubに公開しました。 github.com

X1 Balls (D88)

性能評価

プレーンの組合せで変わりますが、以下の性能でした。

FPSモード Ball 1プレーン Balls 2プレーン Ball 3プレーン
60 8 6 6
30 17 14 13
20 31 29 19

使用する環境(実機/エミュレータ),X1/turboでも数字が変動します。

プレーン2枚の負荷が相対的に軽いので、利用しやすいと思います。
重ね合わせ処理をもっと細かくチューニングすればもう少し向上できそうですが、
スプライト数が増えてくると、ビットラインバッファの制御負荷をもっと下げる工夫が必要です。

デモ MarkX

X1 SGLを使ったスプライトデモをもう一本作りました。
あんまりリソースを増やさずに作ろうと考えたので、3Dデモになりました。

youtu.be

まとめ/今後の課題

X1 SGLはまだ改善点を探求しています。
ソースを公開しているものの、そもそも使い方を書いてないので、そちらもまとめてみます。

  • より高速な描画や最適化について。
    • より高速化な手法が無いか考え中。制御ワークを使う以外では対象ごとに描画方法を変えるのが一番有効。
  • 左右反転描画手法
    • 処理速度を出来るだけ落とさずに左右反転を行う手法。メモリ軽減に大きく寄与できるのでぜひ欲しい。
  • 上下反転
    • 左右反転と合わせて、メモリ軽減に寄与できます。こちらの方がまだ現実的。
  • プレーン組合せ
    • これはわりと近々に試してみたいネタです。
    • 2プレーン書込みが割と実用的なので、BR,BG,RGを組み合わせても割と高速に表現できるはず。

X1turbo Remote Monitor v1.2.2リリース

X1turbo Remote Monitor v1.2.2をリリースしました。

詳しくはX1turbo Remote Monitorのページを見てください。

今回は以下の修正を行いました。

  • d88ファイル読込み時の例外発生
    • FD書込み時などで、d88ファイルを読込む際に例外が発生していたのを修正しました。
    • d88ファイルではセクタエラーが発生すると、セクタデータが無くなってしまい、それが原因で例外が発生していました。
    • セクタデータが無い場合は、ブランクデータを入れ替えることで例外が発生しないようにしました。

X1turbo Remote Monitor v1.2.2

X1turbo Remote Monitor v1.2.1リリース

X1turbo Remote Monitor v1.2.1をリリースしました。

詳しくはX1turbo Remote Monitorのページを見てください。

今回は以下の修正を行いました。

  • FD書込み/FD読み込み
    • FD書込み部分は対応が簡単なものになっていたので、エラーチェックや、タイミングなどを修正して安定性を向上させました。
    • 合わせて、FD読み込み部分も修正を行いました。まだ完璧ではないので、今後も修正を続けます。
    • FD書込み部分に Verify機能を追加して、書込み後に再度読み込みして比較を行い、データが正常に書込めているかをチェックします。
    • エラーになった場合は、再度書込むようにしました。

X1turbo Remote Monitor v1.2.1

X1turbo Remote Monitor v1.2.0リリース

X1turbo Remote Monitor v1.2.0をリリースしました。

詳しくはX1turbo Remote Monitorのページを見てください。

今回は以下の修正を行いました。

  • FD書込み
    • 2HD書込み時に77トラックまでの制限を掛けていたのですが 78トラック以上指定しているD88ファイルを指定するとアプリが停止していました。
    • 82シリンダ (184トラック)まで指定できるように修正しました。
    • 以前から不具合があったのですが、対応が遅れていました。

X1turbo Remote Monitor v1.2.0

X1turbo Remote Monitor v1.1.8リリース

X1turbo Remote Monitor v1.1.8をリリースしました。

詳しくはX1turbo Remote Monitorのページを見てください。

今回は以下の3つの機能を追加しました。

  • 転送ボーレート変更タイミングを各コマンドの開始時/終了時に変更するようにしました。
  • FD書込み
    • 書込みトラックの範囲を後から変更できるようにしました。
    • EMMへの書込み機能を用意しました。EMMにキャッシュデータを書込む等活用する事ができます。
  • プログラム実行機能
    • 実機でちょっとプログラムを検証する場合など、プログラムを転送して実行が可能です。
    • .2d/.d88などのディスクファイルを指定した場合は、IPL部分を転送/実行します。
    • CZ-8FB02などのBASICも直接起動できました。(その後の startup.basが読み込めないですが)

エミュレータでも開発を行うのですが、実機でプログラムを検証したい時に
実行機能が思いのほか便利でした。

通信エラーが発生する事があるということで、そちらも調査しています。
通信設定なども関係ありそうなので、いくつか環境を用意しています。
今回からトラブルシューティングのカテゴリも追加しました。

f:id:x1turbo_agency:20210525095336p:plain

X1turbo CRTCでの縦スクロールテスト

X1turbo CRTC制御による縦スクロールテスト

X1turboで縦方向のスムーズなスクロールは可能だろうか?
実現のきっかけは、スーパーターボさんがアップされていた以下の動画でした。

www.youtube.com

この中でX1turbo版ではカットされていた縦方向の画面スクロール部分を
CRTCで実現している箇所が衝撃的でした。
この動画を参考に、CRTCによる縦スクロール制御をテストを作ってみたのが以下の動画です。

www.youtube.com

CRTC縦スクロールの仕組み

CRTC 各レジスタを調整する事で縦スクロールを実現します。
まず レジスタR5を変更して、画面全体のラスタ位置調整して画面全体を上下させる事ができます。
しかしある程度の値を設定すると同期がずれて画面が崩れてしまいます。
次に、行のラスタを調整しているレジスタR9を書き換える事でラスタ総量を調整します。

例として、画面全体に1ライン下に下げる時は、R5値を+1して、
最終行のR9値を-1して全体のラスタ総量が変わらないようにします。

このレジスタR9を変更するのは走査線が最終行に差し掛かった時に行う必要があります。
それ以外のタイミングではR9を初期値に戻しておかないと同期ずれが発生します。

f:id:x1turbo_agency:20210404163438p:plain
CRTCレジスタ (「試験に出るX1」から引用)

これでラスタ単位の縦シフトが0-7まで実現できたので、あとは画面全体の8ドット単位のスクロールを
行います。CRTC R12,R13による描画開始位置を設定するのが処理負荷を下げやすいです。

R12,R13レジスタの値は、VSyncが終了する直前に設定されるので、画像表示期間中に変更しても
反映されません。即時反映する事ができれば、部分スクロールなどが実現できたのですが…
そうなるとティアリングで画面が壊れやすくなっていたでしょうね。

実装

最初のテスト版はVSyncや走査線チェックをCPUポーリングで行いました。
これらを非同期に行うため、その後CTC割込み版を実装しました。
上の図の緑色の吹き出しの箇所で割込みを発生させています。
CTC0を割込み中にリセットして再設定することで、より細かい制御が可能です。

サンプルプログラム

  • CRTCによるスムーズな縦スクロールのサンプルを githubに公開しました。
  • 検証やツッコミがあればレポートをお願いします。

2021/04/17 ソースファイルをgithubに公開しました。 github.com

f:id:x1turbo_agency:20210417225716p:plain
CRTC縦スクロールサンプル

TIPS

画面マスク

画面上部はCRTC R5レジスタ値を反映して何も表示されていません。
スクロールが見えないようにするためには、GRAMであれば描画量を調整し、
PCGであればマスクを上に載せる必要があります。
テスト版ではPCGの上にGRAMが表示されるように設定を行って、
スクロール値に合わせてマスクしています。

走査線の位置確認

走査線が今どの辺にあるかが判らないと調整しにくいです。
パレット0を一度黒以外の青とかに設定することで現在の走査線の位置を確認できます。
これを使ってどの走査線位置に割込みが起きているかを判定します。

パレット設定に失敗するタイミング

VSync中にパレットを変更するとパレットの反映が遅くなる事があるようです。
VSync中でない画像表示期間タイミングでパレット設定を行うと正常に設定されています。
この辺りはX1turboの機種によっても変わるかもしれません。

VSyncタイミング

1a01h pb7でVSyncの開始/終了を検知しています。
ところが、VSyncの終了検知したはずなのに、まだ VSyncが終わっていませんでした。
そこで、VSync開始時にタイマー割込みをセットして、VSync終了後最初の走査線に
差し掛かるタイミングを検出するようにしました。

VSync終了時に次のVSync割込みを設定しますが、
その際に一度HSyncを待たないと割込み位置が安定しませんでした。

HSyncを待つには

細かい走査線をチェックする上でHSyncを待たないといけない場面があります。
その場合は、PCG高速モードにして適当にCG読出しを行うと、HSyncを待つ事ができます。
HSync中でないとPCG/CGデータを読み出す事ができないためです。

動作検証とエミュレータ

動作検証はエミュレータ上では走査線ごとのCRTCレジスタ書換えに対応していないため、
実機で行う必要があります。
ただ、CRTCについては、かなりの再現度で武田さんのエミュレータは実機同様の動作を
しており、R9が即時反映されない以外は、VSyncタイミングのずれなども含めてほぼ完璧に
再現されています。

検証の度にFDDにプログラムを書込んでいたのでは検証に時間がかかるため、
X1turboRemoteMonitorでプログラムを転送/実行する機能を追加しています。
こちらは他機能が検証できたら公開したいと思います。

サウンド

CTCを画面制御に使っている関係で、サウンドの制御はVSyncタイミングで行えればと思っています。
X1turboのVSyncは15KHz,24KHzいずれも60fps丁度ではないので、サウンドのテンポの問題があります。

今後の改良

X1turbo用で解説していますがX1でも使用できるはずです。
CTCを搭載したX1で、HSyncをタイマー等で調整できれば同様に使えると思います。

今回はVSync中の処理時間もあって15KHzモードで実装しています。
24KHzでも一度試してみたいですね。


X1turboのVBlankタイミングについて

X1turboの垂直同期信号について

ずっと気になっていたVBlank周りの時間を計測してみます。

f:id:x1turbo_agency:20200530205515p:plain
VBlankイメージ

X1turboは IOポート 1a01h PB7に垂直帰線期間信号(VBlank)が出ています。
これはVBlankに入ると Lowになり、VBlank外では Highになります。

これをポーリングしてVBlankを検出します。
これがどの位のタイミングで変化しているかが気になっていたのです。

CPUのクロック数計測

まずは、CPUのクロック数で計測を行います。
実際は計測以外のコードも入っているので、合計値は少なめな値です。
対象はエミュレータ(武田さんエミュ)と実機(X1turboZIII)で計測します。

計測結果

Emu/実機 VBlank 期間(msec) VBlank外 期間(msec) 合計(msec)
24KHz (Emu) 1.32 15.52 16.84
15KHz (Emu) 2.96 12.07 15.03
24KHz (実機) 1.37 15.51 16.88
15KHz (実機) 3.00 12.07 15.07
  • Emuと実機ではほぼ差がありませんでした。
  • Width40,Width80でも計測しましたが差はありませんでした。
  • 15KHz,24KHzでVBlank時間に倍近い差があります。

15KHz, 24KHzで意外にも差があるのが判りました。

であれば、60回x60秒=3600回の長いフレームを計測してみます。
60秒にどれだけ近いか、という事になりますね。

以下が結果です。

Emu/実機 実測時間(sec) 同期時間(msec)
24KHz(Emu) 1:05 18.05
15KHz(Emu) 0:58 16.11
24KHz(実機) 1:05 18.05
15KHz(実機) 0:58 16.11

24KHzにけっこう大きなずれがありますね。
レースゲームなどでタイム計測をVBlankで行うと思わぬずれが発生しそうです。

まとめ

この計測が意味するところは、X1turboのVBlankは60fps程度かと思っていたら、
15KHzは 約 62fps、24KHzは 約 55fpsという結果でした。

最近のLEDディスプレイでも、640x400表示が可能なものは、
水平周波数 24.8KHz 垂直周波数 56.3Hzだったので
これで、ちょっとすっきりしました。

今度は、X1 / X1turbo / X1turboZ では異なるかどうかが気になりますね。
(CRTCの値が同じなので変わらないハズですが)