<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>r-srd.net</title>
<link>https://www.r-srd.net</link>
<description></description>
<generator>Zola</generator>
<language>ja</language>
<atom:link href="https://www.r-srd.net/rss.xml" rel="self" type="application/rss+xml"/>

  <lastBuildDate>Mon, 13 Jul 2026 00:00:00 +0000</lastBuildDate>


<item>
  <title>落ち着いた感</title>
  <pubDate>Mon, 13 Jul 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260713/</link>
  <guid>https://www.r-srd.net/posts/20260713/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260713/">
    &lt;p&gt;n2kd v1.0a の beta 版じゃないやつを公開して、何だか久々に肩の荷がちゃんと下りたような感覚があった。
n2kd の実装したい機能がなくなった訳でもないし、公私どちらでも今後すべきことはまあ色々と視界にちらついてはいるのだが、兎に角、落ち着いたように感じられた。
こういう時、次に何をすると決めるべきだろうか。
ここで大仰なことを考えると自分の場合大抵碌なことにならないのだ。
第一、昨秋の体調不良以来、もう無理を押すようなやり方は自分にはできないという感覚がある。
事後を考慮に入れなければあと 1 回くらいは無理できそうだが、それは何か別の大切な時のために残しておくのが良いだろう。
そうすると、そんなに大変じゃないことをやるか、大変なことを大変じゃない程度に細切れにしてやるか……。
特に思い浮かばないので、暫く前に修理から戻ってきていた OM-1 の空シャッターを切って寝た。&lt;/p&gt;

  </description>
</item>

<item>
  <title>n2kd FM Driver v1.0a（beta じゃないやつ）</title>
  <pubDate>Sun, 12 Jul 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260712-n2kd-v10a/</link>
  <guid>https://www.r-srd.net/posts/20260712-n2kd-v10a/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260712-n2kd-v10a/">
    &lt;p&gt;今年 01/03 に &lt;a href=&quot;https://www.r-srd.net/posts/20260103-n2kd-v1-0a-beta-1/&quot;&gt;v1.0a (beta 1) を公開&lt;/a&gt;してから、追加で 14 回目の更新、漸く n2kd FM Driver の v1.0a の公開に到達した。
v1.0a (beta 1) の時点では、それなりの完成度になっていると勝手に思っていたのだが、M3 2026 春向けの曲を作るのに実際に使ってみると、色々とボロが出てきて beta が外れるまでに結構時間がかかってしまった。
印象に残っている作業を挙げると、SB16 及び SBPro でのテンポ管理機能の導入と廃止、MML ドキュメントの HTML 版作成、MML コンパイラの最適化だろうか。&lt;/p&gt;
&lt;p&gt;SB16 及び SBPro によるテンポ管理は、PC/AT 互換機で SB の PCM 再生機能による定期的な割込を利用して楽曲を演奏しようという試みだった。
PC/AT 互換機では、自由に使えるタイマの数があまり多くないので、OPL3 があるならまず間違いなく同時に存在するであろう SB の PCM 再生機能をテンポ管理に使えれば、結構ありがたいんじゃないかという思い付きが切っ掛けである。
実装してみると最初はなんかそれっぽく動いている雰囲気だった。
しかし、ちゃんと検証すると、環境によってテンポが違ったり、楽曲途中でのテンポ変更がうまくいかなかったりと問題があることがわかった。
試行錯誤したが解決することができなかったので、最終的にこの機能は撤廃することにした。
というわけで、現状 PC/AT 互換機版では演奏時のテンポ管理に使えるタイマは i8253 PIT のみである。&lt;/p&gt;
&lt;p&gt;MML ドキュメントの HTML 版は、あるといいかなあ、とずっと思って作っていなかったのでこの機に作ったものである。
MML ドキュメントは元々手書きのプレーンテキストのものを配布物に含めていたが、整形を全部手動かつ気分で行っていたため、Markdown とはあまり近しくない雰囲気になっていた。
本 Web ページは Zola で作っているので Markdown 版の MML マニュアルが欲しかったが、
同等の Markdown を別に用意して 2 つの文書を維持するのは、面倒なのでやりたくなかった。
もにょもにょ悩んだ結果、原本になる Markdown を 1 個書き、それを Pandoc で変換して、プレーンテキスト版と HTML 用の Markdown 版の MML マニュアルを生成することにした。
Pandoc は、Lua で書いた独自の filter と writer を読み込ませて変換時に所望の処理を行わせることができる。
元々書いていたマニュアルに雰囲気が近くなるようなプレーンテキスト版用と、Zola に上手く食わせられる Markdown 版用の filter と writer をそれぞれ作って、なんとかした。
大変だった。
成果物のHTML 版 MML マニュアルは&lt;a href=&quot;https://www.r-srd.net/n2kd/n2kc-mml/&quot;&gt;ここ&lt;/a&gt;にある。&lt;/p&gt;
&lt;p&gt;MML コンパイラの高速化は、&lt;a href=&quot;https://www.r-srd.net/posts/20260429-petit-prof-v01a/&quot;&gt;ここで作った Petit Profiler&lt;/a&gt; が滅茶苦茶役に立って捗った。
コンパイル対象の MML の内容にもよるが、運が良い場合なら最初の実装に比べて 6 割弱くらいのコンパイル時間まで高速化させることができた。
保守しないといけないコード増えるので避けたかったが、一部どうしても遅い関数はアセンブラ化した。
高速化の余地が残っていない訳ではないが、少な目の労力で結構高速化する部分は大体手を入れてしまったので、以後、高速化はあんまり積極的には行わないつもりである。&lt;/p&gt;
&lt;p&gt;今後の計画の優先度高めのところとしては、PC-9801-118 の OPL3 部分対応と、OPN 及び OPNA 対応を考えている。
が、特に急ぎとも思っていないため、いつ完成するか皆目見当もつかない。
それでも、完成した後で曲を書けるくらいに元気なうちには達成したい。&lt;/p&gt;

  </description>
</item>

<item>
  <title>EGC のブロック転送</title>
  <pubDate>Sat, 20 Jun 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260620-egc-blkxfer/</link>
  <guid>https://www.r-srd.net/posts/20260620-egc-blkxfer/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260620-egc-blkxfer/">
    &lt;p&gt;&lt;a href=&quot;https://www.r-srd.net/posts/20260613-hr11-v1-0a/&quot;&gt;HR11 初出記事&lt;/a&gt;で、HR11 では EGC よりも GRCG を多用していること、EGC は 2 倍表示中の表示範囲変更の際のブロック転送にしか使っていないことを書いた。
