パピコンファンの皆様、お待たせいたしました。
情報得てました? z88dk から C 言語で作れるって。
でもサンプルがあまりにないので、ちょっと触れておきます。
「こんにちはマイコン」で覚えた人です。はい~。

z88dk

z88dk は Windows や macOS などで使用できる、
Z80 に対応している各プラットフォーム向けのクロス開発ツールです。
日本だと MSX で紹介されているケースが多いですが、
PC-6001 も対応しています。

https://github.com/z88dk/z88dk/wiki/Platform---NEC-PC6001

この記事ではダウンロード・インストールは詳しく触れません。
検索してもらえれば詳細な説明が出てくると思います。
PC-6001 向けでもインストールは一緒です。MSX とかあっても大丈夫。

……という自分も MSX や PC-G850 の人。
そんな自分でも PC-6001 を問題なく扱える環境があるのでした。

PC-6001用互換BASIC

PC-6001 には互換BASIC という素晴らしいものが開発・公開されています。
これで実機を持っていない・動かなくても、安心してエミュレータを使えるというわけです。

PC-6001 対応のエミュレータは……あ、これが良い!

武田鉄矢さんのアイコン! 知ってます、知ってます。CM してたんですよね。

互換 BASIC で PC-6001 を起動

という事で、PC-6001VW+互換BASIC で無事に起動できました。

Hello, World

まずは Hello World ですよね。

#include <stdio.h>

main(){
    printf("Hello world!\n");
}

これを hello.c で保存しました。これをコンパイル(ビルド)します。
C 言語からは zcc を使います。PC-6001 関連は +pc6001 を付けます。
最低限で、こんな感じになります。

zcc +pc6001 -create-app -bn hello hello.c

これで hello.cas ができます。カセットテープイメージですね。
それでは PC-6001VW で動作を確認してみます。

PC-6001VW の設定画面

PC-6001VW では、起動するとこのような画面になります。
機種を切り替えたりできるんですね。
機種は PC-6001、そして 互換ROMを使用する を有効しています。
右上に「LOAD-TAPEイメージ」があります。右の を選び、
z88dk で生成した hello.cas を選択します。
これで準備完了。Start Emulation で起動します。

PC-6001VW の起動から読み込み

「How Many Pages?」と出ました。 Enter でも良いようですが、
32k の場合は 2 Enter になるそうです。
起動画面が表示された後、CLOAD とします。
この時 PC-6001VW ではカセットの音がちゃんと聞けます。
「Found:hello.」と出たら RUN と入力します。
更にカセットを読み込む音が聞こえて……

左上に Hello World!

「Ok」あれ? いやいや、よく見ると、左上にちゃんと
「Hello World!」が出ています。はい、これで成功です。
ちゃんと z88dk でビルドしたマシン語が動いています。

テキストをもう少しちゃんと出してみる

テキスト表示をもう少ししっかりと出したいですね。
ほしいところは BASIC でいう CLS と LOCATE でしょう。
z88dk の場合、conio.h に CLS に対応する clrscr()、
LOCATE に対応する gotoxy() が含まれています。
他にコントロールコードとエスケープシーケンス(ESC)を
用いた方法もあるのですが、PC-6001 では動作しないようです。

#include <stdio.h>
#include <conio.h>

void main() {
  clrscr();

  for (int i=1; i<=11; i++) {
    gotoxy(i, i);
    printf("test");
  }

  while (!getk());
}

GETK は INKEY$ ですね。何か入力するまで待ち状態です。
BASIC しか分からない人でもなんとなくやってる事が分かるでしょう?
それではこのソース text.c をビルドしまして……

zcc +pc6001 -create-app -bn text text.c

PC-6001VW で実行します。

test が並んで表示

良い感じに表示できました。
clrscr() では自動的にファンクションキー表示を非表示にします。

グラフィック表示

グラフィックももちろん扱えます。
で、z88dk にはプラットフォーム共通で扱える
モノクログラフィック・モノクロスプライト機能があります。
そこで、モノクログラフィックを用いたサンプルを紹介します。

