Apple II Plus
Personal Computer
(1978) |
|
メインボードには正しい電源電圧が与えられているのに、システムが立ち上がらない・・・
まずはシステムクロックが正しく生成できているかどうかを調べるべきでしょうか。 でも考えてみれば、ビデオモニタには乱雑なキャラクタが…「ソソソ」とかが表示されています。 それに、複数個所にあるものの、カーソル点滅している文字もあります。 これはテキストビデオメモリがスキャンされ、メモリの値に応じた文字の形を取り出して、 それをテレビ画面に表示するためのNTSCコンポジットビデオ信号を正しく生成できているということです。 つまり、キャラクタジェネレータを含むビデオディスプレイ回路は正常に動作しているのです。 ということは、ビデオディスプレイ回路に必要なクロック周波数は正常に発生できているわけです。 Apple IIのビデオ回路は、マイクロプロセッサとは完全独立で動作し、 RAMのうちビデオメモリとして割り当てられたアドレスレンジをサイクルスチールで共有しています。 これは、プロセッサクロック信号が正のサイクルのときにはCPUがメモリをアクセスし、 クロックが負のサイクルのときにビデオ回路がメモリをアクセスすることによって実現されています。 そしてビデオ回路が正常に動作しているということは、 プロセッサクロックもまた正しく所定の周波数で動作しているということ、のはずです。 リファレンスマニュアルを読んで、Apple IIのシステムクロック信号がどのように生成されるかを調べました。 うーん、すごい。 廃棄扱いの本機を譲り受けた1988年のときはリファレンスマニュアルに付属している回路図なんてチラ見しかしなかったし、 チラ見以上の理解はできませんでしたけれど、今読むと、これはすごい。 Apple IIは、そのCPUである6502のプロセッサクロック1MHzのほか、NTSCビデオのカラーサブキャリア周波数の3.579545MHz、 ビデオ回路を動作させるためのサブキャリア周波数の倍の7MHz、DRAMのRAS/CASのための2MHzを、 たったひとつのマスターオシレータから巧みに生成しているのです - しかもすべて標準TTLロジックチップだけを使って。 ウォズの天才設計のひとつのなのでしょう、BOMコストは明らかに最低限に抑えられていますし、 マウンテンビューのパーツショップで買える部品だけでできあがっています。 マスターオシレータの発振周波数は14MHzですが、 ここからカラーサブキャリア周波数を生成するため、これは正確には 3.579545MHzの4倍の14.31818MHzになっています。 念のために1MHzのプロセッサクロックφ0とφ1をメインボード上の複数個所で - 6502プロセッサのクロックピンも含めて - オシロスコープで観察しましたが、きちんと1MHz (正確には測定していませんが 1.020484MHz のはず) が出ています。 なお使ったのは夢と時空の部屋用に修理した 岩通SS-5702シンクロスコープ。 これはさすがに 6球真空管オシロ では不可能な測定です。 Apple IIの修理作業の準備として修理しておいたようなもの、かもしれません。 それでは電源投入直後に動作するハードウェアリセット回路がうまく働いていないのでしょうか。 Apple IIにはシステム拡張のためのペリフェラルスロットが8本装備されており、 主要なシステム信号が出ています。 リセット信号はペリフェラルコネクタの31ピンに出ているのでここをオシロで観測してみると、 電源投入直後にリセットラインはLOに落ち、ほんの一瞬遅れてHIに上がります。 これは正常な挙動。 6502プロセッサのリセットピンは一番端の40ピン。 ここも同じ挙動です。 プロセッサのソケットの接触不良ということでもありません。 よって、リセット信号は正常。 2020-01-17 プロセッサクロック1MHzとリセットラインの正常動作を確認 |
|
ウォズニアックがその天性のエンジニアリングスキルで一般ユーザの手が届く価格のフロッピィディスクドライブ "Disk II" を開発するまで、
一般ホビイストがコンピュータプログラムやデータを保存するためにはカセットテープレコーダが広く使われていました。
1と0のビット列をオーディオ信号として出力してテープレコーダで「録音」してセーブし、
それを「再生」してコンピュータにロードする方法です。
Apple IIにもそのためのカセットインターフェイスジャックが用意されています。 ラボのApple IIにはDisk IIが装備されていますが、そのテストは先送りにしているので、 今は作成したプログラムをカセットインターフェイスを使ってセーブします。 本物のカセットテープレコーダを使うのが正統なのかもしれませんが、 今はNoobow9100F Windows10 PCのオーディオインターフェイスを使ってWAVファイルに録音し、それを再生することにします。 カセットテープレコーダではテープのワウフラッタ、いろいろな原因によるノイズや音飛びなどで、 データの記録再生にはトラブルが付きものでした。 Windows PCでデジタル記録すればそのような心配は一切なし。 プログラム名をファイル名としてメモしておけるし、頭出しもライブラリ整理も簡単、 もちろんネットワークで送受信することもできるわけですから、 プログラムを遠隔地に送るためにはカセットテープを郵便で送っていた当時に比べれば夢のような話です。 Apple IIのカセットインターフェイスでは、平均して1.3kbpsのデータ転送レートが得られます。 Twitterのビデオツイートを使えば、2分20秒の中で約16キロバイトまでの プログラムやデータを「ツイート」することもできます。 面白い使い方ができるようにもなりました。 2021-01-23 カセットインターフェイスでプログラムをセーブ/ロードする |
|
どこもかしこも埃で汚れていたメインボードは、
起動不能の修理をしながらあちこち綿棒とアルコール洗浄液を使ってちまちま拭き、
それなりにきれいになってきました。
キーボードの修理をするために外装ケースを取り外しましたので、
キーボードの下で今まで指が届かなかったフロント寄りの部分も清掃。 そんなことをしていたら、ツイッターのタイムラインに #見た人もなにか無言でLチカあげる というハッシュタグが流れてきたので、 ゲームポートのアナウンシエータ出力を使ってLチカを作ってみました。 メインボードのゲームコネクタには、スイッチ入力・ジョイスティック入力のほか、 2つのデジタル出力ポートが用意されています。 たった2ポートではありますが、 これを使って外部装置の制御プログラムを書くこともできるわけで、 これがあればコンピュータの応用範囲が格段に広がりますね。 1988年に入手したとき以降アナウンシエータ出力は一度も使ったことがありませんでした。 今回が初めて。 ひょっとしたらこのコンピュータが製造された1978年以来、初めてアナウンシエータが動作したのかもしれません。 今日はApple IIの外装ケースとお風呂に入って、 シンプルグリーン原液とスポンジとたっぷりのお湯で洗ってあげました。 この時代のプラスチック材料は優秀な紫外線褪色防止剤も自由に使えたのでしょう、 PC-9801に見られるようなみっともない黄ばみは見られず、 すっきり新品同様になりました。 2021-01-24 本体ケース洗浄清掃 |
|
クロック周波数わずか1MHzのApple IIでは、実用的なプログラムを書くにはやはりマシン語プログラミングが欠かせません。
高校生のときの東芝EX-80ではインテル8080のマシン語でプログラムを書くのが唯一だったから当然そうしたし、
大学では富士通FM-7で6809のマシン語プログラムを書きました。
でも見よう見真似の域でしかなく、マイクロプロセッサを理解して使いこなしているとは言えないレベルでしかありませんでした。
17歳の夢であった、「マイコンを理解してマシン語でプログラムを書く」に再挑戦するときかもしれません。
シンプルな6502なら敷居はきっと低いでしょう。 初期型Apple IIでは、6キロバイトのモニタROMの中になんとミニアセンブラが入っています。 これを使えば簡単にマシン語プログラムが書けそう、と思ったのですが、 ラボのは Apple II Plus。 電源投入してすぐにBASICが走る10キロバイトの「オートスタートROM」が使われていて、 その中にはミニアセンブラは入っていません。 なのでプログラム作成そのものは、実にクラシックな方式。 紙にニモニックを書き、インストラクションセット表を見ながら隣にオペコードを書きたしていく、 いわゆる手センブル方式です。 まあ今だからそこは別のコンピュータのエディタを使って… いや、この場合なら Libre Office Calcのほうが便利だな… それにしても手センブルだなんて42年ぶりだぞ。 Apple IIでは、アドレス$0300から$03F7まではユーザに解放されていて、最大248バイトまでのプログラムならこのエリアに入れられます。 まずは$0300始まりで小さなプログラムを書いて練習しよう。 わたしはいままで6502でマシン語プログラミングをしたことはありませんでしたので、 まずは6502プロセッサのプログラミングモデルを学ぶところからのスタートです。 昨年暮、書店の店頭で柴田文彦さん著の 6502とApple II システムROMの秘密 が発行されていることは知っていました。 ウチのラボのApple IIの発掘を予言されていたかのようにも感じます。 作業開始したその日に発注しておいたこの本を読み、 6502プロセッサとAppleIIプログラミングの方法を勉強していきます。 いやあ、それにしてもシンプルなプロセッサだなあ! |
|
|||
マシン語プログラムの入力は、モニタを使って、キーボードでオペコードを十六進数で入力していく方式です。
Apple I 以前は、マイクロコンピュータのプログラム入力と言えば、
フロントパネルにずらりと並んだスイッチをパチパチ操作して1ビットずつデータをセットしていく方式でした。
それに比べれば、
ビデオターミナルディスプレイを見ながらキーボードで十六進入力できるというのは、10倍どころではない生産性の向上です。 Apple IIのモニタは、カセットテープへのセーブとロードもできます。 昔と違ってデジタル録音なので録音ミスや記録の不安定さが全くないのは本当に幸せなこと。 それに何より、モニタに内蔵された逆アセンブル機能がなにより頼もしい! 軽くてストロークの深いApple IIのキーボードをスコンスコンと打ち、 レスポンスの良いモニタプログラムを使ってのプログラム入力は、 原始的だし、生産性はとても低いものですが、 操作していて実に気持ちよく、そして楽しい!! ああだこうだ独り言をつぶやきながらデバッグを続け、 シンプルな "HELLO MIMA SAMA!" プログラムの完成。 2021-01-29 初6502マシン語プログラム完成 次いでTime IIの日付時刻表示プログラムのマシン語版を作成しました。 1回の実行時間は16.91msでした。 Applesoft BASIC版の20倍 高速ということになります。 さすがマシン語は速い!! 2021-01-30 Time II表示プログラム マシン語版 完成 |
|
安定して動作しているApple IIですが、現状 ラボの他のコンピュータとのデータ交換の方法がありません。
CFやSDカードを使ったフロッピィディスクエミュレータのような製品が出回っているようなのでそれを使うのが一般的な解なのでしょうけれど、
なにかひとつ面白みに欠けます。
ラボのApple IIにはパラレルポートインターフェイスカードがありますが、
はたしてこのカードは双方向通信ができるのかなあ。
ゲームポートを使ってテレタイプインターフェイスを作る方法がマニュアルに掲載されていますのでこれはいつか試してみたいところ。 でもまずは、本体改造や特殊な部品追加なしにできる方法 - カセットインターフェイスでWindowsとデータ交換をする方法を試してみます。 カセットインターフェイス出力を録音したデータはWindowsのWAVファイルになっているわけですから、 この波形を解析して、データを取り出せばいいわけです。 さらに、任意のデータをカセットインターフェイスの波形として生成しWAVファイルを作れば、 それをApple IIに流し込むこともできるわけです。 さらに、Windows PCのオーディオインターフェイスをリアルタイムで動作させるプログラムを書けば、 Apple IIからWindowsにカセットインターフェイスでファイルを要求するコマンドを送り、 Windowsが自動的にそのファイルをカセットインターフェイスでApple IIに送り、ロードするといったことも可能なはず。 Disk Operating Systemならぬ Cassette Operating Systemもできそうです。 もっとも私はいまだにWindows PCのオーディオインターフェイスを使ってアナログオーディオ情報をリアルタイムに処理することは試したことがありません。 COSを実現したかったら、Windowsオーディオを制御する方法を学ばないと。 まあ最初の一歩は、Apple IIからWAVファイルにセーブした波形を解析して、データを取り出すことにチャレンジしましょう。 Apple IIのカセットインターフェイスがどのようにデジタル信号をオーディオ信号として出力するかはリファレンスマニュアルに描かれています。 これを読み、実際にWindowsで44.1kHz 16bit 2chで録音したカセット信号の波形を眺め、 どのようにして波形からデータを複合するかを考えます。 いきなりエディタでコードを書かず、まずはフロー図を書いてみるだなんてこれまた20年ぶりのこと。 プロダクトとしてのプログラム開発の仕事をしなくなってからもうそんなに時間が経っちゃったんだな・・・。 2021-01-31 カセットテープ信号 ビット種別判定ロジック設計開始 |
|
|||
アイデア的には、
いまから21年前にエコラン車の走行データをとるためにつくったEX-Pulseプログラム
と同じです。 プログラムは、コマンドラインスタイルのWindowsプログラムとしてつくります。 開発環境は、EZPulseではTurbo Linix上のgccを使いましたが、 今回はこれまたずいぶん久しぶりに、MinGWを使います。 最新版MinGWをダウンロードしてNoobow9300/Noobow9200B/Noobow9100Fの3台にインストール。 いつでも、ちょっとした空き時間に開発を進められるようにします。 Cで実用プログラムを書くこと自体、本当に久しぶりです。 fgetc()の使い方などすっかり忘れてしまっていて、1994年の技術評論社のC言語辞典を引っ張り出して、 リハビリするようにプログラム開発。 Apple IIのカセットインターフェイスはハードウェアは実に素朴。 ただ信号レベルをトグルするだけです。 データのセーブもロードも、タイミングを含めすべてソフトウェアによって処理されています。 したがって突き詰めればそのロジックはとてもシンプルに実現可能なのでしょうが、 いまのWindowsマシンはApple IIとはけた違いなんてもんじゃない、10万倍以上の処理能力を持ちます。 なので、Windows側のプログラム - CassetteNetと名を付けました - は、 デバッグしやすさを主眼に置き、 処理速度は気にせず、 冗長な書きっぷりも気にせず開発します。 ステップ・バイ・ステップでのんびりと作業を進め、 カセットオーディオWAVファイルからバイナリデータを取り出すことに成功。 2021-02-03 カセットテープ信号からのデータ復号機能完成 |
|
|||
今度は、Windows側で用意したバイナリデータをオーディオ信号に変換すること。
こちらは当然のことながら復号よりもずっと簡単にできます。 2021-02-03 任意のバイナリデータからカセットテープ信号を生成する機能 作成開始 生成したオーディオ波形は新しいWAVファイルとして出力するわけですが、 ここでチャレンジ。 WAVファイルの先頭にはRIFFヘッダという部分があって、その中にそのデータはWAVフォーマットであるということ、 どのようなエンコード方式でデジタル化されているのか・・・といった情報が入っています。 さらに、「このあとにつづく波形データは合計何バイト」というサイズ情報も入っているのです。 RIFFヘッダを書き出す段階では波形データの総バイト数は分かっていません。 いったん0かなにかを暫定的に書き込んでおいて、波形データを生成したのちにその総バイト数で書き換えるようかなあ。 今回は、波形データ部分だけをテンポラリファイルに書き出して、それが終わったらテンポラリファイルのバイト数を実際に数え、 それから本番WAVファイルにRIFFヘッダを書き出して、テンポラリファイルをアペンドする方法をとりました。 2021-02-03 RIFFヘッダ書き出し処理 実装 |
1か所間違ってますね。 dLen = $001AEAA0 =1764000 = 44100 x 2 x 2 x 10 というのは、 |
|||
RIFFヘッダ書き出しルーチン、でーっきたっ!
WAVファイルを読み込ませると、ちゃんとWinAmpでピーギャー音が出ます。
さっそくApple IIのモニタでカセットからのデータロードを試しますが・・・
うまくいきません。
オーディオデータの再生が終わっても、モニタは完了のビープ音を出さず、
ロードが完了しないのです。 ちょっと考えて気づきました。 チェックサム最後に足してないや。 Apple IIからセーブしたオーディオファイル中のチェックサムを見て、 うん? これはどうやって計算されているのだろう? データ部のすべてのバイトの和をとると、 実際に生成されたチェックサムとは合いません。 単純な和の下桁ではないようです。 そこで、とても短いバイナリデータをApple IIのメモリ上に用意し、 それをモニタのカセットセーブコマンドでWindowsに取り込み、CassetteNetプログラムでデータを見て、 チェックサムの生成の規則性を調べてみます。 何回か試して、ははあ、こういうことらしい。 仮説を立てて、このデータからこうなるはず・・・と、うん、当たり。 データバイトを加算していくのではなくて、ビットごとに加算しているのですね。 バイト列の各ビットごとに和を取っていき、その結果を最後にビット反転しています。 結果として、チェックサムのビットnは、全データのビットnに1が偶数個あれば1、奇数個あれば0 となります。 これは手順的には、データバイトのXORを取っていって、最後に全ビットを反転すればできあがりです。 まあこんなのは今の時代、語り継がれる名機Apple IIのことですから調べればどこかに書かれているのでしょうけれど、 自分で調べて自力で見つけ出せればうれしいですね。 またひとつこのマシンが自分のものになった気がします。 CassetteNetプログラムのWAVファイル生成ルーチンにチェックサム生成ルーチンを追加して、 よーし、できた! これでWindowsから任意のデータをApple IIに流し込める。 2021-02-06 チェックサム計算方法調査・実装 |
|
今度は長文テキストを転送してみよう。
データバッファのデータをテキスト表示するプログラムを書いて、できたできた。 読み込ませるテキストは、Steve Wozniac著 "iWoz" から、Capter 13 "The Apple II" を。 そう、君はこうして生まれたんだよ、アップルII。 データ転送用バッファとしてシステム起動時に8キロバイトを確保していますが、 8キロバイトに収められるのは同書Chapter 13の3分の1にも届きません。 2021-02-07 Windows 10からテキストファイルをApple IIに転送して画面に表示することに成功 |
|
それまでの「フロントパネルにスイッチとランプがずらりと並ぶ」スタイルのマイクロコンピュータではなく、
「ディスプレイとキーボードを持つ」マイクロコンピュータシステムとして生まれたApple I は、
間違いなく初めて「パーソナル・コンピュータ」のスタイルを確立したマシンでした。
大評判のApple Iの量産モデルの開発に取り掛かったウォズは、
次期モデル Apple II が絶対に具備するべきものしてカラー・グラフィックス表示機能の開発に着手しました。
しかしマイクロコンピュータシステムそのものがまだまだ高根の花だったころに、
ホビイストのお小遣いやビジネスマンのポケットマネーで手が届く価格帯の製品にカラーグラフィックスを持たせることなど、
コスト的に暴挙とも思えるチャレンジでした。 それを実現したのはひとえにウォズが彼のエンジニアリングのコンセプト、 つまり「ハードウェアを極限までシンプルにし、複雑な処理をソフトウェアに行わせる」を突き詰めたからにほかなりません。 ウォズは280ピクセルx192ピクセルという「高精細」で、 かつ普通に考えればモノクロ表示がせいぜいのビデオメモリ容量とシンプルな回路で、 6色カラー表現を可能にする魔法のようなグラフィックスハードウェアを設計したのです。 本体搭載のApplesoft BASICを使えば、 マイクロコンピュータプログラミングの経験がなくとも、またハードウェア制御の方法を全く知らなくても、 テレビ画面に線画を描くことができました。 グラフィックスが簡単に使えるApple IIで多くの人がコンピュータゲームづくりに夢中になったし、 数値の羅列の表に比べ訴求力が段違いの折れ線グラフを簡単に描けるApple IIは、ビジネスコンピューティングの世界も拓きました。 |
データバッファに読み込んだWindows BMPファイルを高精細グラフィックスのビデオメモリに直接描画する手順は実証できましたので、
ここからは高速化に向けてプログラムの機能ブロックをひとつひとつマシン語プログラムで置き換えていきます。 Apple IIのメインメモリのうちアドレス$0300から$03F7まではユーザに解放されていてマシン語プログラムを置いておけますが、 今回やろうとしているビットマップ表示プログラムはそこで許された最大サイズ248バイトには収まりそうにないので、 8KBのデータバッファに加えて新たに$7200〜$75FFの1キロバイトをマシン語プログラム領域として確保することにしました。 メインプログラムは相変わらずApplesoft BASICで書きますが、 BASICとマシン語パートのデータ受け渡しはゼロページでユーザ使用可能となっている$F9〜$FFの7バイトを使用します。 取り掛かりは、ビデオメモリの全バイトについて実行する必要のあるビットオーダー逆転ルーチン。 Cのテキストにも出てくるような、上位・下位に分けて入れ替えを繰り返すアルゴリズムです。 高精細グラフィックスのビデオメモリのビット7は色決めビットで、今回はこれはすべて0固定とするのですが、 サブルーチンは汎用とするためにbit0〜bit7をすべて対象とします。 これに合わせて、BMPビットマップ7バイトから高精細グラフィックス8ビットに詰め替える上位処理ではビット0を色決めビットとしておいてから、 ビットオーダー逆転サブルーチンを呼び出すように改造しました。 2021-02-23 MSB-LSB反転ルーチンをマシン語化 ところで6502のマシン語プログラミング、あいかわらず 6502とApple II システムROMの秘密 を片手に手センブルしていますが、 ふーん、Xレジスタをアキュムレータに転送する命令はないんだ。 変なの。 TYAがあるんだからTXAだってあっていいのにね。 次の日もういちどこの本のインストラクションセット表を見返して、あれ? あれれ? |
|
|||
テストのために8キロバイトのデータバッファをゼロクリアする必要性はたびたび発生しますが、
8キロバイトをゼロクリアするプログラムを Applesoft BASICで書くと、処理に50秒かかります。
Applesoft BASICでは数値を直値でかくよりもいったん数値変数に代入しておいてから変数を参照する方が高速に走ります。
ループ中でこのテクニックを使って、ゼロクリア所要時間は30秒。 頻度が増えると毎回30秒待つのも無駄なので、 8キロバイトをゼロクリアする小さいマシン語プログラムを書きました。 ゼロクリアは一瞬で終わります。 やっぱりマシン語は速いですね。 2021-02-24 データバッファ8キロバイトをゼロクリアするルーチンをマシン語化 |
||||
次のステップは、
BMPデータ中の連続した7バイトを、ハイレゾグラフィックスの連続した8バイトに転送するサブルーチン。
やりたいことは簡単なのですが、プログラムにしようとするとかなりめんどくさい手続きです。
もっとシンプルでエレガントな方法があるはずだよなあとは思いながら、
多少冗長でもわかりやすくてサブブロックに分割できる方法で実装。
結果は1画面描画時間が1分16秒。
4倍のスピードアップになりました。
さすがマシン語、効果がはっきり出ますね。 2021-02-25 BMPデータ7ビットをビデオメモリ8ビットに転送するマシン語ルーチン作成 表示時間 1分16秒 つぎはBMP7バイト->HGR8バイト転送ルーチンを5回連続で呼び出して、1ライン描画すべてをマシン語化。 たかが5回繰り返すだけのFOR文を置き換えただけですが、 1画面の描画時間は24秒まで縮まりました。 FOR文で5回ループ、その中でのPOKE文によるメモリ書き込み、 CALL文によるサブルーチン呼び出し。 1ステートメントごとに、BASICではやはりかなりの時間を費やしてしまうのですね。 2021-02-25 1ライン データバッファ->ビデオメモリ転送ルーチンをマシン語化 表示時間 24秒 |
|
|||
グラフィック表示Y座標からBMPファイルデータチャンク中のベースアドレスオフセットを計算する次の式SB = BA + 62 + ( 191 - y ) * 36をマシン語化。 191からYを引いているのは、画面一番上のラインから下に向かって画像をスキャンさせる見栄えのため。 36を掛けるのは、1ラインは36バイトで成り立っているから。 62は、BMPファイル中でデータチャンク先頭までのオフセット。 BAはBMPファイルが格納されているベースアドレス。 シンプルな算術演算だし、割り算は使っていないし、192回呼び出すだけだからさほどには影響ないかなあと思いつつ。 ここでは36を掛けるという掛け算が必要になりますが、6502プロセッサには掛け算命令はありません。 自分で掛け算サブルーチンを書く必要があります。 う、いままで掛け算サブルーチンを自分で書いたことはなかったなあ。 これはマイコン入門者にとってはきちんと教科書を読んで学ぶべき単元です。 けど。 あはは。 ここでは36を掛けるだけのことですからね。 2回左シフトして4倍したものと5回左シフトして32倍したものを足し算する方法でいきました。 結果は、24秒かかっていたところを19.7秒まで短縮できました。 4秒の短縮。 この計算を1回行うために、Applesoftは20ミリ秒前後使っていたことになります。 2021-02-26 データバッファY座標アドレス計算ルーチンをマシン語化 表示時間 19.7秒 |
||||
さあいよいよ、変態グラフィックスの変態たる所以、表示Y座標からビデオメモリのベースアドレスを算出する計算式をマシン語化します。
BASICプログラムとしてはたった1行で、Y座標ぶん、すなわち192回繰り返すだけたのでさほどに時間は食わないように思えるのですが、
いっぽうで本来ならマスクとビットシフトだけで処理できるところを剰余演算とINT関数を使って描いているので、それなりに時間がかかっているはず
(写真では説明のために数値は直値定数で書いていますが実際のBASCIの中では高速化のためにあらかじめ変数に置き換えてあります)。 結構ややこしく長ったらしくなってしまったこの計算、マシン語で書いたサブルーチンに置き換えたら、 それまでの19.7秒が半分以下の9秒になりました! とうとう10秒を切ったぞ! 2021-02-27 ビデオメモリY座標アドレス計算ルーチンをマシン語化 表示時間 9秒 |
|
|||
最後の仕上げは、バッファとビデオメモリの先頭アドレスを計算して1ラインを表示する手順を192回、
つまり1画面にわたって繰り返す処理。
BASICではPOKE文によるゼロページデータ書き込みとCALL文によるマシン語サブルーチン呼び出し3回。それを192回繰り返すだけです。
ここはそんなに時間は食ってないだろうと思いながら、
1画面描画のすべてをマシン語に置き換えた結果は、
なんと描画時間1.2秒でした。
POKE文とCALL文だけでも、192回繰り返すと8秒も必要としていたんですね。 高精細グラフィックスビデオメモリへの直接書き込み描画プログラムは、 当初全BASICで1画面描くのに9分39秒かかっていました。 これがいまではすべてマシン語で書き替えて1.2秒で描けるようになったわけなので、 480倍の高速化に成功です! プログラムには冗長な部分もかなりあるのでさらなる高速化が狙えますが、 この先は保守性・可読性も次第に低下しはじめ、そのうちカリカリチューンの領域に入っていきます。 まずはここで一段落しましょう。 2021-02-28 ハイレゾグラフィックス直接書き込みBMP表示ルーチン完成 描画時間1.2秒 |
|
Apple IIのテキスト画面に表示できる文字は、ASCIIコードに似ているものの、同じではありません。
小文字はないし、記号文字の文字種も限られているし、制御コードも違うところがあります。
よって、外部から読み込んだテキストを画面表示させるときは、PRINT文で単純に表示することはできず、
一文字ずつ文字コード変換処理を施す必要があります。
となると、BASICでは、ちょうど高速のテレタイプが文字を打ち出すような速度での表示になってしまいます。
読みながら表示を進めていくのであればちょうど良い速度ですが、
1画面を一気に表示したいような場合は遅すぎます。 そこで、ビットマップ画像表示の高速化に続いて、テキスト表示の高速化も行います。 書いたのはシンプルな、改行文字までの1行を画面に表示するルーチン。 小文字->大文字変換も含みます。 1文字出力はモニタのCOUT1ルーチンを呼び出しています。 やはりマシン語は速いねえ…というか、BASICインタプリタは遅い、という当たり前のことなのですが。 2021-03-04 テキスト表示ルーチンをマシン語化 |
|
さて、1989年に書いてワープロとして使っていたWORDCAPSULEプログラムで解決できていなかった、
バグというか機能制限の問題について考えます。
WORDCAPSULEプログラムでは、文字列中にカンマやコロンを含んだテキストを取り扱えなかったのです。 APPLESOFT BASICには、テキストファイルから1行を読み込む機能がないのです。 NEC PC-9801シリーズ用のBASICであるN88BASIC(98)ならば LINE INPUT #1, TEXT$なのですが、APPLESOFT BASICにはLINE INPUT文はありません。 テキストファイルから文字列を取り込むものとしてINPUTコマンドがありますが、 INPUTコマンドは文字列をカンマおよびコロン区切りとして扱うので、 1行中にカンマあるいはコロンがあるとそれ以降を取りこぼしてしまい、 画面に EXTRA IGNOREDというメッセージを出してしまうのです。 これは、Apple DOSにおけるテキストファイルというのは、 SUZUKI, SP370, 1976[CR] YAMAHA, XT400, 1983[CR] HONDA, PS250, 2006[CR] YAMAHA, TDM850, 1996[CR] SUZUKI, V-Strom1000ABS, 2014[CR]といった、フィールド数固定の可変長テキストレコードを記録するためのものとして考えられていて、 行末区切りでのフリーテキストを記録するためのものとは考えられていない、のだと思えます。 Apple IIでは小文字は表示できないわけですし、ワードプロセッサとしての用途は想定していなかったのでしょう。 GETコマンドを使えばキーボードあるいはファイルから1文字を受けとる事ができ、 カンマやコロンや制御文字も受け取れます。 機能的にはこれで目的が果たせるのですが、 問題はその処理速度。 8キロバイトのテキストファイルを読み込むのに5分51秒もかかってしまい、 とても実用的ではありません。 いろいろ考えて試してみて、やはりINPUTコマンドもGETコマンドも使わず、 Apple DOSのファイルデータバッファから直接データを取り出す方法を取ることにしました。 Disk IIのフロッピィディスクは1セクタが256バイトです。 Apple DOSはファイルの読み書きはいつも1セクタ256バイト単位で読み書きし、 そのためのデータバッファが「DOSバッファ」としてシステム起動時に確保されています。 これを使い、 PRINT D$;"OPEN FILENAME,L256"で 1レコード長が256バイトのランダムアクセスファイルとしてファイルをオープンし、 PRINT D$;"READ FILENAME,Rn"でn番目のレコードを読み出します。 これでテキストファイルのn番目のセクタがDOSバッファに入りますので、 そこから256バイトのデータをユーザプログラム側のバッファにコピーすることで目的が達成できます。 もちろんファイルの最終セクタの場合は256バイトの途中でファイル終端を検出する処理が必要になります。 DOSバッファからデータバッファへの256バイトコピールーチンをPEEKコマンドとPOKEコマンドで書いて機能をテストし、 つぎに256バイトコピーを行うサブルーチンをマシン語で書きました。 ところで、DOSバッファに読み込まれたディスクのデータを見ると、どういうわけかデータバイトのビット7がすべて立っています。 データバッファに読み込んだ後にビット7を降ろす処理を入れるとこれまた時間がかかってしまうので、 256バイトデータ転送のマシン語サブルーチンの中でビット7を降ろす処理を付け加えました。 結果、8キロバイトのテキストファイルの読み込みは、5分51秒かかっていたところを10秒44まで高速化できました。 ざっと33倍の高速化です。 これで実用的な性能が得られました。 DOSバッファに読み込まれたデータのビット7が立っているのはどういうわけなんだろう。 このままではこの方法は、バイナリファイルの読み出しには使えません。 それともこれは、ファイル書き込み時にビット7を1にしてしまっているのかな? ひきつづき調べを進める必要があります。 なおドライブ#2はここのところ数日間、快調てす。 ので、ドライブ#2のケースを組付けました。 [課題] DOSバッファのデータのビット7が立っている理由を調べる。 [課題] 現在は読み込むファイルのサイズを8kB固定として扱っている。 任意サイズのファイルを読むために、あらかじめファイルサイズを調べ、それに応じたセクタ数だけ読み込むようにすること。 [課題] テキストファイルとして扱う場合は、ファイル中にEOF (MS-DOSファイル形式を使う場合) および NULL (Apple DOSテキストファイル形式を取り扱う場合) を検知した場合の終了処理を入れること。 |
ダイソーのスモークアクリル板を使ってグリーンモニタのスクリーンをつくってみました。
明るさは落ちてしまいますがコントラストは強まって、引き締まった印象の色になりますね。 2021-03-07 グリーンディスプレイ スクリーン手作り 温度が上がると動作異常が起きる件、 いのぶ〜 にでも取り付けようかと思って買ってあった、センサが1mほどのケーブルで伸びているデジタル温度計がありました。 これをROMチップの上に取り付けて、温度と異常動作の関係を見てみます。 ROMに取り付けたのは、指先で触れてみて一番温度が高いのがROMチップであるようなので。 冷却ファンを持たないApple IIは、当然ながら、ケースカバーを閉じるとメインボード上のチップの温度が上がります。 ROMチップ表面温度は室温に対して20〜25℃程度高くなるようで、 室温が22℃を超えるとROM温度は45℃を超えます。 ROM温度が46℃を超えたあたりから異常動作の可能性が出てきて、 47.5℃で2時間に1回程度の割合、 48.5℃に達すると頻繁に誤動作を起こすようになります。 誤動作を最初に起こすのはどこなんだろう? プロセッサかもしれないしROMかもしれないしRAMかもしれないしバスバッファかもしれないしアドレスデコーダかもしれないし、 言ってみればメインボードのほぼすべてのチップに可能性はあるわけです。 修理できるかもしれないと思ってもらってきた故障廃棄品の赤外線サーモグラフィがあったのですが、 あれは修理できずに捨てちゃいましたね。 あれがあれば文字通りどれが一番熱いのか一目瞭然なんでしょうけれど。 まあとにかく、風を当てればよくなるんじゃないのかな。 ラボの在庫パーツを見ると、60mm角のファンの新品在庫が一個あります。 どこに付けるのがいいかな。 背面スリットのあたりにつけて匡体内への吸気を試してみましたが、 ROMチップ表面温度はあまり変化がありませんでした。 むしろ匡体中央部において、中の空気を攪拌し、ROMチップやプロセッサに直接風が当たるようにする方がずっと昇温を抑えられます。 カバーを閉じても室温プラス10〜15℃どまりで、 ROMチップ表面温度は37度以下。 動作は安定しており、連続4日間、テキスト表示プログラムがループで動き続いています。 この方法でいこう。 ファン単体は「静音」を売りにしているのですが、ファンフレーム自体ははっきりと振動しており、 ケース内側に取り付けたら気にならないとは決して言えない音量でメカノイズが聞こえます。 スポンジ懸垂かなにかの方法で、うまく取り付ける方法を考えよう。 ファンスピード調整機能も欲しいかな。 2021-03-08 ケース内循環ファン仮装着 以降 異常動作は皆無 筐体内にステンレスステーを取り付けてファンを固定しました。 スポンジをかませたのですが、やはり音は気になります。 試しに5Vで回してみたら風量は少ないながら安定して静かに回っていますので、 これで様子を見てみましょう。 室温22℃で3時間連続稼働、ROMチップ表面温度は42℃まで上がりました。 これでは夏場は無理ですね。 可変電圧の電源を用意して、7V程度で回すようかな? 2021-03-26 ステンレスステー取り付け 5V駆動 ROM表面温度は室温+20℃ |
|
先行していた作業と学びの結果を後追いでこのウェブページに書いていて、
前述ビットオーダーのセクションを書いているときに、あれっ?
これってこういう方法でもいけるんじゃね? 第3研究所で気がついたので手元に実機はありませんが、 JavaScriptによるApple IIエミュレータである Apple IIjs を試してみたら想像以上に正確に再現されており、モニタによるマシン語プログラミングもきちんと動きいているようす。 手センブルでプログラムを書き、Apple IIjsのにプログラムを入力して実行させてみると、 期待通りの結果が出ています。 1994年から2002年ころまでのプログラマ現役時代はずっとCで書いていましたので、 Cで解法を考え、それをマシン語化するというアプローチになってしまっていました。 この課題にチャレンジしてから2週間経過、 その間に6502プロセッサのマシンネイティブな動きがアタマの中ですこしずつ見えるようになってきている、 のかもしれません。 できあがったプログラムのアルゴリズムは、Cで書いたのでは絶対に出てこないもの。 LSR命令でソースバイトからビットをひとつ取り出してキャリーフラグに入れ、 それをROL(キャリー付き左ローテート)命令でディスティネーションバイトに入れていく方法です。 とてもシンプルなアイデアだし、ずっとコンパクトになりました。 これを使えば、ビットマップイメージ描画ルーチンがより速くなるはずです。 20201-03-11 MSB-LSB反転コードの効率的な方法を思いつく 中央研究所に戻り、CASSETTENETのマシン語サブルーチンライブラリにビットオーダー反転高速化を組み込み。 実際には、そのバイトがすべて白あるいは黒であればビット反転処理は省く仕組みを入れてあったこともあり、 体感できるような速度向上ではありませんでした。 ちょっと残念。 20201-03-13 MSB-LSB反転コード高速版を実機に組み込む - 速度改善はわずか |
|