もともとは、全部 GRCG で処理できるならばそうしてしまいたい気持ちはあった。
EGC の使い方に関する情報はあまり多くなく、自分でもその機能の理解には曖昧なところがあり、EGC を使った処理を書くならば絶対に実験から着手せねばならないことが想定されたからだ。&lt;/p&gt;
&lt;p&gt;そういったことを頭の隅に置きながら実装を進めたが、やはり 386 や 486 にとってハイレゾの VRAM は広大だった。
また、プレーン方式であるため読み書きの位置がバイトまたはワード境界に乗らない場合にはシフト演算も必要となり更に処理時間が嵩んでしまう。
幾らか覚悟はしていたが、EGC を利用したブロック転送ルーチンの実装は必至のようだった。&lt;/p&gt;
&lt;p&gt;で、参考資料 &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; を見ながら実装してみたところ、今回のブロック転送の目的である 2 倍表示中の表示範囲変更では転送に際する VRAM データ加工は不要なので、ROP の設定は大したことなかったが、転送開始位置と転送回数の設定がなかなか上手くいかなかった。
数日苦しんだ結果、転送の設定についてはどうやら以下の 2 点に注意すれば大丈夫なようだとわかった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;転送先の領域全体をカバーするワード数が転送元よりも大きい場合は、その分余計に転送が行われるようにする。&lt;/li&gt;
&lt;li&gt;最初のリードで得られるビット数が、最初のライトで書き出されるビット数より少ない場合は、その分余計に読み込みが行われるようにする。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;つまり、以下のようにする。
転送にはストリング命令を使うことを想定している。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;転送方向に依らない事前の共通の計算。
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;src_bit_pos = 転送元ビット位置;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dst_bit_pos = 転送先ビット位置;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;n_xfer_bits = 転送ビット数;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;転送ワード数を、src 全体を読み取るのに必要なワード数で初期化。&lt;br&gt;
&lt;code&gt;n_xfer_words = ((src_bit_pos &amp;amp; 0x0f) + n_xfer_bits + 15) / 16;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;src 領域と dst 領域のワード境界の位置を求める（バイト単位の偶数値での表現であることに注意）。&lt;br&gt;
&lt;code&gt;src_word_pos = (src_bit_pos / 8) &amp;amp; ~1;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dst_word_pos = (dst_bit_pos / 8) &amp;amp; ~1;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DF = 0&lt;/code&gt; で転送する場合。
&lt;ol&gt;
&lt;li&gt;ビットアドレス計算。&lt;br&gt;
&lt;code&gt;src_bit_addr = src_bit_pos &amp;amp; 0x0f;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dst_bit_addr = dst_bit_pos &amp;amp; 0x0f;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;src 及び dst の転送で最後に転送されるワード位置の計算。&lt;br&gt;
&lt;code&gt;src_last_word = (src_bit_addr + n_xfer_bits - 1) / 16;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dst_last_word = (dst_bit_addr + n_xfer_bits - 1) / 16;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;転送位置及び転送回数の調整。
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;src_bit_addr == dst_bit_addr&lt;/code&gt; の場合は追加処理不要。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src_bit_addr &amp;lt; dst_bit_addr&lt;/code&gt; の場合は &lt;code&gt;n_xfer_word += (dst_last_word - src_last_word);&lt;/code&gt; する。&lt;br&gt;
最初のリードで dst に書き出されるビット数以上読み込める場合、dst 末尾がワード境界をはみ出すことがある。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src_bit_addr &amp;gt; dst_bit_addr&lt;/code&gt; の場合、最初のリードで得られるビット数が最初の書き出しに必要なビット数より小さい。&lt;br&gt;
&lt;code&gt;dst_word_pos -= 2;&lt;/code&gt; して、事前に 2 回リードしてデータが揃ってから dst に書き出されるよう、dst を 1 ワード減らす。&lt;br&gt;
さらに &lt;code&gt;n_xfer_words += (dst_last_word + 1) - src_last_word;&lt;/code&gt; する。この 2-c-iii のケースでは、転送中は dst が src よりも 1 ワード遅れて書かれていくので追加の書き出しが必要な場合がある。
即ち、dst 冒頭位置を 1 ワード減らしたので、dst 側は &lt;code&gt;(dst_last_word + 1)&lt;/code&gt; 回目の転送を最後の転送としなくてはならないが、&lt;code&gt;n_xfer_word&lt;/code&gt; を src 全体を読み取るのに必要なワード数として求めているので、src 側の最後の転送である &lt;code&gt;src_last_word&lt;/code&gt; 回目の転送が dst 側にとって足りないならば転送回数を増やす必要がある。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src_word_pos&lt;/code&gt; から &lt;code&gt;dst_word_pos&lt;/code&gt; に、高位のアドレス方向に &lt;code&gt;n_xfer_word&lt;/code&gt; 回ワード単位で転送する。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DF = 1&lt;/code&gt; で転送する場合。
&lt;ol&gt;
&lt;li&gt;ビットアドレス計算（転送領域末尾から、その直前のワード境界までの距離）。&lt;br&gt;
&lt;code&gt;src_bit_addr = (src_bit_pos &amp;amp; 0x0f) ? 16 - (src_bit_pos &amp;amp; 0x0f) : 0;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dst_bit_addr = (dst_bit_pos &amp;amp; 0x0f) ? 16 - (dst_bit_pos &amp;amp; 0x0f) : 0;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;src 及び dst の転送で最後に転送されるワード位置の計算。&lt;br&gt;
&lt;code&gt;src_last_word = (src_bit_addr + n_xfer_bits - 1) / 16;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dst_last_word = (dst_bit_addr + n_xfer_bits - 1) / 16;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;転送位置及び転送回数の調整。
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;src_bit_addr == dst_bit_addr&lt;/code&gt; の場合は追加処理不要。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src_bit_addr &amp;lt; dst_bit_addr&lt;/code&gt; の場合は &lt;code&gt;n_xfer_word += (dst_last_word - src_last_word);&lt;/code&gt; する。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src_bit_addr &amp;gt; dst_bit_addr&lt;/code&gt; の場合、&lt;code&gt;dst_word_pos += 2;&lt;/code&gt; して、2回のリードで dst に書き出すデータが揃ってから dst に書き出されるよう dst を 1 ワード増やす。&lt;br&gt;
さらに、転送中 dst が 1 ワード遅れて書かれるので追加の書き出しが必要な場合のために &lt;code&gt;n_xfer_words += (dst_last_w + 1) - src_last_word;&lt;/code&gt; する。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src_word_pos + n_xfer_words * 2 - 2&lt;/code&gt; から &lt;code&gt;dst_word_pos + n_xfer_words * 2 - 2&lt;/code&gt; に、低位のアドレス方向に &lt;code&gt;n_xfer_word&lt;/code&gt; 回ワード単位で転送する。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;上記の処理は 1 ライン分の転送なので、これを縦方向に反復すればブロック転送が実現できる。&lt;/p&gt;
&lt;p&gt;2-c-ii は割と直ぐ気づいたものの、2-c-iii を把握するにはちょっと時間がかかった。
多分合っている筈……なのだが、動くようになるまで割と紆余曲折したのもあって微妙に自信がない。
とは言えど、纏めてしまえばまあ納得の挙動という感じで何だかあっけないような気もするのだった。&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://web.archive.org/web/20070826134023/http://www2.muroran-it.ac.jp/circle/mpc/program/pc98dos/index.html&quot;&gt;PC98 DOSプログラミング ハードウェアバリバリ編 (Internet Archive)&lt;/a&gt; &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://jhalfmoon.com/dbc/2023/10/17/%E8%AA%98%E3%81%86pc98%E4%BA%92%E6%8F%9B%E6%A9%9F5-gdc%E3%81%A0%E3%81%91%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8Fegc%E3%82%82%E3%81%82%E3%82%8B/&quot;&gt;誘うPC98互換機(5) GDCだけではなくEGCもある&lt;/a&gt; &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://seesaawiki.jp/asem9821/d/EGC%A4%CE%A5%A8%A5%DF%A5%E5%A4%C8%BC%C2%B5%A1%A4%CE%B0%E3%A4%A4&quot;&gt;EGCのエミュと実機の違い&lt;/a&gt; &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

  </description>
