重要なお知らせ
アーリーアクセスキット関連は別の記事にしました。Qiitaで5万文字超えてくると記事編集画面がおかしくなってつらいためです。
https://qiita.com/isimiya/items/266b2df8d4ad579118cd
X68000 Zの新規勢の覚書
X68000Zではなく、半角スペースを入れてX68000 Zが正式表記。
たぶんずっと未完成で下書きママ。
編集リクエストもらったら検討するので、追記や修正してほしい内容については編集リクエストかTwitterで連絡ください。
内容は随時追加していきます。
マークダウンを整えるまではメモ書き感がすごいです。
説明が少ないのでエンジニア向けの内容メインです。
もっと良いものが欲しければ、あなたには自分で作る自由がある。
ていうか作って。
あと重要なことなのでここに書いておきたい。
X68000でPython環境あります。作者さんに感謝。
https://github.com/yunkya2/micropython-x68k
あと当記事ではX68000 ZのローンチタイトルのSHOOTHING68K Z-EDITIONを応援しています。
https://stg68k.remotex.co.jp/
実機(1900年代X68K)でも動くらしいです。(私は実機無いので分かる人に聞いてください)
コンテンツ一覧
- 作者の作業環境
- 大前提
- 当時の話
- 必要な資料とソフトと情報サイト
- 高速化に必要なソフト一覧
- 基本操作-CUI
- ゲームで遊ぶ
- ディレクトリ構成- 拡張子の概要
- 環境構築-XM6 ハード面
- 環境構築-XM6 ソフト面
- BATファイルの書き方
- Human68kの日常操作
- ゲームを作る-X68000上で作る
- ゲームを作る-Windowsで作ってクロスコンパイル
- ゲームを作る-Windowsで素材作成
- ゲームを作る-Z-MUSIC-V2用ZMDファイルの準備
- ゲームを作る-Z-MUSIC-V2用ZMSファイルの作成
- プログラミング-X-BASIC
- プログラミング-C言語
- プログラミング-アセンブリ
- クロスコンパイル
- 面倒な話-スプライトの実装内容
- 面倒な話-知識体系
- その他
- エミュレータの妄想
- 個人的なメモ
- 風の噂
- 操作逆引きリスト
Cプログラミング関係のコンテンツ一覧
- プログラミング-C言語
- コンパイラの違いについて
- ライブラリの違いについて
- 環境構築-GCC真里子版-HAS-hlk-XCライブラリ
- 役立つ自作関数例-キーボード入力
- 役立つ自作関数例-文字列のTrim関数
- 役立つ自作関数例-iniファイル操作
- 役立つ自作関数例-iniファイルの想定フォーマット
- チラつき対策
- 筆者が使っている画面モードの仕様
- パレットと色
- スプライトとBG
- 半透明処理
- 実行ファイルのパス
- 型のサイズについて
- ゲームループについて_基本形
作者の作業環境
エミュレータ
XM6 type G
OS
Human68k
テキストエディタ
Windows : サクラエディタ, VSCode
プログラミング
gcc真里子版, XCライブラリ
Make : まだ自作batファイルで代用中
音関係
FM音源ドライバ : Z-MUSIC V2
Windows : ZMS(MML)作成 サクラエディタ
Windows : ZMS動作確認 ZMDRIVE
画像制作
Windows : ドット絵作成 EDGE
Windows : 画像変換 GIMP
Windows : 画像一括変換 Ralpha
Windows : テクスチャファイル作成 TexturePacker
Windows : 画像変換(X68000用画像データへの変換) 自作ツール
オフィスソフト
Windows : LibreOffice
大前提
lzh形式の展開の仕方
当時はファイルの圧縮形式がlzhでした。
今はWindowsで対応していないため、7zipなどのソフトを使用しましょう。
ハードとOS
まずX68000はOSではありません。ハードです。
OSはHuman68kです。これはフロッピーに入ってます。(install機能はある)
なので理屈としてはX68000準拠のOSなら何でも起動できる気がします。未確認。
内部の設計はMSーDOSに色々と似てるらしいです。未確認。
参考 WikipediaのHuman68kのページ
ピクセル比が違う
今はピクセルと言えば正方形だが、X68000のピクセルは公式のモニターで4対3だった。やや横長。
よって、ピクセル比が4対3のモニタ用に作られた画像は、現在のモニターで見ると横が短く圧縮されて見える。
何ができるの? どう違うの?
他のOSと比べるなら、WindowsとLinuxの違いくらいです。出来ることはスペックの許す範囲で理論上Windowsと同じですが、公式やユーザーの積み重ねたソフトウェア資産の違いが大きいです。当時は巨大なライブラリやフレームワークが発明される以前ですから。
なので、当時X68000に大きな意味があったのはスペック的に最上位機種だったからです。今では優位性が消えてます。今からするとラズパイのほうが完全上位。高性能。
なのになぜX68000 Z? という話になると、メガドライブミニからのミニハード瑞起の流れです(個人の感想)。
それはさておきハードやOSが圧倒的にレトロ仕様だから、電子工作・電子工学あたりと親和性が高い。今のラズパイやLinux系OSを触っても低レイヤーなことは考えなくていいし触る必要もないし、なんなら触るのに手間がかかって面倒。特にセキュリティ関係の機能があるから面倒。地球大統領にされて何でもできると言われるより、自分の公園をもらって工作したいんだわ。X68000だとセキュリティ関係が少なく直接触りやすいので、低レイヤーなことをプログラミングする環境としてはかなり優秀。今と仕様違うじゃん?というのは問題なし。どうせ低レイヤーな部分はハード次第で色々変わるので問題なし。むしろX68000の頃のほうが仕様が超小さいので憶えやすい。今のPC OSの仕様をX68000時代並みに細かく憶えるの無理でしょ。しかも仕様に種類が多い時代なわけだし。
そんなわけで、CPU固定のX68000で、Human68kというOSが10MHzで動けるのは面白いわけです。X68000の命令セットや仕様だけカバーできる現在仕様のCPUを合成できればハード面でも面白そうなわけで(さすがにデカいから厳しいが)、個人で目指せる電子工作の究極系としてのX68000は面白そう!
そんな『現在ではパワー弱すぎスペック低すぎPC』としてのX68000は、現行に比べて複雑すぎずセキュリティが無いって点で低レイヤー初心者が楽しめる場所になればいいなーと思ったり思わなかったり。
なんでもいいから自作基板作ってデバイスドライバ書こうぜ!
シングルタスク
シングルタスクだから何?
という話はあると思う。でも、マルチタスクから入った人は、マルチタスクとの違いが本当に分からないのだ。少なくとも私は分からなかった。
キーボード入力のあるプログラムを書いて最初に思ったのは、『フォーカスはどうなるのだろう? プログラム実行中もHuman68kのシェルが動いていると、シェルも一緒に動いてしまうのでは? シェルからフォーカスを外さないと、キーボード入力に合わせてシェルに入力されてしまうのでは?』というものだった。
結論から言えば、シングルタスクだと心配無用だった。実行中はひとつのタスクしか実行されないため、バックグラウンドからの割り込みが無いのだ。Windowsのデスクトップアプリのような、ウィンドウのフォーカスとかいう概念も無いと思われる(ただしSX-WINDOWはまだ調べてないので分からない)。
要は、プログラムが実行され始めると、『大丈夫。全部任せてくれ、バトンタッチだ。俺がPCを使う。使ったあとは片付けて、辻褄を合わせてから返すよ』って感じで動く。
OSはOSで、プログラムを実行すると、それが帰ってくるのを信じて冬眠する。
並行して実行できないからそうなるのだ。
慣れるしかない。
デスクトップ環境
Human68kの標準のデスクトップ環境はコマンドシェルです。CUIです。
GUIのデスクトップ環境としてはSXーWindowなどがあります。
Linuxみたいにデスクトップ環境を入れ替えられるのか、それともHuman68kのデスクトップ環境を変えてコンパイルしているのかは分かりません。後者の気がするけど未確認。
→デスクトップマネージャなんて代物は存在しません。
そこに割ける資源が無いので...
GUI環境は
(1) ビジュアルシェル(VS.X)
(2) SX-WINDOW
(3) Ko-Window
とありますが、(1)はシングルタスクということもあって、常用している人は見たことがありません。
参考 WikipediaのHuman68kのページ
OSの違いによる前提の違い
ファイルシステム(FAT16系?)がWindows11と互換性がありません。→X68000のフロッピー等は、FAT12/16をハドソンが独自に互換して誰かが21文字に拡張したものだけれど、8+3文字部分だけ使い大文字で揃ってるならFATとして読める。vfatとは拡張方法が異なる。
文字コードの違いがあります。UTF登場前なので爆散してください。SJISより前の時代と予想。→記事拝見しました。文字コードはPC-9801などと同じくShift-JIS前提です。
Unicodeは産声を上げる前でした。
特定方向への文字コード変換ツールは無くはない、という状況ですので、基本的には他所でShift-JISに変換してから持ち込む形になります。
圧縮形式の違い lzh全盛期です。LHAですね。Windowsだと7zipなどで解凍できます。
BIOSではなくIOCS。配置される階層としての立ち位置は同じだが、提供している機能が違うように思う。細かく確認していない。
ハード面の違い
X68000 Zから入った人にはキーボードの洗礼が待っております。キー配置の違いを楽しんでください。
画面の合成
今はフレームバッファが2つ以上あって表裏を切り替えたり、なんなら切り替えも自動なので何も意識しない画面です。手動切り替えにするためには特殊な設定が必要になりますね。だから画面の切り替えを自前でやったことない人もいるはず。
が、X68000の頃にはそんな今の常識は通用しないわけで、手動です。
さらには画面が複数種類あります。
- テキスト画面(16色)
- グラフィック画面(16、256、65536色)
- BG画面(16色、パレット16本)(スプライトと共用のため設定により0から2画面)
- スプライト(16色、パレット16本)(BG画面と共用のため設定により256から128個)
ここで気になるのはテキスト画面とBG画面とスプライトって何だ? ということでしょう。
スプライトと言えば画像(スプライトシート)を均等に切ったスプライトのことですが、この頃は別物でした。それぞれの存在が出力後に回路合成されて最終画面が作られます。
予想になりますが、当時はCPUが遅くて画面全部を書き換えられないため、複数の画面を用意し、一部だけ書き換えるという思想だったのでしょう。BG画面にはスクロール機能があることから、2Dアクションや2Dシューティングゲームを念頭に置いていたと思われます。
また、画面ごとに使える色数が違います。さらには色パレットなる存在も。色パレットと言えば古のgif形式で使われていた言葉ですが、ドット絵を描かない人には謎の呪文。
今はドット絵アプリで16色のパレットで打つやつがありますが、そのあたりが目にする唯一の機会でしょうか。
さらにはPNG形式などが登場する前のため、減色処理や画像形式について調べる必要があります。例えばグラフィック画面のRGBデータはGRBのようです。流し込むデータを作るときは気をつけましょう。
エミュレータ
筆者はXM6を使っています。Windows11で動作します。他は知りません。
ダウンロードや細かい動作方法はXM6のページを検索
当時の話
プログラミングがアートだった頃
Javaあたりからはスクリプターとしての側面が強くなる。
と書いていてふと思ったのだが、今のハードウェアを意識しないプログラミングは、スクリプト言語(の考え方と機能)が究極進化したため、プログラミング言語のように振る舞えるからプログラミング言語として扱われているだけなのかもしれない
↓
WordPressのプラグインを書くので最近PHPとJavaScriptでも書くんですけど、なんか雰囲気で「こんなカンジー?」で書いてもなんとなく動いちゃう感がハンパないです。記法がブレてもエラーにならないので「正解がわからない」ユルユルな感触が気色悪すぎて
↓
概念的なプログラミングなので
AをBにしたい
という命令に対して、実行結果だけ保証されていて、過程についてはブラックボックスって感じですからね。
正解というのは、AがどうやってBになるのが最短又は製作者の意図か?の話なんでしょうけど、概念的なプログラミングだと最短には興味ないし(そもそも概念的なプログラミングは最短とは真逆の手法です)、製作者の意図は、シンタックスシュガーみたいに他の意図でも結果が同じになる上、組織やグループで作られるため個人製作者の意図みたいなものは薄くなるのかなと。
やり方のルートが一つにならないのも、概念的なプログラミングあるあるなのだと思ってます。(C#からスタートした者の意見)
↓
結果がOKなら実装の詳細は問わない、というのが時代の趨勢です。それが現代の「ソフトウェア工学」のゴールであり成果ですし。「正解」って感覚はおそらく「システム資源の浪費」に躊躇する意識、それともうひとつ課題を「効率的に」解いていきたいという、時代錯誤的な「美意識」からきている。
これって一種の「ビンボー症」ではあるんだけど、それともう一つ、プログラミングが「工学」になる前の時代、例えばX68000が生まれた頃の時代の人々が持っていた感覚でもあるんですよね。例えばこういう本↓が成り立つ時代。ソースコードを「鑑賞」するって感覚があったんですよ(本→Lions' Commentary on UNIX)
↓
『プログラミングがアートだった時代』
という言葉を聞いたときによく分からず流していましたが、その意味が分かってきた気がします。
その文化が無い場所で生まれ育ったから、私が観光客として眺めてるのは否めませんが。
↓
わかります。で、その時代の「道具」はそれなりの経験と手管を使い手に求めます。おそらくそれがisimiyaさんが感じている戸惑いの原因でしょうね。それとこの分野におけるレトロ趣味というのは「アート」への回帰でもあるので、こういう博物館もあったりします( https://computerhistory.org/art-of-code/ )
結果がOKなら実装の詳細は問わない、というのが「ソフトウェア工学」のゴールだ、っていう話には一つウラもあって。
それは「プログラマー」を、いつでも欠員の補充をできる、ソフトウェア工場の「従業員」とすることですね。今の人たちはそのあたりのウラは、あまり知らないかもですね
そんなわけで現代のプログラミングは明確に「生産」なのですが、当時のそれはまだまだ「経験」や「試行錯誤」の範疇でした。だから「アート」は「芸術」というよりは「技芸」に近い意味ですし、プログラマーも「芸術家」というより「職人」とか「親方と丁稚」みたいな雰囲気で。ほら、アノ人たちとか
PCの大航海時代
https://twitter.com/guhon/status/1602977204249702401?t=22Z2y2CjKDPgYfjsBzSu7Q&s=19
unityでゲーム作ってる若い子がX68kでゲーム開発環境作り出したけど、サウンド関係、予想以上の無知具合から始まっててビビる
そうかー、MIDIかー。
あとゲームに使うミュージックドライバーはzmusic以外ありえないよね。ドライバーも自作したいなら止めないがw
↓
2000年代生まれかな?と思うと、仕方ない、そうかーそう来るかーと思いますね。(笑)
吸収力の早さは、凄いのであっという間に追い越されそう。
そして、外野からヤイヤイいうと、新しい何かが生まれて来なくなくなるのではと思い始めました(笑)
↓
あまり若くないですねー。
37なんで。
MP3は90年代ですよ90年代。
わたしが小学生ラストくらいでPC使い始めたとき、MIDIは古い環境用として並行配布されてた気がします。たしか最初に触ったPCはメモリ64MBくらいだったはず。で、パソコンの開発関係の知識を持ち始めたのは23くらいからなので、2007年か2008年くらいからがメインの知識です。
↓
最近の10年の環境ってそんな変化ないですけど、80年代の10年ってすげーカッ飛んでますよねえ。
1981年にPC-6001が出て、1987年に初代X68000がグラディウス引っ提げて登場ですからねえw
↓
80年代は過渡期なのでマジでやばかったっすw 8歳でPC-6001mkII(8bit メモリ64kb)だったのがオレ12歳でX68000(16bit 1MB)になりましたからねwww
↓
俺も小学生は無印MSXでメモリ16KBから、高校でX68k EXPERT IIでメモリ2048KBっすからねえ。128倍パワーアップですわw
↓
激動の時代
↓
文字通り「PCの大航海時代」みたいな時代だったかも。
各社ごとにマシンやOSを作り込んで「やぁやぁ我こそは」と名乗りを上げていた時代ですね。
新機種という言葉に今以上の期待感があった頃です。
互換性は無かったし苦労も多かったけど、ああいった時代をリアルタイムで見られたのは良かった
↓
江戸時代に生まれた人は戦国時代を知らないみたいな話だ。。。
必要な資料とソフトと情報サイト
問題のあるリンクは分かり次第削除します。
Human68kのユーザーズマニュアル : https://ia800206.us.archive.org/12/items/X68000Human68k3.0/X68000_Human68k_3.0.pdf
必須です。これが無いとHuman68kの機能や操作方法が分かりません。
SX-WINDOW ユーザーズマニュアル : https://archive.org/details/X68000SXWINDOW3.0
SX-WINDOW 日本語マルチフォントエディタ ユーザーズマニュアル
探していますがネットには無いかもしれません。
サービスマニュアル X68000 CZ-634C/CZ-644C : https://galapagosstore.com/web/book/detail/sstb-B215-1215000-sm-cz-634c
ハード面のあれこれが書いてある。シャープさんのストアで0円で買える。
ぷにぐらま~ずまにゅある : https://github.com/kg68k/puni
超重要!!!! 色々な仕様のまとめ。深いプログラミングに必須。とりあえずmmio.txtは見よう。
X68k:IOMAP : https://datacrystal.romhacking.net/wiki/X68k:IOMAP
レジスタのアドレス説明。高速な処理を望むなら見る必要があるが、これだけだと説明が足りていないので色々辛い。グラフィック関連はぷにぐらま~ずまにゅあるのmmio.txtを見た方がいい。
X68000 LIBRARY : http://retropc.net/x68000/
最低限のソフトやエミュレータも含めて色々あります。ここが無ければいきなり詰みます。
魔法使いの森のX68000のページ : https://www.wizforest.com/OldGood/X68k/
こちらも色々情報があります。
練炭ブログ:https://rentan.org/blog/
最近のX68000の情報を知りたいならここへ
VectorのX68000のページ : https://www.vector.co.jp/vpack/filearea/x68/
色々なソフトがダウンロードできます。
X68030 日本語入力・辞書ユーティリティ ユーザーズマニュアル : https://archive.org/details/X68000FEP
日本語フロントプロセッサASK68Kのマニュアル
SHARP X68030 X-BASIC Ver 2.0 ユーザーズリファレンス : https://archive.org/details/X68000XBASIC2.0
X-BASICのユーザーズリファレンス。初心者がプログラミングするならここから。
XCライブラリのリファレンスはこれに載っている。
X68000 C COMPILER PRO-68K ver2.0 Cユーザーズマニュアル : https://archive.org/details/XC20CUsersManual
XCライブラリのリファレンスはX−BASICのユーザーズリファレンスに載っているので注意。→と思ったらCライブラリマニュアルもあり、そちらがXCライブラリに対して正しそうな内容だった。
X68000 C COMPILER PRO-68K ver2.0 Cライブラリマニュアル VOL.1 : https://archive.org/details/XC20LibManual1
CでXCライブラリを使うなら必須 VOL.2とセット
→個人的な正誤表:https://qiita.com/isimiya/private/7581eca8da75307edd66
X68000 C COMPILER PRO-68K ver2.0 Cライブラリマニュアル VOL.2 : https://archive.org/details/XC20LibManual2
CでXCライブラリを使うなら必須 VOL.1とセット
→個人的な正誤表:https://qiita.com/isimiya/private/7581eca8da75307edd66
X68000マシン語プログラミング : https://nfggames.com/X68000/Documentation/Books/X68000%20Assembly%20Language%20Programming%20-%20Introduction%20(omnipage%20600dpi).pdf
マシン語でのプログラミングのための資料。
Outside X68000 :
Inside X68000 : https://mdx.vampi.tech/files/Inside%20X68000.pdf
Inside X68000の正誤表(立花さんのページ) : https://kg68k.github.io/InsideX68000-errata/
IOCSコール一覧 : https://datacrystal.romhacking.net/wiki/X68k:IOCS
WindowsのGUI環境でプログラミングしていると関係ないが、X68000ではグラフィカルなソフトを作るときに理解しておく必要があるらしい。VRAMを直接いじる世界。
あとIOCSコール遅いのでHIOCS.X導入推奨らしい。
環境ハンドブック : https://archive.org/details/x-68000-programmers-x-68000-environment-handbook
IPLなどのことも載ってるらしい。大事そう。
X68000テクニカルデータブック : https://archive.org/details/X68000_488
仕様に近いもの
GCCによるX680x0ゲームプログラミング : https://nfggames.com/X68000/Documentation/Books/X68000%20Game%20Programming%20with%20GCC%20(omnipage%20600dpi).pdf
私にとってそのものズバリな本
PIC_FMT
http://www.vector.co.jp/soft/data/art/se003198.html
PICのファイルフォーマット仕様書。
Oh! MZ : https://archive.org/details/OhMZOhx19861989/Oh%21MZ_1986-01/
雑誌らしい
https://gorry.haun.org/x68index.html
個人サイト。画像のローダやグラフィックパターンエディタなどのソフトが公開されている。
X68000 Human68Kを使わずにプログラムを実行する
https://zenn.dev/morian/articles/ab313ec56c4c4f
FDでHuman68kを経由せずにプログラムを起動する方法
https://github.com/YosAwed/pon-x68k
おくとぱすXのパズルでGoGo! ゲームのソースコード
https://github.com/kata68k/-X68000-MACSplay.x/releases/tag/v1.06p
MACSプレイヤー
ZMDRIVE(Windowsアプリ)
https://twitter.com/markun2/status/1360971951703871497
Windows用のZMSやZMDを再生できるソフト。コンパイルしなくていいので非常に便利。
X68Sound.dllというDLLが必要。
http://mpuusan.web.fc2.com/x68sound/x68soundbody.htm
MML環境構築まとめ2022 with X68000
https://min.togetter.com/UHfvR3K
MicroPython
https://github.com/yunkya2/micropython-x68k
X68000でPythonが使える。古いCやX-BASICより、Pythonのほうがいい人は多いだろう。
X680x0 の未公開機能 : https://stdkmd.net/udcx68k/
??? : ttps://nfggames.com/X68000/index.php
不思議な呪文
ttps://archive.org/search?query=creator%3A%22%E6%BA%80%E9%96%8B%E8%A3%BD%E4%BD%9C%E6%89%80%22+OR+Description%3A%22X68000%22+OR+Description%3A%22X68030%22+OR+Description%3A%22X680X0%22+OR+Description%3A%22X68K%22+OR+creator%3A%22%E9%9B%BB%E6%B3%A2%E6%96%B0%E8%81%9E%E7%A4%BE%22+OR+title%3A%22X68000%22+OR+title%3A%22X680X0%22+OR+title%3A%22X68030%22+OR+title%3A%22X68K%22
高速化に必要なソフト一覧
- DMA転送 DMATURBO.R
- IOCS HIOCS.x
XM6GだとFDイメージのロードが早いが、68000 Zではわざと遅くしていそう。
そうなると今後はFDイメージの高速読込の方法が探されることになると思う(予想)
基本操作-CUI
CUI(キャラクターユーザーインターフェース)とは、文字だけで操作することです。
Human68kユーザーズマニュアルのPDFなどを手元で見られるようにしておきましょう。
STEP1
実機なら電源オンは本体から離れた機器から・・ポチポチペチポチポチフロッピードライブ、HDD、MO、midi、本体
電源オフは逆順・・・
X68000でHuman68kを起動させたら、下図のような画面が出ているはずです。
DIRと打ってみましょう。
これはディレクトリの略語で、ディレクトリとはWindowsで言うところのフォルダです。
現在の階層にあるファイルやフォルダの一覧を見ることができます。
ドライブの移動 a: b: c: など
ディレクトリの移動 cd a:\フォルダ名
ひとつ上に戻るcd ..
コマンドの一覧はHuman68kのユーザーズマニュアルにあります。
STEP2
電源を切ってみましょう。
ソフトを何も動かしていない(読み書きしていない)状態で電源スイッチオフ!
シャットダウンコマンドが無いです。
厳密には電源スイッチが押されたときの処理(trap#10)があるらしい。未確認。
Human68kの頃はフロッピーディスクからOSを起動していたので、そもそも終了時にOSのログファイルを更新する習慣が無かったのでしょう。
ただ、電源スイッチをOFFにしたときBIOS側か何かでtrap#10なる何かが走る?らしい。未確認。
補足として、実機でHDDを使っている場合は「BREAKキーを押して、HDDのヘッドを退避させてから電源を切る」が手順になります。HDD使ってなければ不要。
Human68kコマンドシェルの外部コマンド一覧
dir a:\bin\
ゲームで遊ぶ
フロッピーディスクのイメージファイルで提供されていることが多いです。FDDにメディアをセットしてリセットしましょう。
FDのイメージファイル内のAUTOEXEC.BATが実行されてゲームが始まります。
FDD2台のドライブレターがAとBになっているのを前提としたスクリプトが書いてあるので、ドライブレターを変えている場合は注意。
公開されているフリーソフト
X68000 LIBRARY ゲーム
http://retropc.net/x68000/software/games/
いくつかゲームをダウンロードできる
Vector X68000 ゲーム
https://www.vector.co.jp/vpack/filearea/x68/game
登録されているゲームがダウンロードできる
BM68
http://t-forth.gonna.jp/
音ゲー。BM98のデータをコンバートして使用できる。
JNetHack 1.0.x
http://nethack-users.osdn.jp/jnethack/
X68000 用の JNetHack 1.0.6
不思議のダンジョンみたいな親切なUIを想像していると爆散します
Duel Fighter 2
http://www.mugenunagi.com/products/games/df2/df2.html
Team無限うなぎが作った縦スクロールSTG、作るのに4年かかったらしい
バーンウェルト WinX68 版
http://www.quarter-dev.info/bw/bwmain.php
WinX68というエミュレータ環境向けに作られたゲーム
BREAKTHROUGH
http://hp.vector.co.jp/authors/VA012382/index.html
縦STG
アリスソフトアーカイブス
http://retropc.net/alice/
アリスソフトさんが出していた過去の商業ゲーム。
NOZ's FreeSoftWares for X68000
http://noz.ub32.org/68fsw.html
落ち物パズル
Z-MUSIC
http://www.z-z-z.jp/zmusic/
DTM。特定のMIDI機器を鳴らせるらしいが、実機勢にしか関係ない。
内臓音源でも遊べるらしい。
ZOOMの過去配布ソフト
http://web.archive.org/web/20031007225528/http://www.zoom-inc.co.jp:80/2001/download1.htm
ジェノサイドなど
くるんくるーぱ
https://github.com/raseene/X68_Kurunku
くるくるアクションパズル
YAMACO記念館
http://sysplan.nams.kyushu-u.ac.jp/gen/hobby/yamaco/history/history.html
戦車戦など複数のゲームが公開されている
うたくらホームページ
https://www.asahi-net.or.jp/~yy8a-imi/20040913/index.html
ルナ・レスキューの勝手移植など
世界征服セット(モアイソフト)
https://www.retrogamesoft.com/X68000_SSS.htm
パズルゲーム
BREAKTHROUGH
http://hp.vector.co.jp/authors/VA012382/index.html
STGゲーム
起動方法参考: https://moondoldo.com/wordpress/?p=2557
ときめく射的
https://circle-ay.info/danf3e68.zip
弾河
https://circle-ay.info/kmkm.zip
参考: ttps://x.com/circle_ay_ugm/status/1680785394122788870?s=20
ディレクトリ構成
工事中
拡張子の概要
-DIM WindowsバックアップおよびリカバリプログラムであるActive @ Disk Imageによって作成された生のディスクイメージバックアップファイル。要はFDのイメージファイル。
- X 実行ファイル
環境構築-XM6 ハード面
HDDイメージを作らないとストレージが無いに等しいので作ってください。
わたしは下記の記事を参考にしました。
https://ameblo.jp/alicemev/entry-12730351493.html
https://www.saoyagi2.net/diary/post_339.html
http://coexe.web.fc2.com/xm6.html
SCSIのHDDを認識したらAドライブがHDDになって詰むので、ドライブレターをDとかEとかFとか別のものにすると良いです。もしくはswitchコマンドで起動優先をフロッピーディスクに変更。
コマンド : DRIVE A: D:
コマンド : switch
環境構築-XM6 ソフト面
Human68kコマンドシェル用
テキストエディタ ED
プログラミング関係
→プログラミング(C言語) などを参照
音を鳴らす
→ZMUSICなど。ただしMIDIはエミュレータだとMIDI機器が使えないので選択肢に無い。当時は内蔵音源を鳴らすのが一般的。AMPCM音源(4bit)も使える。
BATファイルの書き方
- コメントアウト REM
他はリクエスト待ち。
Human68kの日常操作
GUIにすると楽なはずだが、そこはGUI勢が知っているはず。Human68kならHuman68kユーザーズマニュアルを参照。
CUIと言えばパイプライン処理や自作コマンドなので、Linux系OSのコマンドの使い方を参考にしよう。コマンドが足りないときは作るかBAT処理。
ゲームを作る-X68000上で作る
XCライブラリとLIBCの違い
https://twitter.com/kg68k/status/1602421276210970624?t=GqgZUYWJ1cXD60XqyfxdPA&s=19
libc本によると、LIBCの短所として実行ファイルが大きくなる、実行速度がやや遅い、商品ではない、X-BASICをサポートしていない、FLOATn.Xが必要、XC上で開発されたライブラリと互換性がない、というのが挙げられていました。FM音源やスプライトを用いたゲームを作るならXCを、ともあります。
描画の作法
X-BASICのマニュアルに描画の作法があるらしい。
→最初はIOCSコールを使ってCで画面モード設定、画面クリアとかしてグラフィックスを描画してみるとかでしょうかねー。その次にスプライトを出してみるとか。
→画面モードを設定しないとスプライトが出なかったり色数が変わったりしますね。上のソースはアセンブリ言語でしたが、IOCSCALLだとCRTMODでX-BASICだとSCREEN関数がそれにあたります。Cからの場合はどちらか呼べば使えると思います(要ヘッダのインクルードとライブラリのリンク)
→この辺りは98やMSXでも大差無かった頃かな? 用途に合わせた画面モードを指定して、描画やスプライト関連の関数を発行するという流れですが、画面モード類は皆さん書かれている通りX-BASICマニュアルの応用篇(35ページくらい?)に記載があると思います。
https://twitter.com/DD_samidare_kai/status/1602495584383815680?t=26OInab-jtrUJF2kfRepLg&s=19
https://twitter.com/DD_samidare_kai/status/1602496074882510848?t=6qYILqA7hnKuZDl1Tva_yw&s=19
エフェクト関連の話
音を鳴らす話
https://twitter.com/DD_samidare_kai/status/1602968627174522880?t=_h-g6wtjBn_nKWTujHmPXg&s=19
https://twitter.com/DD_samidare_kai/status/1602969024492552192?t=zGlVHsyWYGHFGC5TBEU7pQ&s=19
https://twitter.com/DD_samidare_kai/status/1602970505845215232?t=3T3xy4fj084c5viFx8UahA&s=19
参考本
GCCによるX680x0ゲームプログラミング : https://nfggames.com/X68000/Documentation/Books/X68000%20Game%20Programming%20with%20GCC%20(omnipage%20600dpi).pdf
私にとってそのものズバリな本
スプライトダブラー
X68000はラインバッファのため、ラインが通過した後の使用済みスプライトを再利用するテクニックがある。それはスプライトダブラーと呼ばれている。
スプライトダブラーの流れがライブラリ化されているらしい
XSP : https://github.com/yosshin4004/x68k_xsp
テキスト表示ライブラリ
FTX : https://github.com/yosshin4004/x68k_ftx
オープンソースのゲーム
男弾 : http://retropc.net/x68000/software/games/shooting/otoko/
PixelDotZero / X68000 : https://github.com/PixelDotZero/X68000
あって嬉しいSTGのソースコードなど。
ゲームを作る-Windowsで作ってクロスコンパイル
xdev68k を使用することでWindows上で開発し、X68000向けにクロスコンパイルできる。
xdev68k : https://github.com/yosshin4004/xdev68k
ゲームを作る-Windowsで素材作成
Tiled : https://www.mapeditor.org/
マップチップを使ったマップエディタ
PNG2PX2 : https://github.com/pirota-pirozou/PNG2PX2
pngファイルからX68000用スプライトエディタ「ぴくせる君」向けスプライト・パターンデータ「PX2」ファイルに変換する
ゲームを作る-Z-MUSIC-V2用ZMDファイルの準備
作曲ができない人にとって、X68000でゲームを作る上で最難関になる部分だろう。
Z-MUSIC V2は、音源の役割をしている。
FM音源を鳴らすためのファイルとして、ZMDを使用する。
ZMDファイルはZMSファイルをZ-MUSICでコンパイルして作成する。
ZMSファイルはZ-MUSIC用のMMLをテキストエディタを使用して書く。
そう、五線譜やピアノロールは使えないのだ。音を文字で書いて作曲することになる。
地獄度が非常に高い。
ZMDファイルができたら、今度はZ-MUSICに含まれているFUNC(X-BASIC用ライブラリ、C言語用も昔は存在していた)を利用してプログラム中で再生することになる。
ライブラリの内容はともかく、プログラム中からの使用はDirectSoundなどと極端には変わらないかもしれないが未検証なので不明。
ゲームを作る-Z-MUSIC-V2用ZMSファイルの作成
Z-MUSIC V2向けのMMLを書く。
MMLとは何か?(参考)
https://sites.google.com/site/yyagisite/zmcman
MMLで書いたZMSファイルは、ZMDRIVEというWindows用のソフトで再生できる。コンパイルしなくていいので非常に便利。
https://twitter.com/markun2/status/1360971951703871497
プログラミング-X-BASIC
使ってないので全然分からないが、呼べるライブラリはC言語と同じ。
速度は不利だがBASICなので構文が分かりやすそう(妄想)
プログラミング-C言語
コンパイラの違いについて
XCのコンパイラよりgccのほうが性能が良いらしい。
なので当時からgccとXCライブラリの組み合わせが多かったらしい。
ライブラリの違いについて
libcは超昔のANSI標準っぽいやつ。
XCはX68000専用ライブラリなので、スプライト機能の関数など専用関数がある。
GCC真里子版などでライブラリとして使う場合、XCはgnulib.lも必要だったりXCのバージョン違いがあったりするので注意。
両方のいいとこ取りをする方法がないか永遠に模索中。
速度はXCライブラリのほうが有利らしい。なのでゲームを作るならXCライブラリがいい(らしい)。
どの環境にも癖があるため、プログラミングそのものが初めてなら最初はX-BASICでいいと思う。公式のインストールでボリューム名称変更などは必要だが。
あとIOCSコール遅いのでHIOCS.X導入推奨らしい。
https://twitter.com/Awed_Urshy/status/1602800169552314368?t=wOCIGgj4Szbg5yl2PBw1yQ&s=19
https://twitter.com/GOROman/status/1602800969880068096?t=wVnSrma0ORCyKk-NHHg4eg&s=19
参考になった情報
https://hp.vector.co.jp/authors/VA004474/kowin/manual/kowin_p2.txt
https://sanohito.hatenablog.com/entry/2022/04/27/112207
環境構築-GCC真里子版-HAS-hlk-libc
【DL】
GCC真里子版 → X68000 LIBRALYからDL
HAS.X → X68000 LIBRALYからDL
hlk.r → X68000 LIBRALYからDL
LIBC 1.1.32A → X68000 LIBRALYからDL
【環境変数】
AUTOEXEC.BATのPATHにGCC真里子版のパスを通す。
AUTOEXEC.BATのラストに、
prompt $p$g
SET GCC_AS=has.x
SET GCC_LINK=hlk.r
SET GCC_NO_XCLIB=USE_LIBC
SET MARIKO=A
SET INCLUDE=a:¥libc32b¥INCLUDE
SET LIB=a:¥libc32b¥LIB
SET HAS=-u -w
SET GCC_OPTION=LFIOAM+
を追加する。
パスはそれぞれのディレクトリに合わせる。
has.xとhlk.rもパスが通ってないとダメだと思うので、AUTOEXEC.BATのPATHでパスを通しておくか、パスの通っているところに置くか、絶対パスにしておく必要があると思う。
ただしこのやり方だとiocslib.h関係が上手くリンクできなかった。stdio.hは問題ない。
よく分からない問題だが、まだ理解していないのでなんとも言えない。
→教えてもらった
https://twitter.com/DD_samidare_kai/status/1601993127388061696?t=-8NM-MGxW8nQDyr4FPZKpA&s=19
https://twitter.com/DD_samidare_kai/status/1601995238217633793?t=GS-x6Vxou4dVtM5t02PpDg&s=19
https://twitter.com/DD_samidare_kai/status/1602002145779146752?t=hSNxxK3E3x7tjp0lJwiXhw&s=19
https://twitter.com/Awed_Urshy/status/1602067848729604096?t=mVKhfIQ-J1gginLoQHphjQ&s=19
https://twitter.com/GOROman/status/1602073922266357760?t=BdvSTL72Or6-SXBtkKGZ5Q&s=19
問題の論点としては、このX68000時代はヘッダーファイルを使うときに対応する静的ライブラリを手動でリンクしてやるという『当時の常識』を知らなかったことだと思う。今は静的ライブラリはCのソースコードのみで完結するような配布のされ方をしているため(私の扱ったもの限定か?)、ヘッダーファイルに対応した静的ライブラリをリンクさせるという発想がなかった。
・GCC真里子版が空の配列定義に対応してない
・作業者が、ヘッダーファイルに対応する静的ライブラリのリンクを手動でするということを知らなかった。
今回がX68000で初の環境構築だったので、作業者が環境構築のミスだと思い込んでたからややこしくなってました。
その後 : https://twitter.com/swapout993/status/1602088367335710721?t=hHjuM7o5LRmp3AxBvywPTQ&s=19
https://twitter.com/DD_samidare_kai/status/1602118943786684417?t=KoU_ep_M8vpPWzPhXoZ51w&s=19
https://twitter.com/GOROman/status/1602112237690580993?t=ihowvTovj_wwQZZC2iBQ6w&s=19
https://twitter.com/GOROman/status/1602114470582841344?t=bN7zBa1ZW6Lf_rIrrWHeoA&s=19
https://twitter.com/swapout993/status/1602099811062231040?t=EWurjB7uW9G94oVvUsL6sQ&s=19
https://twitter.com/GOROman/status/1602079163619627009?t=UHXUTQ2TI3jZveQiheSK-Q&s=19
環境構築-GCC真里子版-HAS-hlk-XCライブラリ
参考 : https://sanohito.hatenablog.com/entry/2022/04/27/112207
【DL】
GCC真里子版 → X68000 LIBRALYからDL
HAS.X → X68000 LIBRALYからDL
hlk.r → X68000 LIBRALYからDL
C Compiler PRO-68K ver2.1(XC)(XCライブラリ) → X68000 LIBRALYからDL。ライブラリとして使うので必要なのはDISK2のINCLUDEとLIBディレクトリのみ。
libgnu : https://www.vector.co.jp/soft/dl/x68/prog/se023312.html (libgnu.a のみが必要)
変換BAT : https://drive.google.com/file/d/1UjMgIoLPc72xp4T28Vrz4nNb3zUTs-Mm/view (リンク元 https://sanohito.hatenablog.com/entry/2022/04/27/112207 )
(追記:変換BATですが対象にするlibgnuがVer1.50だとpatchlevel.oの記述も必要になります。コンパイル時に%や/や*でmodsi3.oやDIVやMULのエラーが出るなら ar /x libgnu.a patchlevel.o と lib /u _libgnu patchlevel.o を追記して対応してください)
libgnuのlibgnu.aを、変換BATで別形式に変換します。libgnu.aと変換BATを同じディレクトリに置いて、cdでそのディレクトリに行き、変換BATを実行します。大量のファイルと_libgnu.lができます。_libgnu.lのファイル名をgnulib.lに変更して、LIBのディレクトリに突っ込みましょう。
【環境変数】
AUTOEXEC.BATのPATHにGCC真里子版のパスを通す。
AUTOEXEC.BATのラストに、
REM GCCMARIKO & XCLIB
prompt $p$g
SET CC=A:\XC\CC
SET GCC_AS=has.x
SET GCC_LINK=hlk.R
SET GCC_LIB=.l
SET GCC_NO_XCLIB=
SET MARIKO=AB
SET include=A:\XC\INCLUDE
SET lib=A:\XC\LIB
SET HAS=-u -w
SET GCC_OPTION=LFIOAM+
SET DOSEQU=DOSCALL.MAC
SET SILK=-l floatfnc.l
を追加する。
パスはそれぞれのディレクトリに合わせる。
has.xとhlk.rもパスが通ってないとダメだと思うので、AUTOEXEC.BATのPATHでパスを通しておくか、パスの通っているところに置くか、絶対パスにしておく必要があると思う。
ここまで書いて心苦しいが、このままではリンカーのエラーでコンパイル完了ができない。どうすればいいか分からない。
→使用するヘッダーファイルに対応したライブラリファイルのリンク指定が必要でした。つまり環境としては正常に構築できていた。
環境構築-XC-HAS-hlk-XCライブラリ
C Compiler PRO-68K ver2.1(XC)(XCライブラリ) → X68000 LIBRALYからDL
HAS.X → X68000 LIBRALYからDL
hlk.r → X68000 LIBRALYからDL
C Compiler PRO-68K ver2.1(XC)(XCライブラリ)のインストールのためにドライブのボリューム名を変更する必要がある。XM6ならソフトウェアキーボードで日本語を打てる。
ボリューム名変更のコマンドはHuman68kのユーザーズマニュアルを参考にする。
手順:Disk1をA、Disk2をBにセットしてリセットから起動し、組み込み開始にNでノー。その後
vol a:
vol a:XCシステム#1/s (システムは半角カナ)
vol a:
vol b:
vol b:XCシステム#2/s (システムは半角カナ)
vol b:
ボリューム名を変更し終わったらAUTOEXEC.BATを叩いてインストール。
以上
役立つ自作関数例-キーボード入力
キーボード入力チェック : int BITSNS(int) // 補足として、BITSNSに引数を渡すときは変数を渡して下さい。リテラルを渡すとパスエラーが起きました。番外編として、キーのホールドへの対応は、直前のキー入力を保持して対応することになります。
面倒なので実装をヘッダーファイルに書いてしまいますが、キーボード入力周りの作り方の一例を示します。
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* keyboard.h
* @isimiya9
*
* #include <iocslib.h> // -liocs
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef KEYBOARD_H
#define KEYBOARD_H
/* * * * * * * * * * * * * * * * * * * *
* enum
* * * * * * * * * * * * * * * * * * * */
enum CTRLBTN {
BTN_START = 0, BTN_SELECT = 1,
BTN_LEFT = 2, BTN_RIGHT = 3, BTN_UP = 4, BTN_DOWN = 5,
BTN_A = 6, BTN_B = 7, BTN_C = 8, BTN_X = 9, BTN_Y = 10, BTN_Z = 11, BTN_L= 12, BTN_R = 13
};
/* * * * * * * * * * * * * * * * * * * *
* static global var
* * * * * * * * * * * * * * * * * * * */
static int keyCode[] = {0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0};
static int keyGrp[] = {0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0}; // need init
static int keyBit[] = {0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0}; // need init
static int keyGrpRes[] = {0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0};
static char isKbdSetting = false;
/* * * * * * * * * * * * * * * * * * * *
* updateKeyStatus
* * * * * * * * * * * * * * * * * * * */
static void updateKeyboardStatus(){
keyGrpRes[ 0] = BITSNS( 0);
keyGrpRes[ 1] = BITSNS( 1);
keyGrpRes[ 2] = BITSNS( 2);
keyGrpRes[ 3] = BITSNS( 3);
keyGrpRes[ 4] = BITSNS( 4);
keyGrpRes[ 5] = BITSNS( 5);
keyGrpRes[ 6] = BITSNS( 6);
keyGrpRes[ 7] = BITSNS( 7);
keyGrpRes[ 8] = BITSNS( 8);
keyGrpRes[ 9] = BITSNS( 9);
keyGrpRes[10] = BITSNS(10);
keyGrpRes[11] = BITSNS(11);
keyGrpRes[12] = BITSNS(12);
keyGrpRes[13] = BITSNS(13);
keyGrpRes[14] = BITSNS(14);
keyGrpRes[15] = BITSNS(15);
keyCode[BTN_START ] = keyGrpRes[keyGrp[BTN_START ]] & keyBit[BTN_START ];
keyCode[BTN_SELECT] = keyGrpRes[keyGrp[BTN_SELECT]] & keyBit[BTN_SELECT];
keyCode[BTN_LEFT ] = keyGrpRes[keyGrp[BTN_LEFT ]] & keyBit[BTN_LEFT ];
keyCode[BTN_RIGHT ] = keyGrpRes[keyGrp[BTN_RIGHT ]] & keyBit[BTN_RIGHT ];
keyCode[BTN_UP ] = keyGrpRes[keyGrp[BTN_UP ]] & keyBit[BTN_UP ];
keyCode[BTN_DOWN ] = keyGrpRes[keyGrp[BTN_DOWN ]] & keyBit[BTN_DOWN ];
keyCode[BTN_A ] = keyGrpRes[keyGrp[BTN_A ]] & keyBit[BTN_A ];
keyCode[BTN_B ] = keyGrpRes[keyGrp[BTN_B ]] & keyBit[BTN_B ];
keyCode[BTN_C ] = keyGrpRes[keyGrp[BTN_C ]] & keyBit[BTN_C ];
keyCode[BTN_X ] = keyGrpRes[keyGrp[BTN_X ]] & keyBit[BTN_X ];
keyCode[BTN_Y ] = keyGrpRes[keyGrp[BTN_Y ]] & keyBit[BTN_Y ];
keyCode[BTN_Z ] = keyGrpRes[keyGrp[BTN_Z ]] & keyBit[BTN_Z ];
keyCode[BTN_L ] = keyGrpRes[keyGrp[BTN_L ]] & keyBit[BTN_L ];
keyCode[BTN_R ] = keyGrpRes[keyGrp[BTN_R ]] & keyBit[BTN_R ];
}
/* * * * * * * * * * * * * * * * * * * *
* init keyboard setting
* * * * * * * * * * * * * * * * * * * */
static void initKeyboardSetting(){
// initialize keyboard setting
// file stream. check keyboard.ini
// set keyGrp[] keyBit
// kari setting
keyGrp[BTN_START ] = 4; keybit[BTN_START ] = 4; // G key get status (START)
keyGrp[BTN_SELECT] = 4; keybit[BTN_SELECT] = 8; // H key get status (SELECT)
keyGrp[BTN_LEFT ] = 3; keybit[BTN_LEFT ] = 128; // S key get status (LEFT)
keyGrp[BTN_RIGHT ] = 4; keybit[BTN_RIGHT ] = 2; // F key get status (RIGHT)
keyGrp[BTN_UP ] = 2; keybit[BTN_UP ] = 8; // E key get status (UP)
keyGrp[BTN_DOWN ] = 4; keybit[BTN_DOWN ] = 1; // D key get status (DOWN)
keyGrp[BTN_A ] = 4; keybit[BTN_A ] = 16; // J key get status (A)
keyGrp[BTN_B ] = 4; keybit[BTN_B ] = 32; // K key get status (B)
keyGrp[BTN_C ] = 4; keybit[BTN_C ] = 64; // L key get status (C)
keyGrp[BTN_X ] = 2; keybit[BTN_X ] = 128; // U key get status (X)
keyGrp[BTN_Y ] = 3; keybit[BTN_Y ] = 1; // I key get status (Y)
keyGrp[BTN_Z ] = 3; keybit[BTN_Z ] = 2; // O key get status (Z)
keyGrp[BTN_L ] = 3; keybit[BTN_L ] = 64; // A key get status (L)
keyGrp[BTN_R ] = 6; keybit[BTN_R ] = 1; // SPkey get status (R)
isKbdSetting = true;
}
/* * * * * * * * * * * * * * * * * * * *
* other keyboard FUNCTION'S
* * * * * * * * * * * * * * * * * * * */
#endif /* KEYBOARD_H */
役立つ自作関数例-文字列のTrim関数
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* util.h
* @isimiya9
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef UTIL_H
#define UTIL_H
#include <stdio.h>
#include <string.h>
int strTrim(char *dst, size_t dstsz, int beg, int len, const char *s){
size_t i;
size_t slen;
char *b; /* cut start */
char *e; /* cut end */
char *send; /* string end */
if(!dst || !dstsz || beg < 0 || len < 0 || !s){ return 0; }
slen = strlen(s);
b = s + beg;
e = b + len;
send = s + slen;
for(i = 0; i < dstsz - 1 && b < e && b < send; b+=1, i+=1){
if(*b == '\0'){ break; }
dst[i] = *b;
}
if(dst[0] == '\0'){ return 0; }
dst[i] = '\0';
return 1;
}
#endif /* UTIL_H */
役立つ自作関数例-iniファイル操作
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* inifile.h
* @isimiya9
*
* #include <iocslib.h> // -liocs
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef INIFILE_H
#define INIFILE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#define INIFILE_LINELEN 256
/**************************************
* ini file format
* [SECTION_NAME]
* KEY_NAME=VALUE
*
* [SECTION_NAME2]
* KEY_NAME=VALUE
**************************************/
/**************************************
* int getIniFileParamInt(in char *, in char *, in char *, out int *)
* Example :
* if(getIniFileParamInt(driveName, "[SECTION_NAME]", "KEY_NAME", &outValue) == 0){ error!; }
**************************************/
int getIniFileParamInt(char *iniFilePath, char *iniSection, char *iniParamName, int *outValue){
char *rp;
char *eqPnt;
FILE *inifp;
char line[INIFILE_LINELEN];
char stemp[INIFILE_LINELEN];
int cntSection, eqCnt;
cntSection = 0;
eqCnt = 0;
if((inifp = fopen(iniFilePath, "r")) == NULL){ return 0; }
while(fgets(line, INIFILE_LINELEN, inifp) != NULL){
line[strlen(line)] = '\0';
if(line[0] == ';'){ continue; }
switch(cntSection){
case 0 :
if(line[0] != '['){ break; }
if(strstr(line, iniSection) == line){ cntSection += 1; }
break;
case 1 :
if(strstr(line, iniParamName) == line){
eqPnt = strchr(line, '=');
eqCnt = eqPnt - line;
eqCnt++;
strTrim(stemp, sizeof stemp, eqCnt, strlen(iniParamName), line);
*outValue = strtol(stemp, &rp, 10);
cntSection += 1; // exit while
}
break;
default :
break;
}
if(cntSection >= 2){ break; }
}
(void)fclose(inifp);
if(cntSection == 0){ return 0; }
return 1;
}
/**************************************
* int getIniFileParamString(in char *, in char *, in char *, out char *)
* Example :
* if(getIniFileParamString(driveName, "[SECTION_NAME]", "KEY_NAME", outValue) == 0){ error!; }
**************************************/
int getIniFileParamString(char *iniFilePath, char *iniSection, char *iniParamName, char *outValue){
char *eqPnt;
FILE *inifp;
char line[INIFILE_LINELEN];
char stemp[INIFILE_LINELEN];
int cntSection, eqCnt, stempLen, len;
size_t i, outValueSz;
cntSection = 0;
eqCnt = 0;
outValueSz = sizeof outValue;
if((inifp = fopen(iniFilePath, "r")) == NULL){ return 0; }
while(fgets(line, INIFILE_LINELEN, inifp) != NULL){
line[strlen(line)] = '\0';
if(line[0] == ';'){ continue; }
switch(cntSection){
case 0 :
if(line[0] != '['){ break; }
if(strstr(line, iniSection) == line){ cntSection += 1; }
break;
case 1 :
if(strstr(line, iniParamName) == line){
eqPnt = strchr(line, '=');
eqCnt = eqPnt - line;
eqCnt++;
strTrim(stemp, sizeof stemp, eqCnt, strlen(iniParamName), line);
stempLen = strlen(stemp);
stempLen -= 1;
len = 0;
for(i = 0; i < stempLen && stemp[i] != '\0'; i++){
len++;
}
outValue[0] = '\0'; outValue[1] = '\0';
outValue[2] = '\0'; outValue[3] = '\0';
outValue[4] = '\0'; outValue[5] = '\0';
for(i = 0; i < outValueSz - 1 && i < len; i++){
outValue[i] = stemp[i];
}
cntSection += 1; // exit while
}
break;
default :
break;
}
if(cntSection >= 2){ break; }
}
(void)fclose(inifp);
if(cntSection == 0 || outValue[0] == '\0'){ return 0; }
return 1;
}
#endif /* INIFILE_H */
役立つ自作関数例-iniファイルの想定フォーマット
[KEYBOARD]
BTN_START=H
BTN_SELECT=G
BTN_LEFT=S
BTN_RIGHT=F
BTN_UP=E
BTN_DOWN=D
BTN_A=J
BTN_B=K
BTN_C=L
BTN_X=U
BTN_Y=I
BTN_Z=O
BTN_L=A
BTN_R=SP
[SECTION0]
KEY0=1
KEY1=2
KEY2=3
[SECTION1]
KEY0=9
KEY1=99
KEY2=999
チラつき対策
画面切り替えしてもチラつく→directxのようなダブルバッファはないので、vsync中に書き込まないとちらつきますよ? 当たり前だけど
vsync(垂直同期)に対して待てる仕組みがあるってこと?要確認。最悪、ワークメモリか何かに垂直同期信号を確認できるアドレスがあるのでは。
↓
垂直同期割込信号に対する割込関数を設定することで実現できる。
C言語(gcc真里子版)+XCライブラリであれば下記の通り。(関数の説明はXCのC言語ライブラリマニュアルにある)
ちなみにxdev68kでは多分書き方が違います。gccのバージョンによって割り込み関係の書き方が微妙に違ったりするので注意。これはコンパイラの問題。
(前略)
static void interrupt funcVerticalSync(){
// VSYNC割込時(V-BLANK開始時)の処理
// 割り込みに入ったらまず割り込み内で割り込み自体を禁止、使用するレジスタは退避。
// 処理が終われば割り込みを許可してレジスタを戻しブランキング終わるまで待つか、リターンしてメインに処理を復帰。
// VDISPST()を使っているとレジスタの退避や戻しはやってくれている?のでそのあたり不要かも。必要になったら検証が必要。
}
// VDISPST(割込時実行関数のアドレス, モード, カウンタ);
// モード: 0=垂直帰線期間をカウント、 1=垂直表示期間をカウント
// 垂直帰線期間はV-BLANK、垂直表示期間はV-BLANKが終わって描画を開始し始めるとき
// カウント: 何回目の信号でアドレスの関数を呼びに行くか。毎フレーム呼びたいなら1
VDISPST(funcVerticalSync, 0, 1); // Vertical Sync
(後略)
筆者が使っている画面モードの仕様
グラフィック画面は512x512の65536色
VRAMに書き込むデータは16bitカラー値
テキスト画面は1024×1024の16色
プレーン1から4まであり、その4枚の1bitずつ計4bitによりテキストカラーパレット0の色0番から15番で選択される。なのでカラーパレット0はテキストでは固定になる。
プレーン単位では1bitが1ドットに対応しているため1回の書き込みで16ドットの色変更が可能。
スプライト&BGは16パレット×16色
スプライト毎に参照するパレットを0番から15番で指定できる。0番はテキスト画面と共用なので注意。もちろんパレット指定は後からの切り替えも可能。
スプライトのデータとして書き込むのは4bitの色番号(0から15)。スプライトのスクロールのところに色パレットの指定があり、それが0から15で16種類。
色パレット×色番号=で256種類。透明色を除いて255色。透明色の色コードは0x0000。
スプライトもBGも共通して透明色がある。BGは名前からすると背景だが、実際には画面プライオリティ設定が初期値だとグラフィック面やテキスト面が後ろにある。
よって、BGに透明色で穴を開けて、グラフィック面とテキスト面に描画した内容を穴から除くように表示することもできる。
パレットと色
X68000での画像データだが、色は65536色が基本となる。
ここから画面モードによって、3つのパターンの管理方法になる。
- 65536色 → そのまま16bit使用される(グラフィック画面65536色モード)
- 256色 → 65536色のうち256色だけ使用される(パレット使用)(スプライト&BGでは16のカラーパレットを指定し、その中での16色から指定)
- 16色 → 65536色のうち16色だけ使用される(パレット使用)
画面ごとの使用できる色数は以下の通り。解像度との組み合わせに制限があるため結構面倒。
画面 | 65536色 | 256色 | 16色 |
---|---|---|---|
グラフィック | ○(選択) | ○(選択) | ○(選択) |
テキスト | ○ | ||
スプライト | ○ | ||
BG | ○ |
スプライトとBGの色パレット0番は透明色扱い。(グラフィックやテキスト画面でも0番が透明色かは未確認)
パレットはインデックスカラーのインデックスと思ってもらいたい。
パレットのアドレスは、VRAMとは別のアドレスにあるので注意。
- 例)グラフィックVRAMのパレット → $E82000 から
また、16bitカラー(65536色)だが、ビットの配置は以下の通り。
15-11 | 10-6 | 5-1 | 0 |
---|---|---|---|
G | R | B | 輝度 |
GRB配置で、それぞれ5bitずつ。残り1bitは輝度で、当時は計算が面倒だから使われていなかったらしい。
つまり実質15bitカラーである。また1word(wordは一度に処理するbit数のことでX68000では16ibtだ)は2byteである。
要は1word単位でドットバイドットになっている。
スプライトとBG
スプライトとBGは似ている。どちらも16x16または8x8のキャラチップで、サイズは設定中の解像度に依存する。
また、RAMは共有である。
メモリアドレスを叩けば特殊な設定もできるかもしれないが試していない。
共有RAMのアドレスは以下の通り。
共有なのでBG不要の時はスプライトがすべてを使う。
$EB8000 - | $EBA000 - | $EBC000 - | $EBE000 - |
---|---|---|---|
共有PCGエリア | 共有PCGエリア | BGエリア0 | BGエリア1 |
スプライトは以下の流れで使う。
//該当部分を自ソースから切り貼りしているので動作確認してません…動かなかったら連絡ください直します
static char ptn8_01[64] = {
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1 };
static char ptn8_02[64] = {
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2 };
static char ptn8_03[64] = {
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3 };
static char ptn8_04[64] = {
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4 };
static int plt01 = rgb(31, 0, 0);
static int plt02 = rgb( 0,31, 0);
static int plt03 = rgb( 0, 0,31);
static int plt04 = rgb(31,31, 0);
static int getPtCode(int tr, int hr, int color, int spat){
int ret = 0;
ret = ret + (tr << 15);
ret = ret + (hr << 14);
ret = ret + (color << 8);
ret = ret + (spat);
return ret;
}
int setSP(){
int tempInt;
// 初期化
SP_INIT();
SP_ON();
// スプライトパターン定義
sp_def( 1, ptn8_01, 0); // パターン定義番号1にptn8_01のパターンを8x8サイズとして登録
sp_def( 2, ptn8_02, 0); // パターン定義番号2にptn8_02のパターンを8x8サイズとして登録
sp_def( 3, ptn8_03, 0); // パターン定義番号3にptn8_03のパターンを8x8サイズとして登録
sp_def( 4, ptn8_04, 0); // パターン定義番号4にptn8_04のパターンを8x8サイズとして登録
// パレット定義
SPALET(1, 1, plt01); // パレットブロック1のパレットコード1にplt01の色を設定
SPALET(1, 2, plt02); // パレットブロック1のパレットコード2にplt02の色を設定
SPALET(2, 4, plt03); // パレットブロック2のパレットコード4にplt03の色を設定
SPALET(2, 5, plt04); // パレットブロック2のパレットコード5にplt04の色を設定
tempInt = getPtCode(0,0,1,1); // PTコードの生成
SP_REGST(1, 144, 144, tempInt); // スプライト設定。移動させるときは別関数SP_MOVEを使う。
tempInt = getPtCode(0,0,1,1);
SP_REGST(2, 160, 160, tempInt);
tempInt = getPtCode(0,0,2,1);
SP_REGST(3, 176, 176, tempInt);
tempInt = getPtCode(0,0,2,0);
SP_REGST(4, 192, 192, tempInt);
return 0;
}
BG1面のときは以下の流れで使う。
//該当部分を自ソースから切り貼りしているので動作確認してません…動かなかったら連絡ください直します
static char ptn8_01[64] = {
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1 };
static char ptn8_02[64] = {
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2 };
static char ptn8_03[64] = {
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3 };
static char ptn8_04[64] = {
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4 };
static int plt01 = rgb(31, 0, 0);
static int plt02 = rgb( 0,31, 0);
static int plt03 = rgb( 0, 0,31);
static int plt04 = rgb(31,31, 0);
static int getPtCode(int tr, int hr, int color, int spat){
int ret = 0;
ret = ret + (tr << 15);
ret = ret + (hr << 14);
ret = ret + (color << 8);
ret = ret + (spat);
return ret;
}
int setBG(){
int tempInt;
// 初期化
SP_INIT();
SP_ON(); // BGだけだと不要だけども
// スプライトパターン定義(PCGはBG共通なので)
sp_def( 192, ptn8_01, 0); // パターン定義番号192にptn8_01のパターンを8x8サイズとして登録
sp_def( 193, ptn8_02, 0); // パターン定義番号193にptn8_02のパターンを8x8サイズとして登録
sp_def( 194, ptn8_03, 0); // パターン定義番号194にptn8_03のパターンを8x8サイズとして登録
sp_def( 195, ptn8_04, 0); // パターン定義番号195にptn8_04のパターンを8x8サイズとして登録
// パレット定義
SPALET(1, 1, plt01); // パレットブロック1のパレットコード1にplt01の色を設定
SPALET(1, 2, plt02); // パレットブロック1のパレットコード2にplt02の色を設定
SPALET(2, 4, plt03); // パレットブロック2のパレットコード4にplt03の色を設定
SPALET(2, 5, plt04); // パレットブロック2のパレットコード5にplt04の色を設定
tempInt = getPtCode(0,0,1,1); // PTコードの生成
BGTEXTCL(0, ptCode); // BG0ページを同じパターンで塗りつぶす。別にやらなくてもいい
tempInt = getPtCode(0,0,2,2);
BGTEXTST(0, 15, 15, ptCode);
tempInt = getPtCode(0,0,2,3);
BGTEXTST(0, 16, 16, ptCode);
BGCTRLST(0, 1, 1); // BG0ページの表示設定ON. XM6Gだと第二引数が0でも1でも動くので何が正解か分からない
return 0;
}
BG2面同時使用のときは以下の流れで使う。
//該当部分を自ソースから切り貼りしているので動作確認してません…動かなかったら連絡ください直します
static char ptn8_01[64] = {
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1 };
static char ptn8_02[64] = {
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2 };
static char ptn8_03[64] = {
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3 };
static char ptn8_04[64] = {
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4 };
static int plt01 = rgb(31, 0, 0);
static int plt02 = rgb( 0,31, 0);
static int plt03 = rgb( 0, 0,31);
static int plt04 = rgb(31,31, 0);
static int getPtCode(int tr, int hr, int color, int spat){
int ret = 0;
ret = ret + (tr << 15);
ret = ret + (hr << 14);
ret = ret + (color << 8);
ret = ret + (spat);
return ret;
}
int setBG(){
int tempInt;
// 初期化
SP_INIT();
SP_ON(); // BGだけだと不要だけども
// スプライトパターン定義(PCGはBG共通なので)
sp_def( 128, ptn8_01, 0); // パターン定義番号128にptn8_01のパターンを8x8サイズとして登録
sp_def( 129, ptn8_02, 0); // パターン定義番号129にptn8_02のパターンを8x8サイズとして登録
sp_def( 192, ptn8_03, 0); // パターン定義番号192にptn8_03のパターンを8x8サイズとして登録
sp_def( 193, ptn8_04, 0); // パターン定義番号193にptn8_04のパターンを8x8サイズとして登録
// パレット定義
SPALET(1, 1, plt01); // パレットブロック1のパレットコード1にplt01の色を設定
SPALET(1, 2, plt02); // パレットブロック1のパレットコード2にplt02の色を設定
SPALET(2, 4, plt03); // パレットブロック2のパレットコード4にplt03の色を設定
SPALET(2, 5, plt04); // パレットブロック2のパレットコード5にplt04の色を設定
tempInt = getPtCode(0,0,1,128); // PTコードの生成
BGTEXTCL(0, ptCode); // BG0ページを同じパターンで塗りつぶす。別にやらなくてもいい
tempInt = getPtCode(0,0,2,129);
BGTEXTST(0, 15, 15, ptCode); // 第一引数に0を渡している点に注目、これがBG0ページの指定
tempInt = getPtCode(0,0,2,192);
BGTEXTST(1, 16, 16, ptCode); // 第一引数に1を渡している点に注目、これがBG1ページの指定
BGCTRLST(0, 0, 1); // BG0ページの表示設定ON
BGCTRLST(1, 1, 1); // BG1ページの表示設定ON
return 0;
半透明処理
半透明処理は画面のプライオリティ設定と半透明処理のアドレスに書き込みをして行うらしい。
Inside X68000などの書籍が詳しく説明しているらしい。
実行ファイルのパス
XCライブラリの場合、argv[0]が実行ファイルのフルパス名(パス区切りは)。
また、strsfn()関数で各情報を得られる。
LIBCの場合、argv[0]はHUPAIRで渡されたargv0が格納されるので確実ではない(HUPAIRでない場合はPSPから得られた絶対パスが格納される)。
LIBCでは、DOSなどの方法でパス名(パス区切りは\)とファイル名を得られる。
// XCライブラリ
#include <string.h>
char *driveName;
char *path;
char *exeName;
char *exeExt;
strsfn(argv[0], driveName, path, exeName, exeExt)
// LIBC
#include <sys/dos.h>
const char* path = _dos_getpdb()->exe_path;
const char* name = _dos_getpdb()->exe_name;
LIBCにSolarisのgetexecname()互換の関数を追加すると便利らしい。
要はプロセス管理ポインタ内の情報を参照しているだけなので、XCでもdoslib.hのGETPDB()を使えば同じらしい。
LIBCでもXC互換用のdoslib.hがあるので、そちらにすれば同じソースコードでどちらのライブラリでもコンパイルできるようになるかもしれないらしい。
型のサイズについて
X68000の型のサイズは以下の通り。
char | short | int | long |
---|---|---|---|
1byte | 2byte | 4byte | 4byte |
ゲームループについて_基本形
ゲームループとはゲームのループ処理である。
無限ループで実装されている。
正式名称があるかもしれないが、わざわざゲームループと言っているのには理由がある。
事務処理プログラムはAから始まってZで終われば終了だが、ゲームプログラミングではAからZまで終わったらまたAからスタートするのである。だってプレイヤーが終わるタイミングを決めるから。
無限ループを作るのは主に組込機器である。ゲームも当時は組込機器の一種だったので、その頃からの名残と言える。
ちなみに現在はソフト(アプリ)のライフサイクルがあるため、OS側のアプリ管理に組み込まれた形で無限ループを作っているため、厳密な意味では無限ループではない。
もちろんX68000の時点でも割込処理での強制リセットがあるため、たぶん厳密には無限ループではない。
さて、昔のゲームは基本的にたったひとつの無限ループを使用している。これである。
int main(){
// Game loop start
while(0){
}
// Game loop end
}
ここに各種の処理を追加していく。これは離散時間(デルタタイム)による座標計算とフレームバッファでダブルバッファでの形だ。
ちなみに現在ではトリプルバッファだと思うので、これももう古い形だ。
int main(){
// 初期化処理
// Game loop start
while(ゲーム終了フラグ == 0){ // フラグが立って1になったらループを抜ける
// 入力処理
// 計算処理
// 描画処理(裏画面に描く)
// 描画処理(画面の裏表を入れ替える)
}
// Game loop end
// 終了処理
}
ではX68000ではどうなのか?
垂直同期期間に描画するのである。もしくは垂直同期期間に画面の裏表を入れ替える。
これは当時の人に聞いた内容であるので、細かい違いはあれ、実際に使われていた構成だと思う。
ただ、具体的な処理構成の内容はまだ調査中なので間違っている部分があると思う。ご指導ご鞭撻のほどをいただければ幸いだ。
// 垂直同期割込関数
static void interrupt funcVerticalSync(){
// VSYNC割込時(V-BLANK開始時)の処理
// 描画処理(フレーム同期)
// 当時のSTGゲームのソースコードを確認したところ、描画処理では主に色パレットによる色変更によって行われている。
// グラフィック面に描くのは、どちらかというと非同期処理か裏表画面を入れ替える手法が多そうだ。
// なぜならCPUが遅すぎるため、全画面を1ドットずつ書き込むほどの計算量が確保できないためである。
// よって、無限ループ側でスプライトとBGの座標計算だけ行い、垂直同期割込で色パレット変更を行うのだろう。
}
int main(){
// 初期化処理
// VDISPST(割込時実行関数のアドレス, モード, カウンタ); // モード: 0=垂直帰線期間をカウント、 1=垂直表示期間をカウント
// 垂直帰線期間はV-BLANK、垂直表示期間はV-BLANKが終わって描画を開始し始めるとき
// カウント: 何回目の信号でアドレスの関数を呼びに行くか。毎フレーム呼びたいなら1
VDISPST(funcVerticalSync, 0, 1); // Vertical Sync
// Game loop start
while(ゲーム終了フラグ == 0){ // フラグが立って1になったらループを抜ける
// 入力処理(フレーム同期)
// 計算処理(フレーム同期)
// 計算処理(非同期)
// 描画処理(非同期)
}
// Game loop end
// 終了処理
}
ここにラスタースクロールやスプライトダブラーが加わると、水平同期の割込も使用することになる。
当時は割込処理が非常に重要だったのだろう。
シングルタスクのループ構成に割込処理が大量発生するため、かなり複雑である。
プログラミング-アセンブリ
このあたりの情報が役立つくらいまでいければ……。(願望)
しかしgccであったような環境構築などの問題が起こらないと思われるので、環境的にはある意味こちらのほうが楽かもしれない。
本は、環境ハンドブックがおすすめらしい。
https://stdkmd.net/hastips/
クロスコンパイル
基本的にはWindowsやLinux系OS上で、X68000用のGCCでコンパイルして変換することになる。
リンカーでリンクさせる対象についても変換してあればWindows上でリンクできるかなど未確認。そもそもGCCでコンパイルした後で変換しているのだから、変換後に対してそのままGCCでリンクできない気はする。未確認。
参考例
https://twitter.com/yunkya2/status/1601400566164619269?t=0BdNDl5MAW9IYwiThBH8mQ&s=19
xdev68k : https://github.com/yosshin4004/xdev68k
Macなら : https://zenn.dev/minatsu/articles/a9f8407d48531f
面倒な話-スプライトの実装内容
該当の話のリンク
https://twitter.com/isimiya9/status/1601062034145439745?t=qH3hozV6Z2aZHiLdjrV4ag&s=19
https://twitter.com/GOROman/status/1601131308423737345?t=_NOO7gD_ukCGpzlRDlDYow&s=19
https://twitter.com/GOROman/status/1601139197582405632?t=sqLaaj-9S0u8swY-gWsqzw&s=19
要はX68000のスプライトは、特定のアドレスに書かれたデータを、VRAMから出した後で画像合成用のカスタムIC(LSI?)内のロジック回路で処理している。画像合成用のカスタムIC(LSI?)からスプライトが合成された画像が出てモニターへ向かう。という設計になっている。VRAMに書き込む前にCPUで画像処理といった手法はしていない。CPUが10MHzなので、ドット単位の画像処理までCPUでやるのは不可能だったのだろう。当時のパーツで行える画像処理の最善の設計が、ロジック回路による画像処理だったのだ。もちろんロジック回路なので並列化が容易だ。
現在ではスプライトと言えば1つの画像を特定のサイズで区切って番号をつけるスプライトシートなどなので、今と昔ではスプライトの定義がまったく違うと言える。
面倒な話-知識体系
今とは必要な知識が違う
2022年現在ではC言語でゲームを作るときもDirectXをはじめとしたライブラリを利用するため、かなり概念的なプログラミングをすることになる。
一方で、70年代~80年代はCPUを直接使うのが一般的だったため、概念的なプログラミングが確立される前の時代だ。
そのため、C言語でプログラミングするとき、X68000であればCPUのMC68000の仕様を知っていることが必要となる。
例えばXCライブラリのTRAP15関数は、MC68000のCPUが持つフロー制御のTRAPを使っているラッパー関数だ。レジスタに設定する値を引数としているが、これはレジスタの内容を知っていないと使いようがない。厳密にはIOCSコールを呼ぶ正式な手順はCPUが持つTRAP命令だけであり、IOCSLIB.Hなどで使うIOCSコールもただのラッパー関数ということだ。このあたりの低レイヤーなライブラリ関数の使用方法は、CPU仕様を読んでることが前提となっている。なので、C言語で書く場合も、アセンブリの知識は持っておいた方がいい。これは2022年現在では、強力なハードと強力なライブラリがあるため当てはまらない話で、昔ならではと言える。
プログラマーの分類
強力なライブラリやフレームワークが登場したことにより、プログラマーの中で分類が分かれたと思われる。
- CPU仕様に対して直接プログラミングする人
- CPU仕様を理解した上でしか利用できない高級言語のライブラリを使用する人
- CPU仕様を理解しなくても利用できるライブラリを使用する人
- ハードウェアがラッパーにより包まれ、ハードを意識しない概念的なプログラミングをする人
- 概念的なプログラミングにより構築されたピラミッド上部のライブラリ(高レイヤー)を使う人
- 概念的なプログラミングで組まれたフレームワークを利用してプログラミングする人
こう考えると、仮想マシンに対してプログラミングするJavaあたりからはスクリプターとしての側面が強くなり、フレームワークを利用するあたりからはプレイヤーとしての側面が強くなっていると考えられる。
Javaあたりからはスクリプターとしての側面が強くなる。と書いていてふと思ったのだが、今のハードウェアを意識しないプログラミングは、スクリプト言語(の考え方と機能)が究極進化したため、プログラミング言語のように振る舞えるからプログラミング言語として扱われているだけなのかもしれない。→CPU自体が仮想化してるってのもあると思うよ。プログラムがプロセッサー内部のシーケンサーの回路切り替え信号じゃなくて、さらに分解されて別のアーキテクチャーのプロセッサで実行されたりしてんだもの
CPUの仕様
CPUの仕様はMC68000なので、MC68000とかMPU68000で検索しよう。
やってみて気づいたが、X68000のC言語用XCライブラリは、TRAP15を初めとして、CPUの割り込み動作の仕組みや、レジスタ仕様などを知っていることが前提になっている。真っ向勝負するならCPUの理解や動作の検証は避けて通れない。
IOCSコールについて
妄想だが、名称から予測するとIOCSコールの処理内容は基板のIPL-ROMというチップに焼かれていて、CPU側はTRAP命令を実行したときに見に行っているのではないかと思う。詳しいことは知っている人に聞くか、ハード側の仕様を読む必要がある。未確認。→タイマー割り込みは理解してますよね?タイマー回路のカウントアップ信号が入るとPCレジスタがスタックに積まれて登録された割り込み処理アドレスに飛ぶ。それをハード信号じゃなくてCPU命令で起こすのがTRAP。ちなみにTRAP 10が前に無いと言っていたシャットダウン処理→高速化したりマルチタスク化したりってドライバーがあるのは、ベクターを書き換えてROMに入ってるやつからリバースエンジニアリングして高速処理に書き換えたやつと丸々すげ替えてるんですよ
というわけで(?)、CPUの命令(ジャンプとかループとかだ)の一つとしてTRAP命令があり、レジスタの値で何番のベクター(アドレスの入ったレジスタだ)を見に行くか指定していると思われる。TRAP15は、CPUのTRAP命令と、TRAP番号のレジスタに15、という意味だろう。未検証。
C言語利用時に理解しておくべきこと
とにかくCPUが遅いため、高速化のためにアセンブリで書くことと組み合わせるのが良いように思う。そうなると下記の内容が必要になりそうだ。上から順にCPUに近くなり、無駄が無いことになりそうだ。
- CPUの命令(アセンブリ)
- IOCSコール(ラッパー関数ならこの位置、TRAPで呼ぶときはアセンブリ)
- DOSコール
- C言語のライブラリ
また、アセンブリはアセンブリで、処理内容をパズルのように組み合わせて最適化や高速化を行うことができるため(これはアルゴリズムの話だ)、アセンブリで書くときも知っているアルゴリズムにより実行速度は変わるだろう。
その他
- FDDのオートイジェクト → 実機では電源切ったときにFDがオートイジェクトされるらしい
- Breakキー → キーボードの謎ボタンの筆頭BreakキーだがX68000ではHDDの針の待避などするらしい。たぶん他にもあるはずだが未確認。
- メモリアクセス速度はメモリコントローラ任せで固定
- X68000 Human68Kを使わずにプログラムを実行する→ https://zenn.dev/morian/articles/ab313ec56c4c4f
エミュレータの妄想
なぜ妄想するか
プログラムによる実装で回路のエミュレータを作るのは大変だ。しかし実装について考えないと何が大変かは見えてこない。
そこで、X68000のエミュレータがやっているであろう実装について妄想する。68000 Zはどんな実装になっているのだろう。
メモリ周りの実装
ここは仕様を調べたり決めるのがメインだろうと思っている。例えばメインメモリ2MBでテキストVRAM 512KBでグラフィックVRAM 512KB でスプライトRAM 32KBでスタティックRAM 16KBなら、それぞれをエミュレータ側のメモリに確保するだけでいいと思う。高速化の方法は特に思いつかない。
CPU周りの実装
キャッシュとかは実行効率の話なので実装しなくていいと思っている。CPUの命令セットを、実行環境側の命令セットに置き換えて実行することになると思う。アドレス指定は、確保しているアドレスへの変換が必要になりそう。問題はCPUのbit数が違う場合だが、そこも変換になるだろう。
→キャッシュは無いらしい。キャッシュがないのとアセンブリでもループにコストがかかるため、ループを展開したほうが実行速度が稼げるらしい。テクニック名はそのまま、ループ展開。
描画周りの実装
大きな対応項目は2つある。ラインバッファへの対応と、各VRAMとスプライトの合成だ。
ラインバッファへの対応は、ラインバッファの処理をソフトウェアで再現する仕組みが必要になる。で、ソフトウェアラインバッファで作った画像データに各VRAMとスプライトの内容を合成してから、フレーム毎の最終データをフレームバッファとして扱う。で、そのフレームバッファを1枚だけデーンと画面描画すればいい。
各ハードウェアの実装
基本的にはRS-232Cなど各端子のエミュレーションになるのだろうが、実端子が無いなら実装不要の気がする。
他に何があるかX68000のことを調べないとよく分からない。
各ソフトウェアの実装
ICOSコールの実装?
ファイルシステムの再現はたぶん不要?
このあたりもよく分からない。
結論
よく分からない。
個人的なメモ
68000の確認事項
[ 検索語 ]
MC68000 datasheet
MC68000 schematic
MC68000 opensource
MC68000 schematic opensource
MC68030 datasheet
MC68030 schematic
MC68030 opensource
MC68030 schematic opensource
m68000 schematic
[ 資料検索語 ]
MC68000 16ビット マイクロプロセッサ ユーザーズマニュアル
MC68030 ユーザーズ・マニュアル MOTOROLA 1990年
[ トランジスタ数(Wikipedia調べ大雑把) ]
MC68000
7万 FPGA最近のやつならロジックセル5000でいけると思われる(最適化必要)
MC68030 30万 規模が大きすぎる。一人でやれる気がしない。
MC68040 120万 32bitだが規模が大きすぎる。いきなりやるのは無謀すぎる。
[ FPGA参考 ]
FPGA X68000 I/O Board for DE0-CV : https://github.com/kunichiko/FPGA-X68k-DE0CV-IO
インテル(アルテラ時代?)なので細かいところが参考にならないが、小さいFPGAで実装しているので参考になりそう。
https://github.com/noemi-abril/X68000_MiSTer-DE10-Standard
https://github.com/noemi-abril/X68000_MiSTer-DE1-SoC
TG68K.C : https://github.com/TobiFlex/TG68K.C
X68000ではなくCPUのMC68000のVHD。すごすぎて言葉にならない。
[ 基板参考 ]
68k-nano : https://github.com/74hc595/68k-nano
最小構成になってしまうし機能が色々無くなるが、FPGAなどで周辺回路(ほとんどカスタムLSIだが)を用意できれば夢がありそう。面白い。
[ 未確認 ]
https://github.com/gameblabla/x68000_playground
https://github.com/FedericoTech/X68KTutorials
https://github.com/Mikejmoffitt/png2xsp
https://github.com/kg68k/kg68k.github.io
https://github.com/vampirefrog/x68kfonts
https://twitter.com/AKIRAfromTASSz/status/1602236447116865536?t=bX6s3JXTkSReiqZ3patM7g&s=19
https://github.com/gaolay/MMDSP/blob/master/src/CONTROL.s
風の噂
X68000とかだとフロッピーディスクドライブをいくつもつなぐ人がいたため、そういう人たちはAT互換機初めて触ったときに、なんでフロッピー2台だと決めつけた!とか思ってたりしたらしい。
Human68kでは起動ドライブがAドライブとなるため、WindowsなどのHDDがCドライブになる使用に最初は慣れなかった人もいるらしい。
MS-DOS風使いづらい→Ita Tool Box とか fish.x を調べてみてください。自分はfishを使ってUnix風にして使ってました。→fishrcをちゃんと設定しないと内蔵コマンドはほぼないのでlsできなくて詰むとか起きますのでご注意をw
現代のOSの知識のみでHuman68k(実質MS-DOS)を手探りしようとしているのが(失礼な意味でなく)面白い。Linuxなんかからみれば、この時代のPC用OSは「ブートROMに入ってるIPLから多少の外部コマンドが起動できる」程度の環境です。何の資源も管理しないし、システムログなんか一切吐かないしw
自分も今も残ってるX68000実機ハードディスクやエミュレーション環境も20年間くらいの秘伝のタレ状態なので体系的とか経緯とか紐解かないと「いやー、動きますよ(オレの環境では)」となりがちwww
https://twitter.com/GOROman/status/1602115793168531456?t=6YsU25E381K9A5cNFVO5Qg&s=19
リロケータブル形式(拡張子が.R)な実行ファイルはあったけど、ライブラリを動的にリンクする仕様はそもそもなかったか。Windowsは.DLL(Dynamic Link Library)の概念あったけどMS-DOSはなさそう。MS-DOSをある種パクったHuman68kも同様か?
Windowsでもコマンドプロンプトから何かアプリを起動すると当該アプリ終了まではコマンドプロンプトはプロンプト「A>」を表示せず待機状態になると思います。
https://twitter.com/DD_samidare_kai/status/1602823216438779904?t=-MdIITe1t3j_RtCY5-j04A&s=19
https://twitter.com/gorry5/status/1602909630530990080?t=fcS0umOSZRcwbVjgEGzxKQ&s=19
BEEP音>PSG(プログラマブル・サウンド・ジェネレータ)>FM音源>MIDI音源(モジュール)>PCM(CDやmp3)みたいな感じでパソコンサウンドも進化して行きました。メモリが少ない時代、基本コンセプトは少ないパラメータで如何に多彩な音色を実現するか?みたいな感じでしょうね。
内蔵MIDIはない。(外部音源。MIDIボードも追加必要)ADPCM(モノラル)は、頑張れば鳴らしながら並行動作出来るが一度に転送できるデータ量は少ないので工夫が必要。効果音で使う想定。よってゲームの音楽は内蔵FM音源になります。
X-BASICにキーの押下状況を取得する関数がない!→当時の8bit機のBASIC、N-BASICなんかだとINPを使うのが決まり文句だったけれど、X-BASICはリアルタイムのキーボードの状態を調べることのがなくて、マイコンBASICマガジンの投稿作品でもジョイカード、マウスを入力とするのが多かったような、朧な記憶。
一応、Michael.Hipp氏が作成したMPEGオーディオデコードプログラムをX68000用に移植された方がおりまして、mp3play.x というもので再生可能ではあります。リアルタイム演奏をするには、ハイメモリとかなりのMPUパワーが必要とのことであまり現実的ではありませんが💦
今のようにメモリやマシンパワーが潤沢ではなかったですからね...X68000の場合ですと・音を構成するパラメタ(FM音源の設定)・(FM音源では難しい音の場合)必要な音階分のADPCMデータ・譜面データ(MML)を用意するのが普通でした。なので仰る通り、曲は自作するか、作れる人に頼むことになります
まあ当時画像圧縮してるのなんか見たこと無い。X68000だと使える圧縮形式はPICとMKIとMAGくらいだけど使ってたのはボーナスイラストくらいだな→https://twitter.com/SuperANIJA/status/1603358710318800896?t=Fuao4tNgBD-J9uyuvAlD6Q&s=19
→ゲームプログラムって元々は外部記憶装置無しの前提から始まってるじゃないですか。動画や音声がゲーム本編に組み込まれる時代(具体的にはCD-ROM^2登場)が来るまではその手法で間に合ってたわけですよ。PCというよりはマイコンだったわけです。→画像圧縮はしてましたがJPEGのようなアルゴリズムは重すぎて1枚表示するのに1分とか掛かるのでもうちょっと単純なアルゴリズム(ランレングスとか)でした。 柳沢氏のPICフォーマットがよく使われました。ゲームなどは各自独自でしたね。
X68000には文字コードで表示されるテキスト画面が存在しません。他のパソコンのグラフィック画面と同じくVRAMアドレスを計算して該当ビットに論理演算でビットを置けば何でも描画可能です。CUIの画面では2プレーンが仮想テキスト画面。2プレーンがマウスと仮想キーボードに見える様色調整されてます→普通のPCのテキスト画面は左上ならテキストVRAMの0番へフォントのコードを書けば左上に文字が出る仕組み。コレと同じ機構はX68000にはBG機能として搭載されていますがCUIには使われません。テキスト画面はキャラクターコードは使用できませんのでキャラクター面と言うには語弊がある感じがします。
そうです。テキストエリアのRAM領域が存在して、そのエリアでゴリゴリ書き換えながらアニメーションさせてます。パレットは同時発色が16色までなのですが、1枚毎にパレットも絵に合わせ書き換えてます。
gorry.haun.org/x68index.html
ゲーム用の画像リソースであれば、当時できてたことの大半はAPICGとEELでできます…今時の環境から持っていくならBMP/TGA/TIFFあたりかと。PNGが欲しければ今からportすればいいかな…gccなら問題なくビルドできる気はします
directxのようなダブルバッファはないので、vsync中に書き込まないとちらつきますよ? 当たり前だけど
パフォーマンス出すのに手っ取り早い方法は、graph.hを捨てることです。X68000のグラフィックは描画するのに論理演算必要としないしメモリマップドでバンク切り替えも無いので簡単ですよ
MPU 68000にはTRAPという命令があり、TRAP #15 (15番目)が呼び出されたときにIOCS CALLが作動するようにベクタが設定されています。→「d0レジスタにIOCS番号を設定してtrap #15」というのが本来の(唯一の)IOCSコールの呼び出し方法で、逆にそれ以外はすべてこれを使いやすくするためのラッパーです。上記の方法はアセンブラ命令を直接記述する必要があるので、例えばIOCSLIBはこれをCから関数呼び出しできるようにするためにあります→x86で言うとこのint命令がtrap命令で、所謂ソフトウェア割り込み命令ですね。処理が飛んでから特権モードになるのでモダンなOSでもシステムコールの呼び出しとかで使いますね。X68kでもI/Oとか特権モードで守られてるのでハードを叩くIOCSの呼び出しで使われてます。
タイマー割り込みは理解してますよね?タイマー回路のカウントアップ信号が入るとPCレジスタがスタックに積まれて登録された割り込み処理アドレスに飛ぶ。それをハード信号じゃなくてCPU命令で起こすのがTRAP。ちなみにTRAP 10が前に無いと言っていたシャットダウン処理。なんか良さげなのを見つけましたよ。ココ理解してないとTRAPについてナニ説明されてもチンプンカンプンだと思うので( https://www.slideshare.net/slideshow/embed_code/key/grWkUEhfsXU9Gr )→高速化したりマルチタスク化したりってドライバーがあるのは、ベクターを書き換えてROMに入ってるやつからリバースエンジニアリングして高速処理に書き換えたやつと丸々すげ替えてるんですよ
X68000勢の手持ちフロッピーディスクを見ていて気づいたけど、もしかして昔は、フロッピーディスクケースは無くて、紙の袋に入ってたの……?→不織布のパンツ履いてましたよ。→パンツ、保護性能はほとんど無いのでは……。→磁性体を手で触れないくらいですね。→わたしの知ってるフロッピーディスクは、磁性体のところに金属のシャッターのあるやつなのですが……→それは3.5インチですかね。5インチにはそんな機構はないですw単に磁性体の円盤にプラの側が付いてるだけなので、すぐ折れます。厚み2mmくらいw→他に「ディスケット」って呼ぶこともありますが確かこちらはIBMの商標だったかと。古い人はこっちで呼ぶ人も多いですね→ちなみに私の時代でも古より伝わる伝説の機器化していた部活のPC-8001のフロッピーは5インチ1Dで、当時でさえすでにメディアは売ってなくて、2Dのフロッピーにインデックスホールとライトプロテクトノッチをハサミで切り欠いて手動でひっくり返して両面使ってました
画面のスクリーンショットをハードコピーと呼ぶの、X68000時代やその近辺の頃なのか。確かに会社で使ってる人いた。→X68000はキーボードにCOPYキーがあって、押すとプリンタが動き出してハードコピーが始まりました(間違って押すとうざいwww→誰もが一度は通る道でしたねw公式だと、画面のキャプチャはSX-Window開発キットまで待たなきゃいけなかった感じですねぇ。プリンタドライバも何も無いから、大抵は絵を描いたり印刷するのって「お絵かきソフトや印刷ソフトを自分で書く」のとほぼ同義でしたなぁ。→そしてプリンターがつながっていません。の白帯が。
大抵のパソコンは、X,Y座標に色を置きたい時に、該当するVRAMアドレスの計算が凄く面倒で、カラーモードのビット数により該当するアドレス位置も変わってしまうんですが、X68000はVRAM構造を変えることで、カーモードが変わっても、X,Y座標を示すアドレス位置は変わらないという利点がありましたね。反面、他機種であれば16色(4bit)のドットを4pixel分まとめて16BITレジスタで一気に書き込んだりも出来るんですが、X68は16色モードでも16BIT幅使うので、色数が多くても少なくても速度は同じという弊害が…😭なので6万色モードで16色4ドット分(16BIT)を書き込んで16色モードに戻す技が生まれたとか😅とはいえ、厳密に言えば当時の国産PCは水平型のVRAM構造で横方向8bit単位のアクセスでしたから、更に面倒な処理が多かった記憶があります(X1時代)。X68のような垂直型のVRAM構造で1ドット単位に色コードをダイレクトに指定できる仕様を見た時は、物凄く感動しましたね~
shortとintとどちらが実行効率良いのでしょうか?→本当に速くする必要がある場所はアセンブリが普通だったので、コンパイラでどの程度差があったかは覚えていません。エミュレーターだとまた事情が変わってくる可能性も。→あー。速いプログラムにしたいと言ってるのにC言語のみって時点で『おかしい人』なんですね汗→当時はそういう感覚だったと思います。今それを追体験するメリットがあるかはわかりません。
FM音源にはMMLなるものを使うのかー。難しすぎない?→楽譜があれば、ツールでMMLへの置き換えが容易にできたりします。慣れてくれば、楽譜が無くてもできますし。音色等をダイレクトに変調するとなると、YM2151のレジスタ弄ったりと、一気に難易度が上がりますが(^◇^;)→ツール?ZMUSICとかでしょうか?レジスタ直いじりは辛すぎますね汗→頻繁に使う機能はマクロでコマンドが用意されてますので、ほとんどの場合はそれ使えば間に合いますね。zmusicの曲データはテキスト形式で配布を推奨されてたのでエディタで確認できますよ。mdxとか他のドライバの曲データはmmlからコンパイルしたバイナリ形式で配布されてた
(X68000ではなくファミコンの動画を観て)ラスタースクロールだけど、そもそもラスタースクロールって計算しなくてもラスタースクロール用の計算済みテーブルでやれないだろうか。上下ずらしのパターンをすべてテーブルで持ってればものすごく軽快にラスタースクロールできそうだけど。→8bit世代だと毎ラスター割り込みで処理する事自体が凄く重いし、ファミコンの話だとすると、そもそもラスター割り込みがないので0番スプライトの表示ステータス監視しながら表示位置を移動して……っていう、ベースラインでめちゃくちゃコストが高いです。→ラスターの検出割り込み自体は通称「0爆弾」で可能ですが、それをライン毎に仕掛けるのはコストが大きすぎるので、普通は「発火した後はライン毎の変更になるように実行クロックを数えながらつじつまを合わせる」ので、その間はCPUはかかりっきりになります (例)https://note.com/karu_gamo/n/n58bd3cde35eb
グラディウスのレーザーってどうやって実装してるんだろう…?スプライトだと枚数制限あるから、BGのチップにレーザー用の何かを持ってるのだろうか?昔のゲームを昔の環境で作ろうとすると謎がいっぱい出てくる。こういう謎の実装ばかりを解説した本ってないのだろうか。欲しい。→「伝説のアーケードゲームを支えた技術」という本は買いました。グラディウスは掲載されていませんが、いくつかの古いゲームで、当時の制約の中での工夫とかが面白い内容です。→アーケードがBG。ファミコンがスプライト。X68000がテキスト画面。→ファミコンでグラディウスの長いレーザーを再現した人のツイートttps://twitter.com/Nao_u_/status/1388324811986722820
ドット(ピリオド)を「ポツ」と読む文化がどこから来たのか気になる。→「・」(中黒)は「なかポツ」と呼ばれることもあったりするように、ポツ(ポチ)は日本語由来です。URLを書くようになって「ドット」が輸入・定着したイメージです。1980年代にBASICのファイル名、拡張子に .BAS だの .n88 だの付けてたけど、日本人で「ドット」なんて読んでた人はまずいません。(英語圏の人とやりとりしてた人は別)
草の根BBSはいつから草の根BBSと呼ばれてたの?→https://twitter.com/csharpVtuber/status/1644650964908150784?s=20
FATが大文字縛りの理由→https://twitter.com/ohta8801/status/1646830088141541377?s=20
「disる」を「disassembleする」という意味合いで、主にX68k界隈で使っていた(dis.xに由来)
北海道で、X68000系BBSといえば、南京とMoaiとFunky核爆ネットと趣味人くんのとこ(名前忘れた)?
操作逆引きリスト
- ファイル新規作成(最後にCTRL+ZとEnterで終了) copy con [新規ファイル名] 例:copy con sample.txt
- テキストファイル内容の表示 type [ファイル名] 例:type sample.txt
- ファイル検索 where /f [ドライブ名][検索対象ファイル名] 例:where /f a:\makefile なお、whereコマンドのfオプションは、発見したファイルのPATHだけでなくファイル名も出力するスイッチです。付けないで実行すると直前のPATHのみ出力されます。
- PATHを通す AUTOEXEC.BATにあるPATHにパスを追加する。初回読込で決まるため、起動ドライブのAUTOEXEC.BATに書くのが良い。筆者は変更したらリセットして再適用しているが、他に方法があるかもしれない。
- 環境設定 switch Human68kの環境変数設定みたいなやつ。搭載メモリの選択などがある。この頃は搭載メモリを自分で指定する世界だったらしい。メモリの動作クロック設定とかはどうなっていたんだろう?未確認。 → 確かswitch.xで行った設定内容が本体内のSRAM(16KB)に保存されたと思います。設定変更する事で、このSRAMもRAMディスクとして使えましたが、なにぶん容量が
- ドライブレターの変更 (例)AドライブのドライブレターをDに変更 DRIVE A: D:
- フォルダコピー copyall <コピー元ディレクトリ> <コピー先ディレクトリ>
- 文字コード変換 SJISとUTFの相互変換は何かソフト探すといい x68ksjis : https://github.com/vampirefrog/x68ksjis
- 日本語入力 XM6で実キーボードから日本語入力ができない場合、ツール?からソフトウェアキーボードを出して、ソフトウェアキーボードで入力したらいける。また、日本語入力モードにはいるのは、CTRL+XF1。→辞書データは別なディスクなのでよろしくw→SX-WINDOWの辞書ディスクですかね?そのあたりも環境構築の手順としているかもですね。→はい。それに対し手CONFIG.SYSのASKの設定で辞書データの指定が必要です→元々は独立した辞書データのディスクとして添付されていたのですが、公開されてるのはSXWinの一部になってますね
- X68000のOPMDRVについての考察|あうぇっど : https://note.com/nankin68000/n/nba5591db6737?sub_rt=share_h
- そもそもUNIX系コマンド動かすためにとぅえにぃわんが産まれた
- 当時のパソコン通信ではLinux系コマンドも出回っており、GNUのFSWの移植が多かった。