#include <graphics.h>
#include <math.h>
#include <stdio.h>

void main() {
  int x, y;

  clg();

  for (x=0; x<=getmaxx(); x+=2) {
    plot(x, getmaxy() / 2);
  }

  for (x=0; x<=getmaxx(); x++) {
    y = (int)((getmaxy() / 2) * (1.0 - sin(M_PI * 2.0 * x / getmaxx())));
    if (x==0){
      plot(x, y);
    } else {
      drawto(x, y);
    }
  }

  while (getk() < 1){}
}

サインサーブを表示するプログラムです。
小数点の計算をしているので、math.h というライブラリを使っています。
この場合、-lm というオプションを追加します。

zcc +pc6001 -lm -create-app -bn sin sin.c

では実行してみましょう。

PC-6001 のモノクログラフィック

……ん、緑背景なのに、線画はオレンジで黒背景になってしまうんですね。
と開発者に聞いてみたんです。
そうしたら「PC-6001mkII だと綺麗に表示できるよ~」ですって。
互換 BASIC は PC-6001mkII も入ってました。

PC-6001mkII のモノクログラフィック

こちらは黒背景になるので、綺麗に表示できます。
……え? ちゃんとグラフィックモードがある???
ああ、もちろん対応されているのですが、16k 環境を考慮して、
32✕16 文字のテキスト画面を用いた 64✕48 ドット表示を実現して、
これをデフォルトにしてある、というわけです。
もちろん 256✕192・128✕192 のグラフィック表示にも対応しています。

その他ヒント

PC-6001・PC-6601 機種依存の情報がこのページにあります。

https://github.com/z88dk/z88dk/wiki/Platform---NEC-PC6001

  • オプションに -subtype=32k を付けて 32k 向けでビルド
  • ROM カートリッジイメージでのビルドも可能。(下の項目に注意書きあり)
  • 3 行ほど追加してグラフィックモードに切り替えて表示
  • ゲーム向けは joystick 関数を使うのが良い

-subtype=~ が付いていなければ 16k 向けです。
後期の機種では起動時に 16k・32k の選択になるのですが、
zcc ビルド時の 16k・32k と合わないとスキップしてしまうので、ご注意下さい。

z88dk を使ってパピコンを操作!

z88dk の C 言語から PC-6001 をマシン語で操作できてしまう!
こんな事も可能になっています。
PC-6001 の実機に触れていない人でも互換 BASIC でエミュレータは大丈夫。
パピコンにも触れてみて下さい。


追加 2019/07/11

グラフィック画面での線画方法を紹介しておきます。

console_ioctl(IOCTL_GENCON_SET_MODE, &mode);

初期化でこの行を追加します。clg() の前後になるでしょう。

int mode = 1;

mode は main() 関数の頭や関数外で設定しておきます。

  • mode = 0 : テキスト画面 64✕48
  • mode = 1 : 256✕192・2 色画面
  • mode = 2 : 128✕192・4 色画面

加えたソースがこうなります。

#include <graphics.h>
#include <math.h>
#include <stdio.h>

void main() {
  int mode = 1;
  int x, y;

  console_ioctl(IOCTL_GENCON_SET_MODE, &mode);

  clg();

  for (x=0; x<=getmaxx(); x+=2) {
    plot(x, getmaxy() / 2);
  }

  for (x=0; x<=getmaxx(); x++) {
    y = (int)((getmaxy() / 2) * (1.0 - sin(M_PI * 2.0 * x / getmaxx())));
    if (x==0){
      plot(x, y);
    } else {
      drawto(x, y);
    }
  }

  while (getk() < 1){}
}

実際に表示した画面がこのようになります。

mode 1

mode 1 の表示

mode 2

mode 2 の表示

これを追加で紹介した理由。
実は数日前までこの表示に不具合があってちゃんと表示できなかったんです。
20190710 の時点までに修正が入って表示できるようになっています。
……という事で、表示がおかしくなる場合は
最新の Nightly Build に更新して試してみて下さい。