</item>

<item>
  <title>PC-98 ハイレゾ機種専用お絵描きソフト作成</title>
  <pubDate>Sat, 13 Jun 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260613-hr11-v1-0a/</link>
  <guid>https://www.r-srd.net/posts/20260613-hr11-v1-0a/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260613-hr11-v1-0a/">
    &lt;p&gt;以前「PC-98 ハイレゾ専用プログラムを作るというのは面白い事だと思う」といったことを&lt;a href=&quot;https://www.r-srd.net/posts/20260328-hires-font/&quot;&gt;書いた&lt;/a&gt;ので、実践してみた。
ハイレゾ専用という条件から、題材は自然と画像関係に傾き、お絵描き用のソフトウェアを作ることにした。
ここのところ暫く作業を行って、機能はまだ少ないが最低限取り敢えずの絵を描けるようになった。&lt;/p&gt;
&lt;p&gt;取り扱える画像の解像度はノーマルモードと同じ 640 × 400 固定とした。
ハイレゾ解像度の画像はノーマルモードでは全体を一度に表示できないし、解像度を可変にするのは正直実装が億劫でバグりそうだったのでやめた。
また、上側と下側の 2 つだけとはいえ、レイヤ機能を実装しようと思っていたが、ハイレゾ解像度だとコンベンショナルメモリが足りないのだった。
レイヤを、4 プレーンの画像データ 2 組と、上のレイヤの透過判定用 1bpp マスクで実装する場合 9 プレーン必要になる。
ハイレゾ 1 プレーンが &lt;code&gt;1120 * 750 / 8 = 105000 ≒ 102.5 KiB&lt;/code&gt; バイトなので、9プレーンなら 900 KiB を超えてしまう。&lt;/p&gt;
&lt;p&gt;画面構成はやや悩んだ。
ハイレゾ解像度がノーマル解像度の 2 倍以上あれば、640 × 400 を常時 2 倍拡大表示した状態を基本の状態として色々実装すればいいと思えたのだが、実際のところ 2 倍未満の 1120 × 750 なのでそうはいかない。
結局画面の左上 960 × 608 ドット（ノーマル解像度のほぼ 1.5 倍）の領域を描画領域として、残りの領域にパレットやマスク等各種の UI を常時表示することにした。
また、画像の表示は、描画領域の一部に 640 × 400 を等倍表示するか、全体を一部切り抜いて 2 倍拡大表示するか切替可能にすることにした。&lt;/p&gt;
&lt;p&gt;更に、EMS メモリを用いた undo 機能を付けようと思っていた。
が、やっぱ色々大変に思えたので、妥協して、ユーザが明示的に「復元ポイント」として現在の画像データを登録して、後でその登録した画像を 1 つ選んで画像データを復元できる機能になった。
これだけだと、マルペの fix とあまり変わらないので、復元ポイントは 8 個まで登録できるようにした。&lt;/p&gt;
&lt;p&gt;その後は、TODO リストを作って、ガシガシ実装するだけとなった。&lt;/p&gt;
&lt;p&gt;実装の話というと、EGC は 2 倍拡大表示時の表示範囲変更の際 VRAM 上のデータをブロック転送するのに使っているくらいで、結構 GRCG を使っている。
これは、GRCG の方が機能が単純で使い易かったので、実装の進捗優先で GRCG を多用したことによる。
また、これも実装優先で、描画の実態が 1 ドットの点描処理の複数回呼び出しになっている箇所がちょくちょくある。
EGC の word アクセスも GRCG の byte アクセスも点描ならばメモリアクセス回数は変わらないし、byte データで処理すればレジスタにも余裕ができるので GRCG を使っている。
今後、塗りつぶしの実装等では EGC の活用場面がまだあるだろう。&lt;/p&gt;
&lt;p&gt;UI は、マルペや PST を使ったことがあったため、あんまり独自性を出して取っ付きが悪くなるよりは良いと思い、パレットとマスクの部分はそれらをリスペクトした感じになった。
これからの実装方針は未定（というかこれまでも行き当たりばったり）なので、追加の UI がどうなるかあまり確証のあることは言えないが、既存 UI に引っ張られるだろうから、現状の延長線上の雰囲気からは大きく外れない気はする。&lt;/p&gt;
&lt;p&gt;振り返って、ハイレゾ専用プログラムを書くのが面白かったかというと、今回の作業内容ではハイレゾ機固有のローレベルな機能の利用といったことは殆どしていない。
そのため、個人的には、VRAM へのアクセス方式がやや違うことを除けば、結局 8086 マシン上での DOS プログラミングの範疇という印象が強いのであった。
更に言えば、下回りの基本的な描画ルーチンが完成してしまえば、その先は大体 GUI プログラミングになってしまう。
それもリソースが足りない環境故に極力部分的な更新を要請される難儀なやつ。
そういうことで、今回の成果物は、存在については面白いと思うが、実装が面白かったかというと、どうだろうか。
まあ、規模が大きめのプログラムを書こうとしたら各部を抽象化して疎結合にするのが楽なので、進捗すればするほどハイレゾ味がしなくなってゆくのはちょっと考えれば分かる話だったな。
兎も角、乗りかかった船、ある程度機能が育つまでは付き合おうかと思っている。&lt;/p&gt;
&lt;p&gt;作成したお絵描きソフトは &lt;a href=&quot;https://www.r-srd.net/hr11/&quot;&gt;HR11 のページ&lt;/a&gt; からダウンロードできます。&lt;/p&gt;

  </description>
</item>

<item>
  <title>M3 2026 春に出た</title>
  <pubDate>Mon, 25 May 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260525-m3-2026-spring/</link>
  <guid>https://www.r-srd.net/posts/20260525-m3-2026-spring/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260525-m3-2026-spring/">
    &lt;p&gt;&lt;a href=&quot;https://www.r-srd.net/posts/20251125-m3-2025-autumn/&quot;&gt;例によって&lt;/a&gt;大体 1 か月前の話なのだが、M3 2026 春に出ていた。&lt;/p&gt;
&lt;p&gt;半年前、M3 2025 春への出展と諸々の後仕舞いがそれなりに成功という感じの雰囲気で終わって、当然次の M3 はどうする？という話になったのだった。
正直 M3 2025 秋に申し込んでから出展迄の半年間は大分慌ただしいもので、無理に申し込まなくてもいいのではないかという空気もあった。
が、結局、M3 2026 春にも申し込むことになった。
理由は、チップチューンに興味のある別の知人を 1 人新しいメンバーとして迎えることになり、その知人が出られる次の M3 が早くとも 1 年先になってしまうのは申し訳なく思われたことと、自分含む既存メンバーの 2 人が半年以上熱量を維持できるかあんまり自信がなかったこと、大体以上 2 点による。&lt;/p&gt;
&lt;p&gt;申し込みにあたって、題材を決めなくてはならなかったが、M3 2025 春に出展してから&lt;a href=&quot;https://www.r-srd.net/posts/20260103-n2kd-v1-0a-beta-1/&quot;&gt;自分が考えていた要望&lt;/a&gt;もあり、自作の FM 音源ドライバであるところの n2kd を使って曲を作るということで纏まった。
n2kd は OPL3 にしか対応していないので、自動的に音源チップは OPL3 に決まった。&lt;/p&gt;
&lt;p&gt;M3 2025 春が終わった時点では n2kd の機能は十分といえなかったので、色々更新やらバグ修正やらして、今年初めに v1.0 (beta 1) をリリースした。
が、実際に作曲に使ってみるとまだまだバグや欲しい機能が出てきて、追加のリリースを何度もすることになった。
結構な頻度で作業したので楽ではなかったが、それでも、スケール指定命令の追加やパート指定の記法の拡張など、自作のプログラムが実用に供されてこなれていくのは気分が良かった。&lt;/p&gt;
&lt;p&gt;前回に引き続き当日は実機演奏をする予定だったので m3mp の準備もやった。
m3mp の操作のために PC-98 のキーボードをそのまま置いておくと、操作説明が必要で微妙だったという前回の反省から、また別の知人の協力を受け Arduino で RS-232C 接続の選曲と再生と停止の機能だけ持ったコントローラを用意した。
一方、画面関係はやる気と時間の都合で、基本的には前回の実装を流用して、n2kd の曲データを再生する処理を追加して、ちょっと UI を改変したくらいで終わった。&lt;/p&gt;
&lt;p&gt;作曲の方は、今回は結構手癖になった。
前述のように n2kd の更新等々やっていたので、正直作曲の勉強をしたりしている時間はあまりなかった。
手癖で最後まで一曲できれば良いが、何か躓いた時にそれを更に手癖でどうにかしようとして、ぐちゃぐちゃのぐだぐだになるということが数回あった。
やっぱり引き出しが少ないのはダメなようだ。
時間もカツカツで挽回しきれなかったところもあり、改めて締切駆動の限界を見た気がする。&lt;/p&gt;
&lt;p&gt;当日は相も変わらず睡眠不足。
スペースの賑わいは前回よりかは落ち着いていた感じだった。
思い出してみると前回のスペースの位置は今回よりも会場の出入り口に近く、根本的な人の流れの母数の差もあったような気がする。
そのお陰というのもアレだが今回は CD の売り切れはなく、前回旧譜をお渡しできなかった方にも何人か来てもらえて、心残りを片付けられたので良かった。
あと、今回は CD Extra に加えて、完全にネタで FD も頒布してみたが、現地でも完全にネタ枠になっていた。
当然 FD の容量では音声ファイルを格納することはできず、作曲者と同等の機能の環境を持っていないと曲が聞けないのだからさもありなん。&lt;/p&gt;
&lt;p&gt;2 度目の出展で、初回からの追加の成果として、今回は自作ドライバで作った曲を会場に持って行けたのは良かったが、その曲の完成度の方はというとやや思わしくないところもあった。
そう簡単なことでないのは承知だが、ドライバの出来も良いし曲の出来も良いっていうのが格好良いよなぁ。&lt;/p&gt;

  </description>
</item>

<item>
  <title>Petit Profiler v0.2a (EMS 対応など)</title>
  <pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260503-petit-prof-v02a/</link>
  <guid>https://www.r-srd.net/posts/20260503-petit-prof-v02a/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260503-petit-prof-v02a/">
    &lt;p&gt;先日作った &lt;a href=&quot;https://www.r-srd.net/posts/20260429-petit-prof-v01a/&quot;&gt;PC-98 の DOS 用プロファイラ&lt;/a&gt; に機能を2個足した。
1つは、計測中に計測していることが分かるように画面右下の T-VRAM のアトリビュートを書き換える処理が入っていたが、この挙動の有効無効を切り替えられるようにした。
もう1つは、&lt;code&gt;CS:IP&lt;/code&gt; の記録を EMS メモリに保存できるようにした。&lt;/p&gt;
&lt;p&gt;v0.1a では &lt;code&gt;CS:IP&lt;/code&gt; の記録をコンベンショナルメモリに保存していた。
そのため、プロファイラを実行するには、プロファイラ本体に加え 128KiB のコンベンショナルメモリが必要で、計測対象のプログラムは残りの空きメモリに収まっている必要があった。
上記の Petit Profiler 初出の記事でも「EMS や XMS のメモリに記録した方がいいんだろうな」と書いている。
というわけで、急ぎ EMS メモリへの記録対応を足すことにした。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;int 67h&lt;/code&gt; の API 自体はそんなに難しくはないが、割り込みハンドラ内でいちいちエラーチェックしながら EMS を読み書きするのはちょっと面倒というか億劫だった。
エラーの判定と取り扱いの処理なんてどこで書いてもやっていることは大して変わらない筈だが、割り込みハンドラ内でエラーが起こるかもしれない操作を行うというのは、なんか神経質になる。
この点は、一旦確保してしまえば割り込みハンドラ内から好きに読み書きできるコンベンショナルメモリの方が気楽だ。&lt;/p&gt;
&lt;p&gt;他に考えていることというと、Petit Profiler のパッケージには PPVIEW.CPP という名前で、プロファイルのログとリンカの map ファイル内のシンボルの対応付けをして重い関数を表示するプログラムのソースが入っているが、これの機能追加がある。
現状 PPVIEW.CPP は JWlink の出力する map ファイルにしか対応していない。
まず、JWasm は -Fl オプションで出力できるリスティングファイルにシンボルというかラベル一覧が書かれているっぽい。
これに対応すれば、JWasm で単一の .asm からアセンブルした .com のプロファイル結果を元の .asm に関連付けられそうだ。
あと、Microsoft の LINK.EXE の map ファイルも対応するといいんじゃないかという気がしているが、MS-DOS 拡張機能セットが手元にないので暫く先になりそう。
PPVIEW.CPP 自体の DOS 対応は、この令和に DOS 開発を全部 DOS 上でやっている事例はあんまりなさそうなので、PPVIEW は当分現代コンピュータ上で動かしてくださいということで、優先度低めでいいかなぁと思っている。&lt;/p&gt;

  </description>
</item>

<item>
  <title>PC-98 の DOS 用プロファイラを作った</title>
  <pubDate>Wed, 29 Apr 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260429-petit-prof-v01a/</link>
  <guid>https://www.r-srd.net/posts/20260429-petit-prof-v01a/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260429-petit-prof-v01a/">
    &lt;p&gt;n2kd 付属の MML コンパイラである n2kc は、大体 C 言語で書かれていて、DOS API の呼び出し部分などに限ってアセンブラを使っている。
コンパイルにかかる時間は、実機だと586機であればほぼ直ぐに完了する程度にはなっている。
しかし、個人的には 486 33MHz くらい、あわよくば 386 20MHz くらいのマシンでもそれなりにサクサク動くようにしたいと思っている。
それは、PC-98 を入手しようとすると386～486機の層がそれなりに厚く「586機以降の性能でないと快適に作曲ができません」というのは結構勿体ない切り捨てだと思われるからなのと、単に自分がよく使っている PC-98 が Ap2 や Xe あたりの機種だからだ。&lt;/p&gt;
&lt;p&gt;n2kc の大部分は C で書かれているため、コンパイル時に高頻度に実行されている処理をアセンブラで書き直せば高速化できる可能性がある。
例えば、直感的には、文字列をパースして数値にする関数はアセンブラ化する価値がありそうな気がする。
が、よく言われているようにまず計測ということなので、コンパイラ中で真に多く実行されているパスがどこかを突き止めなくてはならない。
そこで、DOS 用のプロファイラを作ることにした。&lt;/p&gt;
&lt;p&gt;実装方針は、定期的に CPU がどのアドレスの命令を実行しているかを観測して集計できればいいので、以下のようなコードを書けばいい筈だ。
本当は最後に、記録結果をリンカ出力のマップファイル等と比較して高頻度に実行されている箇所を見つける作業が必要だが、この機能はプロファイラと別でいいので一旦忘れることにする。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;システムタイマ割り込みハンドラに、割り込み発生時のスタック上の &lt;code&gt;CS:IP&lt;/code&gt; を記録する処理を登録する。&lt;/li&gt;
&lt;li&gt;計測対象のプログラムを実行する。&lt;/li&gt;
&lt;li&gt;計測対象のプログラムが終了したら &lt;code&gt;CS:IP&lt;/code&gt; の記録結果をファイルに保存する。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これを PC/AT 互換機でやろうとすると PIT のチャンネル0のデフォルト割り込み頻度は約 18.2Hz とプロファイラには恐らく足りないので、チャンネル0の割り込み頻度を変更することになるだろう。
割り込みハンドラでは、&lt;code&gt;CS:IP&lt;/code&gt; を記録する他に、均して約 18.2Hz になる頻度で定期的に元の割り込みハンドラを呼び出す処理が必要になる。
やたら面倒な処理という程ではないが、書かずに済めば楽なので、とりあえず PIT のチャンネル0がシステムで使われていない PC-98 専用として実装することにした。
また、この方法故、PIT のチャンネル0を何かの用途で使っているプログラムのプロファイルは取れない。&lt;/p&gt;
&lt;p&gt;CPU がどの命令を実行している際にタイマの割り込みが発生するかはわからない。
割り込み発生時に計測対象でない、例えば、DOS カーネル中のコードを実行している可能性もあったりするが、計測対象のプログラムを実行中の &lt;code&gt;CS:IP&lt;/code&gt; の集計が得られればプロファイラとしての用は成すので、他の部分を実行している場合の &lt;code&gt;CS:IP&lt;/code&gt; は全部捨てることにした。
つまり、事前に計測対象のプログラムのコードセグメントアドレスを調べておき、割り込みハンドラでは、割り込み時点でスタックに積まれている &lt;code&gt;CS&lt;/code&gt; と事前に調べたアドレスを比べて、同じだった時のみその &lt;code&gt;CS:IP&lt;/code&gt; を記録対象とする。
これを行うためには、メモリ上にロードされたプログラムが実行される前にそのコードセグメントのアドレスを獲得しなくてはならないが、以前思い付きで DOS 用デバッガを作ろうとした（当然？完成していない）ことがあり、&lt;code&gt;int 21h (ah=4bh, al=01h)&lt;/code&gt; でロードだけができることを調べていたのでこれを使った。&lt;/p&gt;
&lt;p&gt;とりあえず動くのを優先ということで、以下のような制約があるが、プロファイラを書いた。
n2kc は複数のコードセグメントを持たないのと、コンベンショナルメモリを 500KiB くらい空けておけばプロファイラと n2kc を動かすのにメモリは十分足りた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;プログラム最初の命令の &lt;code&gt;CS&lt;/code&gt; の指すセグメント中の命令を実行している時のみ記録対象となる。
&lt;ul&gt;
&lt;li&gt;複数のコードセグメントを持つプログラムでは、最初の命令があるコードセグメント以外のセグメントの実行の様子は記録できない。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CS:IP&lt;/code&gt; の記録のために 128KiB のメモリが必要。
&lt;ul&gt;
&lt;li&gt;C 言語風に書くと &lt;code&gt;uint16_t log[65536]&lt;/code&gt; をコンベンショナルメモリに用意して、割り込みハンドラで &lt;code&gt;IP&lt;/code&gt; に応じて &lt;code&gt;log[IP] += 1&lt;/code&gt; をしているため。&lt;/li&gt;
&lt;li&gt;EMS や XMS のメモリに記録した方がいいんだろうなとは思いつつ……。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;早速 n2kc のプロファイルを取ってみた。
前述の、雑な直観で結構呼ばれていそうだと思っていた文字列の数値化関数は、実際には上から3番目に多い出現回数だった。
そして、それよりも出現回数が多かったのは、1番目が次の行へ進む関数で、2番目が連続した指定の種類の文字を飛ばす関数だった。
n2kc は、コンパイル対象（音色や各パートに対する演奏命令等）を切り替えながら入力された MML を何度も先頭から舐めるように動作するので、現在のコンパイル対象でない部分は全部次の行へ進む関数で飛ばされることになる。
また、空白を記述可能な場所等で特定種類の文字を飛ばす処理を実行している。
という訳で、これら2つの関数の出現回数が多くなるのは考えてみれば当然なのだが、当然の如く見落としていた。
現状プロファイルを取っただけで n2kc の高速化には着手していないが、ちゃんと最初に計測をしてよかった。&lt;/p&gt;
&lt;p&gt;実装したプロファイラは &lt;a href=&quot;https://www.r-srd.net/pprof/&quot;&gt;Petit Profiler のページ&lt;/a&gt; からダウンロードできます。&lt;/p&gt;

  </description>
</item>

<item>
  <title>wmdrv v0.6a</title>
  <pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260401-wmdrv-v06a/</link>
  <guid>https://www.r-srd.net/posts/20260401-wmdrv-v06a/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260401-wmdrv-v06a/">
    &lt;p&gt;この前、V30 と 386DX が搭載された PC-98 を求めた結果、案の定 PC-9801RA 後期でなく PC-98RL が生えた話を&lt;a href=&quot;https://www.r-srd.net/posts/20260328-hires-font/&quot;&gt;書いた&lt;/a&gt;。
そこでも言ったが「入手した以上何かに使わないと勿体ない」ということで、何かハイレゾの作業をやることにして、結果 wmdrv のハイレゾ対応をやって wmdrv v0.6a として公開した。
CAD/CAM によく使われたと聞くハイレゾモードでタブレットを利用可能にするというのは、なんだかノーマルモード用のタブレットドライバという姿よりも板に付いている気がする。&lt;/p&gt;
&lt;p&gt;ただ、wmdrv が提供する &lt;code&gt;int 33h&lt;/code&gt; のファンクションはハイレゾモードでもノーマルモード同様マイクロソフト仕様になっている。
ハイレゾ機は ROM で違う仕様のマウス BIOS を持っているようなので、ハイレゾ機内蔵マウス BIOS を使うアプリケーションとは互換性がないことになってしまっている。
NEC 純正ハイレゾマウス BIOS と非互換であるという欠点は致命傷なのか掠り傷にもならないのか、実感を伴って把握することなど全くできていないが、「互換があるに越したことはないだろ」と言われれば首肯せざるを得ないので、何か機会や機運があれば互換モードを足すかもしれない。&lt;/p&gt;
&lt;p&gt;作業を振り返ると、ハイレゾ対応は、想像していた通り IO ポートや INT の差異は大したことはなかったが、描画周りの機能追加がやや難儀だった。
ハイレゾの VRAM 領域は 128KiB あるため、単一のセグメントアドレスで全 VRAM にアクセスすることができない。
マウスカーソルの描画はよく行われる処理であろうから、描画処理をノーマルモード向けに 16bit 幅のレジスタでそれなりに最適化してしまっていたのが裏目に出て、思ったより各所を変更することになってしまった。
最終的には、マウスカーソルの描画範囲は 64KiB 以内に収まるので、最初に1回描画開始位置として適切なセグメントとオフセットを計算して、その後はセグメントレジスタに触らないようなコードになった。&lt;/p&gt;
&lt;p&gt;ハイレゾ対応以外のところでは、新規の起動オプションとして &lt;code&gt;/x&lt;/code&gt; を追加した。
&lt;code&gt;/x&lt;/code&gt; を指定するとタブレットを使用せず（RS-232C の割込に常駐せず）、バスマウスのみを入力とするマウスドライバとして動作する。
また、特定条件下で割込ベクタを破壊するとか、マウスの XOR マスクのデータで XOR でなく OR をしていたといった、だいぶ酷いバグも見つかったので修正した。&lt;/p&gt;
&lt;p&gt;話が少し変わりますが、&lt;a href=&quot;https://www.r-srd.net/posts/20240728-wmdrv-v04a/&quot;&gt;v0.4a の公開記事&lt;/a&gt;で、8086 命令を使うようにしたために8086搭載機でも動くであろう旨を書きましたが、ちゃんと調べてみると古い PC-9801 の差異の吸収を行うコードが入っておらず、多分正常動作しないと思われますので、ここに訂正します。
少なくとも、無条件で 0e000h の VRAM プレーンにアクセスしているため何か別のメモリがあると書き換えてしまうのと、2D FDD インターフェースのイメージが出ている IO ポート 5fh でウェイトを取っているという問題があります。&lt;/p&gt;

  </description>
</item>

<item>
  <title>PC-98 のハイレゾモードと16ドットフォント</title>
  <pubDate>Sat, 28 Mar 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260328-hires-font/</link>
  <guid>https://www.r-srd.net/posts/20260328-hires-font/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260328-hires-font/">
    &lt;p&gt;暫く前から V30 搭載で 386DX 搭載の PC-98 が欲しいなぁと思っていた。
CPU は速い方が良いから、それは殆ど PC-9801RA 後期を指しているわけだが、縁がなかったというか、のらりくらりしていたというかで、欲しいと思っているだけの月日が幾らか経った。
今まで386機をちゃんと使ったことがなく興味をもっていたのもあり、入手してしまうのは遅かれ早かれ当然の成り行きで、遂に、PC-98RL を入手した。&lt;/p&gt;
&lt;p&gt;きっかけは最早覚えていないが、気づかなければ良いのに、兎に角 RL も V30 搭載で 386DX 20MHz であることに気づいて、調子に乗ってしまったのだった。
人気はあまりなさそうなので、RA の代用としての RL は結構穴場かもしれないが、でかいし、情報があんまりないし、でかいし、純正メモリボードが全然見あたらないし、でかいし、重いし、でかいし、割に合っているかというと微妙だ。
実際、分解清掃中に「でかすぎる」と20回くらいは言った。&lt;/p&gt;
&lt;p&gt;残念なことに普段5インチフロッピーディスクを全く使っていないのも噛み合わない。
ただ重さに拍車を掛けているだけの2台の FD1155Dを取り除き、何とか改造なりして3.5インチ化できれば御の字だが、フロントマスクを美しく加工する自信があるかというと微妙だ。&lt;/p&gt;
&lt;p&gt;といった感じで、高性能なでかい計算機に心躍るがきんちょの部分と、なんでこんな選択したんじゃと冷めている部分と心に同居していたが、入手した以上何かに使わないと勿体ないと思い直して、適当に WWW を跋渉していると、目に留まった情報があった。
&lt;a rel=&quot;external&quot; href=&quot;https://x.com/shiura/status/1859188412202602886&quot;&gt;こちら&lt;/a&gt; や &lt;a rel=&quot;external&quot; href=&quot;https://x.com/shiura/status/1859188622429388801&quot;&gt;こちら&lt;/a&gt; のツイートに曰く、「ノーマルモードもついたハイレゾ機(XLとかRL)は、裏技でハイレゾモードから16x16ドットの感じROMが読め」て、それは「とあるIOポートを叩くと漢字ROMを切り替えられ」るためとのこと。
面白そうなので、当該の IO ポートを探すことにした。&lt;/p&gt;
&lt;p&gt;毎度お世話になっております undoc2 を読んで、漢字 ROM 切り替え機能が配置されていそうな IO ポートとして、以下2つに目星を付けた。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CG 関係の IO ポート（0a*h の奇数ポート）のうち undoc2 に機能の記述がないもの。&lt;/li&gt;
&lt;li&gt;IO ポート 68h 及び 6ah のモード FF のうち undoc2 に機能の記述がないもの。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;事前に CG ウィンドウから値を読んでおき、怪しい IO ポートに適当な値を書いた後に再び CG ウィンドウから値を読んで、先に読んでおいた内容と同じかどうか判定するプログラムを書いた。
IO ポート 0a5h に未使用ビットがあったので一応 0a5h から試したところ、次の 0a7h で CG ウィンドウの値が変わっているとプログラムが言ってきた。
どうやら、以下の仕様っぽい。
PC-9821A-E02 による MATE-A のハイレゾモードでも試してみたところ同様の挙動のようだった。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IO ポート 0a7h に 00h を書いておくと CG ウィンドウから24ドットフォントが読み出せる。&lt;/li&gt;
&lt;li&gt;同ポートに 01h を書いておくと CG ウィンドウから16ドットフォントが読み出せる。
&lt;ul&gt;
&lt;li&gt;16ドットフォント読み出しの際の操作はノーマルモードと同じ。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;テストプログラムを書きました → 












    &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;www.r-srd.net&amp;#x2F;posts&amp;#x2F;20260328-hires-font&amp;#x2F;HR16FONT.ASM&quot; type=&quot;text&amp;#x2F;plain&quot;&gt;HR16FONT.ASM&lt;/a&gt;

。
プログラム引数に合わせて「あ」「A」「㍼」の3種類の文字の24ドットまたは16ドットフォントのいずれかを読み出すプログラムです。
読んだフォントパターンは1ドット1文字のテキストで表示するので24ドットフォントの場合、上端が少し見切れます。&lt;/p&gt;







&lt;div class=&quot;img-block&quot;&gt;

	&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.r-srd.net&amp;#x2F;posts&amp;#x2F;20260328-hires-font&amp;#x2F;hr16font.jpg&quot; alt=&quot;テストプログラムの実行例&quot;&gt;


	&lt;div style=&quot;margin: 0.5em auto 0; text-align: center&quot;&gt;
		テストプログラムの実行例
	&lt;/div&gt;

&lt;/div&gt;
&lt;p&gt;というわけでハイレゾモードから16ドットフォントが読めるようになったが、どう活用すればいいんだろうか。
まあ、この令和にハイレゾ専用プログラムを作るというのは、それ自体酔狂で面白いとは思うので、何か思いついたら使ってみよう。
そういえば、07ah に触って CG ウィンドウの値が変わるのが分かった時点で目星を付けた IO ポートの探索は打ち切ってしまったので、0a7h より後の IO ポートやモード FF に何かまだ他の機能があるかもしれない。&lt;/p&gt;
&lt;p&gt;あと、興味で XL^2 を1回は入手するつもりで生きていたが、でかいのは RL で腹一杯なので、多分今後入手はしないだろう。
V30 搭載の 386DX 機が最初の目標だったので RL なんてところに着地してしまったが、そもそも RL 互換のハイレゾモードは、まあ、PC-9821A-E02 でいいと思います……。&lt;/p&gt;

  </description>
</item>

<item>
  <title>MASM で変数定義と PUBLIC 指定を同時にやるマクロ</title>
  <pubDate>Wed, 25 Feb 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260225-masm-macro/</link>
  <guid>https://www.r-srd.net/posts/20260225-masm-macro/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260225-masm-macro/">
    &lt;p&gt;MASM では、&lt;code&gt;some_func PROC PUBLIC&lt;/code&gt; と書いて、関数を書くと同時に他のモジュールから参照可能な公開扱いにすることができるが、どうも変数はそうではないらしい。
例えば &lt;code&gt;hoge db 0&lt;/code&gt; という変数があったとき、これを公開したければ &lt;code&gt;PUBLIC hoge&lt;/code&gt; を別に書かなくてはならない。
そこで、MASM のマクロの勉強も兼ねて &lt;code&gt;PUBVAR hoge db 0&lt;/code&gt; のように書くと、&lt;code&gt;hoge&lt;/code&gt; の PUBLIC 指定も同時にしてくれる &lt;code&gt;PUBVAR&lt;/code&gt; マクロを作ってみることにした。&lt;/p&gt;
&lt;p&gt;MASM の変数定義は &lt;code&gt;変数名 型 初期値&lt;/code&gt; の形式で、例えば &lt;code&gt;hoge db 100&lt;/code&gt; と書くと、初期値が 100 の 1 バイト変数 &lt;code&gt;hoge&lt;/code&gt; が定義される。
また、初期値の部分にカンマ区切りで複数の値を書くことができるので、手っ取り早い実装は、&lt;code&gt;VARARG&lt;/code&gt; を用いて以下のようになるだろう。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D4D4D4; background-color: #1E1E1E;&quot;&gt;&lt;code data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBVAR MACRO &lt;/span&gt;&lt;span style=&quot;color: #DCDCAA;&quot;&gt;varname:&lt;/span&gt;&lt;span&gt;REQ, &lt;/span&gt;&lt;span style=&quot;color: #DCDCAA;&quot;&gt;decl:&lt;/span&gt;&lt;span&gt;VARARG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	PUBLIC varname&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	varname decl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ENDM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBVAR	hoge, &lt;/span&gt;&lt;span style=&quot;color: #569CD6;&quot;&gt;db&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBVAR	fuga, &lt;/span&gt;&lt;span style=&quot;color: #569CD6;&quot;&gt;db&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt; 2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBVAR	piyo, &lt;/span&gt;&lt;span style=&quot;color: #569CD6;&quot;&gt;dw&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #DCDCAA;&quot;&gt; dup&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実際、上記のマクロでも実用上割と問題はないと思わないではないのだが、マクロの引数が &lt;code&gt;varname&lt;/code&gt; （変数名）と &lt;code&gt;decl&lt;/code&gt;（変数の定義内容）に分かれているので、変数名の後にカンマが必要になっている。
&lt;code&gt;PUBVAR&lt;/code&gt; を付けたり外したりするのに合わせてカンマを書いたり消したりするのは、個人的には面倒そうで気に食わない。&lt;/p&gt;
&lt;p&gt;というわけで、カンマ無しで書ける版を作った。
このマクロは、変数定義のうち &lt;code&gt;hoge db 1&lt;/code&gt; といった変数名から1個目の初期値までの範囲を &lt;code&gt;decl&lt;/code&gt; 引数に、さらにカンマ区切りで継続する初期値があればそれらを &lt;code&gt;VARARG&lt;/code&gt; の &lt;code&gt;decl2&lt;/code&gt; 引数に受け取る。
マクロ内では、&lt;code&gt;decl&lt;/code&gt; の先頭から最初に見つかったスペースまたはタブの手前までの内容を &lt;code&gt;PUBLIC&lt;/code&gt; に渡し、&lt;code&gt;decl&lt;/code&gt; と &lt;code&gt;decl2&lt;/code&gt; の内容を使って変数定義を行う。
文字列検索は &lt;code&gt;@Instr&lt;/code&gt; でできるが、OR 検索のようなものはないので、スペースとタブ両方で検索を行い、最初に見つかった方を採用している。&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D4D4D4; background-color: #1E1E1E;&quot;&gt;&lt;code data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBVAR MACRO &lt;/span&gt;&lt;span style=&quot;color: #DCDCAA;&quot;&gt;decl:&lt;/span&gt;&lt;span&gt;REQ, &lt;/span&gt;&lt;span style=&quot;color: #DCDCAA;&quot;&gt;decl2:&lt;/span&gt;&lt;span&gt;VARARG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	LOCAL pos, pos_sp, pos_tab&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	pos_sp = @InStr(&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;1&lt;/span&gt;&lt;span&gt;, &amp;lt;decl&amp;gt;, &amp;lt; &amp;gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	pos_tab = @InStr(&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;1&lt;/span&gt;&lt;span&gt;, &amp;lt;decl&amp;gt;, &amp;lt;	&amp;gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	IF pos_sp EQ &lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		IF pos_tab EQ &lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			.ERR &amp;lt;space or tab was not found&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		ELSE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			pos = pos_tab&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		ENDIF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ELSEIF pos_tab EQ &lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		pos = pos_sp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ELSE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		IF pos_sp LE pos_tab&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			pos = pos_sp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		ELSE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			pos = pos_tab&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		ENDIF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ENDIF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	PUBLIC @SubStr(&amp;lt;decl&amp;gt;, &lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;1&lt;/span&gt;&lt;span&gt;, pos - &lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	IFB &amp;lt;decl2&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		decl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ELSE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		decl, decl2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ENDIF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ENDM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBVAR	hoge	&lt;/span&gt;&lt;span style=&quot;color: #569CD6;&quot;&gt;db&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBVAR	fuga	&lt;/span&gt;&lt;span style=&quot;color: #569CD6;&quot;&gt;db&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt; 2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBVAR	piyo	&lt;/span&gt;&lt;span style=&quot;color: #569CD6;&quot;&gt;dw&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color: #DCDCAA;&quot;&gt; dup&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span style=&quot;color: #B5CEA8;&quot;&gt;2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;今回の作業で、置換 + α 程度でないような MASM のマクロ機能を初めて幾つか使ってみたが結構高機能で頑張れば色々できそうなので、何か他にいい案が浮かんで便利なマクロができたら今後も類似の紹介記事を書くかもしれない。&lt;/p&gt;

  </description>
</item>

<item>
  <title>作りかけの音源基板</title>
  <pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260111-kiban/</link>
  <guid>https://www.r-srd.net/posts/20260111-kiban/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260111-kiban/">
    &lt;p&gt;部屋の片付けをしていたら作りかけの C バス音源基板が出てきた。
過去の記録を漁ると遅くとも2023年10月頃までは作業していたらしい。
OPNA が1個、OPN2 が2個載った基板で、ちびおと搭載の86ボードと組み合わせて「音美ちゃん2枚 + 86PCM」相当になるみたいな目論見だった。
確か、最初は OPN2 が2個だけの基板で「ちびおと付き86ボード + スピークボード + 自作基板」の構成を考えていた。
しかし、スピークボードなどの OPNA 搭載サードパーティ音源ボードの入手性があまりにも悪かったのと、占有する C バススロットの数を減らしたかったので、OPNA も載せてしまえとなった記憶がある。
あと、アドレスデコーダの部品点数削減に GAL を使ったが半導体不足絡みか入手に苦労した記憶も薄ら。&lt;/p&gt;
&lt;p&gt;実装して動かすと色々不具合が出たので、パターンカットやらジャンパ飛ばすやら手を入れて、各チップが所望の IO ポートに見えてそれらしくレジスタを叩けば音が鳴るところまで行った。
とは言っても、ノイズは結構乗っていた覚えがある。
この後は、不具合の修正や部品配置の調整をした新版の基板を起こすのと、n2kd の OPNA 及び OPN2 対応をやるつもりだったんじゃないかと思うが、探してみても作りかけの新版の基板データしか見つからなかったので、現状それまでのようだ。
一応動きはした基板の方は兎も角、n2kd には現在 OPNA 関係のコードが全く入っていないので、再開しても色々と先は長いだろう。
5年後とかに完成していたら良いくらい？&lt;/p&gt;







&lt;div class=&quot;img-block&quot;&gt;

	&lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;www.r-srd.net&amp;#x2F;posts&amp;#x2F;20260111-kiban&amp;#x2F;kiban.jpg&quot; alt=&quot;作りかけの C バス音源基板の写真&quot;&gt;


	&lt;div style=&quot;margin: 0.5em auto 0; text-align: center&quot;&gt;
		作りかけの C バス音源基板
	&lt;/div&gt;

&lt;/div&gt;

  </description>
</item>

<item>
  <title>n2kd FM Driver v1.0a (beta 1)</title>
  <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate><link>https://www.r-srd.net/posts/20260103-n2kd-v1-0a-beta-1/</link>
  <guid>https://www.r-srd.net/posts/20260103-n2kd-v1-0a-beta-1/</guid>
  <description xml:base="https://www.r-srd.net/posts/20260103-n2kd-v1-0a-beta-1/">
    &lt;p&gt;ベータ版扱いですが n2kd の新バージョン v1.0a を公開しました。
&lt;a href=&quot;https://www.r-srd.net/posts/20240906-n2kd-plan/&quot;&gt;前回の進捗報告の記事&lt;/a&gt;での見通しの記述から追加で1年オーバーしました。
もしも新バージョンの公開を待ってくださっていた方が居ましたら大変遅くなってしまい申し訳ありません。
上述の記事では v0.2 系として公開する予定でしたが、旧バージョンの v0.1.2 系で気になっていた部分は結構直した（と思う）ので、思い切って v1.0 系にしたのと、ドライバ本体と MML コンパイラのソースコードも公開することにしました。&lt;/p&gt;
&lt;p&gt;n2kd の実装が進んだのは昨年秋の M3 への参加が大きく、その時は PMD を使いましたが、自作のドライバがあるのだから自作のドライバで曲を書きたいという気持ちが大きくなりました。
結果、冬に入ってからドライバの実装を本格的に再開して、取り敢えず公開しても良さげと思えるところまで来ました。
やはり、必要は発明の母でしょうか。&lt;/p&gt;
&lt;p&gt;v1.0 系は v0.1.2 系と比べると結構変わっている箇所が多く、また開発が中断を挟みつつ長時間に亘ったため、差分を自分でも全部直ぐ思い出せないのですが、（前回の進捗報告の記事と重複するものも含めて）大きな変化を挙げると以下のようなものがあります。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;複数音源対応
&lt;ul&gt;
&lt;li&gt;複数の音源チップを使って演奏する曲データを表現できるようになりました。&lt;/li&gt;
&lt;li&gt;ただし、ドライバがサポートしている音源チップは現状 OPL3 のみですので、OPL3 を複数使った曲データしか作れません。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PC/AT 互換機対応
&lt;ul&gt;
&lt;li&gt;OPL3 向けのドライバである以上、PC/AT 互換機で動かないのはちょっと名が泣くような気がしたので対応させました。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;テンポ管理機能の拡張
&lt;ul&gt;
&lt;li&gt;v0.1.2 系では PC-98x1 シリーズで動かす際にテンポ管理に OPN(A) が必須でしたが、OPN(A) がない時にシステムタイマをテンポ管理に使うようにしました。ただし、仕様上 OPN(A) でテンポ管理する場合と完全に同じテンポでは演奏できません。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MML 文法の機能拡張と整理
&lt;ul&gt;
&lt;li&gt;色々やりました。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;VZ エディタ用コンパイル &amp;amp; 演奏マクロを作成
&lt;ul&gt;
&lt;li&gt;VZ エディタが公開されていたので、あった方が便利だろうと思い、（やや制約がある出来ですが）マクロを書きました。面白かったですが大変でした。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今後は、秋以降実装ばっかりしていましたし、実際に使わないと気付かないバグがまだある可能性は否定できないので、n2kd を使った曲を幾つか書いてみようと思っています。
また、曲データファイルのフォーマットの仕様説明やドライバの内部実装の解説など、技術方面の記事も書けたらいいなと思っています。&lt;/p&gt;

  </description>
</item>

</channel>
</rss>
