第 5 章: アセンブリ言語での Commodore-64 オペレーティング システム

Di 5 Zhang Asenburi Yan Yudeno Commodore 64 Operetingu Shisutemu



5.1 はじめに

Commodore-64 コンピュータのオペレーティング システムは、コンピュータの読み取り専用メモリ (ROM) に組み込まれています。 Commodore-64 のメモリ バイト位置の数は、$0000 ~ $FFFF (つまり、000016 ~ FFFF16、つまり 010 ~ 65,53510) の範囲です。オペレーティング システムは $E000 ~ $FFFF (つまり、57,34410 ~ 65,53610) です。

Commodore-64 オペレーティング システムを研究する理由
Commodore-64 オペレーティング システムは 1982 年にリリースされたコンピューターのオペレーティング システムであったのに、なぜ今それを研究する必要があるのでしょうか。さて、Commodore-64 コンピュータは、6502 μP のアップグレード (大きなアップグレードではありませんが) である中央処理装置 6510 を使用しています。







6502 µP は現在でも大量に生産されています。それはもはや家庭やオフィスのコンピュータではなく、電気および電子機器(デバイス)に使用されています。また、6502 µP は、当時の他のマイクロプロセッサと比較して、理解と操作が簡単です。これらの結果、アセンブリ言語を教えるために使用されるマイクロプロセッサとしては (最高ではないにしても) 最適なものの 1 つとなります。



65C02 µP は、依然として 6502 マイクロプロセッサ クラスに属し、66 個のアセンブリ言語命令を備えており、そのすべてを暗記することもできます。最新のマイクロプロセッサには多くのアセンブリ言語命令があり、暗記することはできません。各μP には独自のアセンブリ言語があります。新しいか古いかにかかわらず、オペレーティング システムはアセンブリ言語で構成されています。そのため、6502 アセンブリ言語は、初心者にオペレーティング システムを教えるのに適しています。 Commodore-64 などのオペレーティング システムを学習した後は、それを基礎として最新のオペレーティング システムを簡単に学習できます。



これは著者(私)だけの意見ではありません。それは世界で増加傾向にあります。 Commodore-64 オペレーティング システムを最新のオペレーティング システムのように見せるために改良された記事がインターネット上で書かれることが増えています。最新のオペレーティング システムについては、次の章以降で説明します。





注記 : Commodore-64 OS (Kernal) は、最新の入出力デバイス (すべてではありません) で依然として良好に動作します。

8ビットコンピュータ
Commodore 64 などの 8 ビット マイクロコンピュータでは、情報は 8 ビット バイナリ コードの形式で保存、転送、および操作されます。



メモリマップ
メモリ マップは、メモリの全範囲をさまざまなサイズの小さな範囲に分割し、何が (サブルーチンおよび/または変数) がどの範囲に属するかを示すスケールです。変数は、値を持つ特定のメモリ アドレスに対応するラベルです。ラベルはサブルーチンの開始を識別するためにも使用されます。ただし、この場合、それらはサブルーチンの名前として知られています。サブルーチンを単にルーチンと呼ぶこともあります。

前の章のメモリ マップ (レイアウト) は十分に詳しく説明されていません。とてもシンプルです。 Commodore-64 コンピュータのメモリ マップは、3 つの詳細レベルで表示できます。中間レベルで示すと、Commodore-64 コンピューターには異なるメモリ マップがあります。 Commodore-64 コンピュータの中間レベルのデフォルトのメモリ マップは次のとおりです。


図 5.11 Commodore-64 のメモリマップ

当時、BASICというコンピュータ言語が流行っていました。多くのコンピュータ ユーザーは、プログラムをディスケット (ディスク) からメモリにロードする、メモリ内でプログラムを実行する (実行する)、プログラムを終了する (閉じる) など、最低限の BASIC 言語コマンドをいくつか知っている必要がありました。 BASIC プログラムの実行中、ユーザーはデータを 1 行ずつ入力する必要があります。アプリケーション (アプリケーションを構成する多数のプログラム) が Windows の高級言語で書かれており、ユーザーがウィンドウ内の特殊な場所にさまざまなデータを当てはめるだけで済むような今日とは異なります。場合によっては、マウスを使用して事前注文されたデータを選択します。 BASICは当時は高級言語でしたが、かなりアセンブリ言語に近いものです。

デフォルトのメモリ マップではメモリの大部分が BASIC によって占有されていることに注意してください。 BASIC には、BASIC インタプリタと呼ばれるものによって実行されるコマンド (命令) があります。実際、BASIC インタプリタは ROM 内の $A000 の位置から $BFFF (両端を含む) までにあり、これはおそらく RAM 領域です。これは8Kバイトということで当時としてはかなり大きいですね!実際には、メモリ全体のその場所の ROM にあります。サイズはオペレーティング システムと同じ $E000 ~ $FFFF (両端を含む) です。 BASICで書かれたプログラムも$0200から$BFFFの範囲に配置されます。

ユーザーアセンブリ言語プログラム用の RAM は $C000 から $CFFF で、64 K バイトのうちわずか 4 K バイトです。では、なぜ私たちはアセンブリ言語を使用したり学習したりするのでしょうか?新旧のオペレーティング システムはアセンブリ言語です。 Commodore-64 のオペレーティング システムは、$E000 から $FFFF までの ROM にあります。これは 65C02 µP (6510 µP) アセンブリ言語で書かれています。サブルーチンで構成されています。アセンブリ言語のユーザー プログラムは、周辺機器 (入力および出力デバイス) と対話するためにこれらのサブルーチンを呼び出す必要があります。 Commodore-64 オペレーティング システムをアセンブリ言語で理解すると、学生はそれほど退屈ではなく、オペレーティング システムをすばやく理解できるようになります。繰り返しになりますが、当時、Commodore-64 のユーザー プログラムの多くはアセンブリ言語ではなく BASIC で書かれていました。当時のアセンブリ言語は、プログラマー自身が技術的な目的で使用することが多かったです。

K-e-r-n-a-l と綴られる Kernal は、Commodore-64 のオペレーティング システムです。 Commodore-64 コンピュータには、ディスク (またはディスケット) ではなく ROM で付属しています。カーナルはサブルーチンで構成されます。ペリフェラルにアクセスするには、アセンブリ言語(機械語)のユーザープログラムがこれらのサブルーチンを使用する必要があります。カーネルは、最新のオペレーティング システムの K-e-r-n-e-l と綴られるカーネルと混同しないでください。ただし、これらはほぼ同じものです。

メモリの$C000(49,15210)から$CFFF(6324810)までのメモリ領域4Kbytes10はRAMまたはROMになります。 RAM の場合、周辺機器へのアクセスに使用されます。 ROMの場合は画面(モニター)上の文字を印刷するために使用されます。これは、文字が画面上に印刷されているか、メモリのこの部分を使用して周辺機器にアクセスしていることを意味します。システムユニット (マザーボード) には ROM (キャラクター ROM) のバンクがあり、これを実現するためにメモリ空間全体に出入りします。ユーザーは切り替えに気付かない可能性があります。

$0100 からのメモリ領域 (256 10 ) から $01FF (511 10 ) はスタックです。これは、オペレーティング システムとユーザー プログラムの両方で使用されます。スタックの役割については、このオンライン キャリア コー​​スの前の章で説明しました。 $0000からのメモリ領域(0 10 ) から $00FF (255 10 ) はオペレーティング システムによって使用されます。そこには多くのポインタが割り当てられています。

カーナルジャンプテーブル
カーナルには、ユーザー プログラムによって呼び出されるルーチンがあります。新しいバージョンの OS が登場すると、これらのルーチンのアドレスが変更されました。これは、ユーザー プログラムが新しい OS バージョンで動作しなくなることを意味します。 Commodore-64 がジャンプ テーブルを提供していたため、このようなことは起こりませんでした。ジャンプ テーブルは 39 個のエントリのリストです。テーブルの各エントリには 3 つのアドレス (最後の 6 バイトを除く) があり、オペレーティング システムのバージョンが変わっても変更されません。

エントリの先頭アドレスには JSR 命令が含まれます。次の 2 つのアドレスは 2 バイトのポインタで構成されます。この 2 バイトのポインタは、OS ROM 内にまだある実際のルーチンのアドレス (または新しいアドレス) です。ポインタの内容は新しい OS バージョンに応じて変更される可能性がありますが、各ジャンプ テーブル エントリの 3 つのアドレスは決して変更されません。たとえば、$FF81、$FF82、および $FF83 アドレスを考えてみましょう。これら 3 つのアドレスは、マザーボードの画面およびキーボード回路 (レジスタ) を初期化するルーチン用です。 $FF81 アドレスには常に JSR のオペコード (1 バイト) が含まれます。 $FF82 および $FF83 アドレスには、初期化を行うサブルーチン (まだ OS ROM 内にある) の古いアドレスまたは新しいアドレスがあります。かつて、$FF82 および $FF83 アドレスには $FF5B の内容 (アドレス) が含まれていましたが、これは次の OS バージョンで変更される可能性があります。ただし、ジャンプ テーブルの $FF81、$FF82、および $FF83 アドレスは決して変更されません。

3 つのアドレスの各エントリについて、JSR を持つ最初のアドレスにはラベル (名前) があります。 $FF81 のラベルは PCINT です。 PCINT は決して変化しません。そのため、プログラマは、Commodore-64 OS のすべてのバージョンで機能する「JSR PCINT」と入力するだけで、画面レジスタとキーボード レジスタを初期化できます。実際のサブルーチン ($FF5B など) の場所 (開始アドレス) は、オペレーティング システムが異なると時間の経過とともに変化する可能性があります。はい、ROM OS を使用するユーザー プログラムには少なくとも 2 つの JSR 命令が含まれています。ユーザープログラムには、ジャンプテーブルのエントリにジャンプする JSR 命令があります。ジャンプ テーブルの最後の 6 アドレスを除いて、ジャンプ テーブルのエントリの最初のアドレスには JSR 命令があります。カーナルでは、一部のサブルーチンが他のサブルーチンを呼び出すことができます。

カーナル ジャンプ テーブルは $FF81 (両端を含む) から始まり、3 つのグループで上向きに進みます。ただし、最後の 6 バイトは下位バイト アドレスを持つ 3 つのポインターです: $FFFA、$FFFC、および $FFFE。すべての ROM OS ルーチンは再利用可能なコードです。したがって、ユーザーがそれらを書き直す必要はありません。

Commodore-64 システムユニットのブロック図
次の図は、前の章のものよりも詳細です。


図 5.12 Commodore_64 システムユニットのブロック図

ここでは ROM と RAM を 1 つのブロックとして示しています。前の章では示されていなかった、画面への情報を処理するためのビデオ インターフェイス チップ (IC) がここに示されています。前の章で示した入出力デバイスの単一ブロックは、ここでは CIA #1 と CIA #2 の 2 つのブロックとして示されています。 CIAはComplex Interface Adaptorの略です。それぞれに、ポート A およびポート B と呼ばれる 2 つの並列 8 ビット ポート (システム ユニットの垂直面にある外部ポートと混同しないでください) があります。この状況では、CIA は 5 つの外部デバイスに接続されています。デバイスは、キーボード、ジョイスティック、ディスク ドライブ/プリンター、およびモデムです。プリンターはディスクドライブの背面に接続されています。図示されていないサウンドインターフェースデバイス回路およびプログラマブルロジックアレイ回路もある。

それでも、ブロック図に表示されていないキャラクターが画面に送信されるときに、両方の CIA と交換できるキャラクター ROM があります。

キャラクタ ROM がない場合の入出力回路の RAM アドレス $D000 から $DFFF には、次の詳細なメモリ マップがあります。

表5.11
$D000 から $DFFF までの詳細なメモリ マップ
サブアドレス範囲 回路 サイズ (バイト)
D000 – D3FF VIC (ビデオ インターフェイス コントローラー (チップ)) 1K
D400 – D7FF SID(サウンドサーキット) 1K
D800 – DBFF カラーRAM 1K ニブル
DC00 – DCFF CIA #1 (キーボード、ジョイスティック) 256
DD00 – DDFF CIA #2 (シリアルバス、ユーザーポート/RS-232) 256
DE00 – DEF I/O スロット #1 を開きます 256
DF00 – DFFF I/O スロット #2 を開きます 256

5.2 2 つの複雑なインターフェイス アダプタ

Commodore-64 システム ユニットには 2 つの特定の集積回路 (IC) があり、それぞれがコンプレックス インターフェイス アダプターと呼ばれます。これら 2 つのチップは、キーボードおよびその他の周辺機器をマイクロプロセッサに接続するために使用されます。 VIC とスクリーンを除いて、マイクロプロセッサと周辺機器の間のすべての入出力信号は、これら 2 つの IC を通過します。 Commodore-64 では、メモリと周辺機器の間に直接通信はありません。メモリと周辺機器間の通信はマイクロプロセッサ アキュムレータを経由し、そのうちの 1 つが CIA アダプタ (IC) です。 IC は CIA #1 および CIA #2 と呼ばれます。 CIAはComplex Interface Adaptorの略です。

各 CIA には 16 個のレジスタがあります。 CIA のタイマー/カウンター レジスタを除き、各レジスタは 8 ビット幅でメモリ アドレスを持っています。 CIA #1 のメモリ レジスタ アドレスは $DC00 (56320) からです。 10 ) から $DC0F (56335) 10 )。 CIA #2 のメモリ レジスタ アドレスは $DD00 (56576) からです。 10 ) から $DD0F (56591) 10 )。これらのレジスタは IC のメモリにはありませんが、メモリの一部です。中間メモリマップでは、$D000 ~ $DFFF の I/O 領域に、$DC00 ~ $DC0F と $DD00 ~ $DD0F の CIA アドレスが含まれます。 $D000 から $DFFF までの RAM I/O メモリ領域のほとんどは、画面キャラクタ用のキャラクタ ROM のメモリ バンクと交換できます。そのため、キャラクターが画面に送信されると、周辺機器は動作できなくなります。ただし、前後のスワップが高速であるため、ユーザーはこれに気付かない可能性があります。

CIA #1 には、ポート A とポート B と呼ばれる 2 つのレジスタがあります。それらのアドレスは、それぞれ $DC00 と $DC01 です。 CIA #2 には、ポート A とポート B と呼ばれる 2 つのレジスタもあります。もちろん、それらのアドレスは異なります。それぞれ $DD00 と $DD01 です。

いずれかの CIA のポート A またはポート B はパラレル ポートです。これは、一度に 8 ビットでペリフェラルにデータを送信したり、一度に 8 ビットでマイクロプロセッサからデータを受信したりできることを意味します。

ポート A またはポート B には、データ方向レジスタ (DDR) が関連付けられています。 CIA #1 (DDRA1) のポート A のデータ方向レジスタは、$DC02 のメモリ バイト位置にあります。 CIA #1 (DDRB1) のポート B のデータ方向レジスタは、$DC03 のメモリ バイト位置にあります。 CIA #2 (DDRA2) のポート A のデータ方向レジスタは、$DD02 のメモリ バイト位置にあります。 CIA #2 (DDRB2) のポート B のデータ方向レジスタは、$DD03 のメモリ バイト位置にあります。

これで、ポート A またはポート B の各ビットを、対応するデータ方向レジスタによって入力または出力に設定できます。入力とは、情報が周辺機器から CIA を介してマイクロプロセッサに送られることを意味します。出力とは、情報が CIA を介してマイクロプロセッサから周辺機器に送信されることを意味します。

ポート (レジスタ) のセルが入力される場合、データ方向レジスタの対応するビットは 0 になります。ポート (レジスタ) のセルが出力される場合、データ方向レジスタの対応するビットは 1 になります。ほとんどの場合、ポートの 8 ビットすべてが入力または出力のいずれかにプログラムされます。コンピュータの電源がオンになると、ポート A が出力用にプログラムされ、ポート B が入力用にプログラムされます。次のコードは、CIA #1 ポート A を出力として、CIA #1 ポート B を入力として作成します。

LDA #$FF
STA DDRA1 ; $DC00 は $DC02 によって指示されます
LDA #$00
STA DDRB1 ; $DC01 は $DC03 によって指示されています

DDRA1 は $DC02 のメモリ バイト位置のラベル (変数名) であり、DDRB1 は $DC03 のメモリ バイト位置のラベル (変数名) です。最初の命令は 11111111 を µP のアキュムレータにロードします。 2 番目の命令は、これを CIA 番号 1 のポート A のデータ方向レジスタにコピーします。 1. 3 番目の命令は 00000000 を µP のアキュムレータにロードします。 4 番目の命令は、これを CIA 番号 2 のポート B のデータ方向レジスタにコピーします。 1. このコードは、コンピュータの電源投入時にこの初期化を実行するオペレーティング システムのサブルーチンの 1 つにあります。

各 CIA には、マイクロプロセッサへの割り込みサービス要求ラインがあります。 CIA #1 からのものは、 IRQ μPのピン。 CIA #2 からのものは、 NMI μPのピン。覚えておいてください NMI よりも優先度が高いです IRQ

5.3 キーボードアセンブリ言語プログラミング

Commodore-64 で可能な割り込みは 3 つだけです。 IRQ 、BRK、および NMI 。のジャンプテーブルポインタ IRQ は、ROM (オペレーティング システム) 内の $FFFE および $FFFF アドレスにあり、OS (ROM) 内にまだあるサブルーチンに対応します。 BRK のジャンプ テーブル ポインタは、OS (ROM) 内にあるサブルーチンに対応する OS 内の $FFFC および $FFFD アドレスにあります。のジャンプテーブルポインタ NMI は、OS (ROM) 内にまだあるサブルーチンに対応する、OS の $FFFA および $FFFB アドレスにあります。のために IRQ , 実際にはサブルーチンが 2 つあります。したがって、BRK ソフトウェア割り込み (命令) には独自のジャンプ テーブル ポインタがあります。のジャンプテーブルポインタ IRQ これは、発生しているのがハードウェア割り込みであるかソフトウェア割り込みであるかを決定するコードにつながります。ハードウェア割り込みの場合は、 IRQ と呼ばれます。ソフトウェア割り込み(BRK)の​​場合は、BRKのルーチンが呼び出されます。いずれかの OS バージョンでは、 IRQ は $EA31 にあり、BRK のサブルーチンは $FE66 にあります。これらのアドレスは $FF81 より下にあるため、ジャンプ テーブル エントリではなく、OS のバージョンによって変更される可能性があります。このトピックで重要なルーチンは 3 つあります。1 つは押されたキーか BRK かをチェックするルーチン、$FE43 にあるルーチン、そして OS バージョンによっても変更される可能性があるルーチンです。

Commodore-64 コンピュータは、外観上は印刷部 (ヘッドと紙) を除いた巨大なタイプライター (上向き) のようなものです。キーボードは CIA #1 に接続されています。デフォルトでは、CIA #1 はプログラミングの干渉を受けることなく、1/60 秒ごとにキーボードを自動的にスキャンします。したがって、1/60 秒ごとに、CIA #1 は IRQ μPに。 1つだけあります IRQ μP のピンは CIA #1 からのみ提供されます。の 1 つの入力ピン NMI μP とは異なります。 IRQ 、CIA #2 からのみ送信されます (次の図を参照)。 BRK は、実際にはユーザー プログラム内でコーディングされたアセンブリ言語命令です。

したがって、1/60 秒ごとに、 IRQ $FFFE と $FFFF が指すルーチンが呼び出されます。このルーチンは、キーが押されたかどうか、または BRK 命令が検出されたかどうかをチェックします。キーが押されると、キーの押下を処理するルーチンが呼び出されます。 BRK 命令の場合は、BRK を処理するルーチンが呼び出されます。どちらでもない場合は、何も起こりません。どちらも起こらない可能性がありますが、CIA #1 は送信します。 IRQ 1/60 秒ごとに µP に送信されます。

キーボード キューはキーボード バッファとも呼ばれ、$0277 から $0280 までの範囲の RAM バイト位置です。全部で1010バイト。これは先入れ先出しバッファです。つまり、最初に来たキャラクターが最初に去ることになります。西欧文字は 1 バイト必要です。

したがって、キーが押されたときにプログラムが文字を消費していない間、キー コードはこのバッファ (キュー) に入ります。バッファは 10 文字になるまで満たされ続けます。 10 文字目以降に押された文字は記録されません。キューから少なくとも 1 文字が取得される (消費される) まで、これは無視されます。ジャンプ テーブルには、キューからマイクロプロセッサに最初の文字を取得するサブルーチンのエントリがあります。これは、キューに入る最初の文字を取得し、それを µP のアキュムレータに入れることを意味します。これを行うためのジャンプ テーブル サブルーチンは GETIN (Get-In の略) と呼ばれます。ジャンプ テーブルの 3 バイト エントリの最初のバイトには、GETIN (アドレス $FFE4) というラベルが付けられます。次の 2 バイトは、ROM (OS) 上の実際のルーチンを指すポインタ (アドレス) です。このルーチンを呼び出すのはプログラマの責任です。そうしないと、キーボード バッファがいっぱいのままになり、最近押したキーはすべて無視されます。アキュムレータに入る値は、対応するキーの ASCII 値です。

そもそもキーコードはどのようにしてキューに入れられるのでしょうか? SCNKEY (スキャン キー) と呼ばれるジャンプ テーブル ルーチンがあります。このルーチンは、ソフトウェアとハ​​ードウェアの両方から呼び出すことができます。この場合、電気信号が送信されると、マイクロプロセッサ内の電子 (物理) 回路によって呼び出されます。 IRQ 低い。それがどのように正確に行われるかについては、このオンライン キャリア コー​​スでは取り上げられていません。

最初のキー コードをキーボード バッファからアキュムレータ A に取得するコードは、次の 1 行です。

入れ

キーボード バッファが空の場合、$00 がアキュムレータに格納されます。ゼロの ASCII コードは $00 ではないことに注意してください。 30ドルです。 $00 は Null を意味します。プログラムでは、キーが押されるまで待機する必要があるポイントが存在する場合があります。このコードは次のとおりです。

JSR GETIN を待ちます
CMP #$00
カエル待ち

1 行目の「WAIT」は、JSR 命令が配置される (入力される) RAM アドレスを識別するラベルです。GETIN もアドレスです。これは、ジャンプ テーブル内の対応する 3 バイトの最初のアドレスです。 GETIN エントリは、ジャンプ テーブル内のすべてのエントリ (最後の 3 つを除く) と同様に 3 バイトで構成されます。エントリの最初のバイトは JSR 命令です。次の 2 バイトは、実際の G​​ETIN サブルーチンの本体のアドレスです。これはまだ ROM (OS) 内にありますが、ジャンプ テーブルの下にあります。したがって、エントリでは GETIN サブルーチンにジャンプするように指示されています。キーボード キューが空でない場合、GETIN は先入れ先出しキューの ASCII キー コードをアキュムレータに入れます。キューが空の場合、アキュムレータには Null ($00) が入れられます。

2 番目の命令は、アキュムレータの値を $00 と比較します。 $00 の場合、キーボード キューが空であることを意味し、CMP 命令はプロセッサ ステータス レジスタ (単にステータス レジスタと呼びます) の Z フラグに 1 を送信します。 A の値が $00 でない場合、CMP 命令はステータス レジスタの Z フラグに 0 を送信します。

3 番目の命令「BEQ WAIT」は、ステータスレジスタの Z フラグが 1 であればプログラムを最初の命令に戻します。キーボードのキーが押されるまで、1 番目、2 番目、3 番目の命令が順番に繰り返し実行されます。 。キーが押されない場合、このサイクルが無限に繰り返されます。このようなコード セグメントは通常、キーが押されなかった場合にしばらくしてからループを終了するタイミング コード セグメントを使用して書き込まれます (次の説明を参照)。

注記 : キーボードはデフォルトの入力デバイスであり、画面はデフォルトの出力デバイスです。

5.4 チャネル、デバイス番号、論理ファイル番号

この章で Commodore-64 オペレーティング システムを説明するために使用する周辺機器は、キーボード、画面 (モニタ)、ディスケット付きのディスク ドライブ、プリンタ、および RS-232C インターフェイスを介して接続するモデムです。これらのデバイスとシステムユニット (マイクロプロセッサとメモリ) の間で通信を行うには、チャネルを確立する必要があります。

チャネルは、バッファ、デバイス番号、論理ファイル番号、およびオプションでセカンダリ アドレスで構成されます。これらの用語の説明は次のとおりです。

バッファ
前のセクションで、キーが押されると、そのコードが RAM 内の 10 個の連続した位置のバイト位置に移動する必要があることに注意してください。この一連の 10 個の場所がキーボード バッファーです。各入力または出力デバイス (周辺機器) には、RAM 内にバッファと呼ばれる一連の連続した場所があります。

装置番号
Commodore-64 では、あらゆる周辺機器にデバイス番号が与えられます。次の表に、さまざまなデバイスとその数を示します。

表5.41
Commodore 64 デバイス番号とそのデバイス
番号 デバイス
0 キーボード
1 テープドライブ
2 たとえば、RS 232C インターフェイスモデム
3 画面
4 プリンター#1
5 プリンター #2
6 プロッター #1
7 プロッター #2
8 ディスクドライブ
9



30
8 台 (両端を含む) から最大 22 台までのストレージ デバイス

コンピュータには 2 種類のポートがあります。 1 つのタイプは外部にあり、システム ユニットの垂直面にあります。もう 1 つのタイプは内部タイプです。この内部ポートはレジスタです。 Commodore-64 には、CIA 1 用のポート A とポート B、CIA 2 用のポート A とポート B の 4 つの内部ポートがあります。Commodore-64 には、シリアル ポートと呼ばれる外部ポートが 1 つあります。 3 以降の数字が付いているデバイスはシリアル ポートに接続されています。これらはデイジー チェーン形式 (一方が他方の後ろに接続される) で接続されており、それぞれはデバイス番号によって識別できます。数字 8 が上に付いているデバイスは、通常、ストレージ デバイスです。

注記 : デフォルトの入力デバイスは、デバイス番号 0 のキーボードです。デフォルトの出力デバイスは、デバイス番号 3 の画面です。

論理ファイル番号
論理ファイル番号とは、デバイス(周辺機器)に対して、アクセスするために開かれた順に付与される番号です。範囲は 010 から 255 までです 10

二次アドレス
ディスク内で 2 つのファイル (または複数のファイル) が開かれていると想像してください。これら 2 つのファイルを区別するために、セカンダリ アドレスが使用されます。セカンダリ アドレスはデバイスごとに異なる番号です。プリンターの二次アドレスとしての 3 の意味は、ディスク ドライブの二次アドレスとしての 3 の意味とは異なります。意味は、ファイルが読み取り用に開かれたときや、ファイルが書き込み用に開かれたときなどの機能によって異なります。可能な二次番号は 0 からです 10 15まで 10 デバイスごとに。多くのデバイスでは、コマンドの送信に 15 という数字が使用されます。

注記 : デバイス番号はデバイス アドレスとも呼ばれ、セカンダリ番号はセカンダリ アドレスとも呼ばれます。

周辺機器のターゲットの特定
デフォルトの Commodore メモリ マップの場合、$0200 から $02FF (ページ 2) のメモリ アドレスは、ROM (カーナル) 内のオペレーティング システムによってのみ使用され、オペレーティング システムと BASIC 言語によっては使用されません。ただし、BASIC は ROM OS を介してその場所を使用できます。

モデムとプリンターは 2 つの異なる周辺機器ターゲットです。ディスクから 2 つのファイルが開かれた場合、それらは 2 つの異なるターゲットになります。デフォルトのメモリ マップでは、3 つの連続したテーブル (リスト) があり、1 つの大きなテーブルとして見ることができます。これら 3 つのテーブルは、論理ファイル番号、デバイス番号、およびセカンダリ アドレス間の関係を保持します。これにより、特定のチャネルまたは入出力対象が識別可能になります。 3 つのテーブルはファイル テーブルと呼ばれます。 RAM アドレスとその内容は次のとおりです。

$0259 — $0262: 最大 10 個のアクティブな論理ファイル番号のラベル LAT を持つテーブル。
$0263 — $026C: 最大 10 個の対応するデバイス番号のラベル、FAT を持つテーブル。
$026D — $0276: 10 個の対応するセカンダリ アドレスのラベル SAT を持つテーブル。

ここで、「—」は「〜」を意味し、数字は 1 バイトになります。

読者は、「なぜ各デバイスのバッファがチャネルの識別に含まれていないのですか?」と疑問に思うかもしれません。その答えは、commodore-64 では、各外部デバイス (周辺機器) が RAM (メモリ マップ) 内に固定された一連のバイトを持っているということです。チャネルが開かれていない場合、それらの位置はメモリ内にまだ存在します。たとえば、キーボードのバッファは、デフォルトのメモリ マップで $0277 ~ $0280 (両端を含む) に固定されています。

カーナル SETLFS および SETNAM サブルーチン
SETLFS と SETNAM はカーナル ルーチンです。チャネルは論理ファイルとして見ることができます。チャネルを開くには、論理ファイル番号、デバイス番号、およびオプションのセカンダリ アドレスを生成する必要があります。オプションのファイル名 (テキスト) も必要になる場合があります。 SETLFS ルーチンは、論理ファイル番号、デバイス番号、およびオプションの 2 次アドレスを設定します。これらの番号はそれぞれの表に入れられます。 SETNAM ルーチンは、ファイルの文字列名を設定します。これは、あるチャネルでは必須であり、別のチャネルではオプションである場合があります。メモリ内のポインタ(2バイトアドレス)で構成されます。ポインタは、メモリ内の別の場所にある可能性がある文字列 (名前) の先頭を指します。文字列名は文字列の長さのバイトで始まり、その後にテキスト (名前) が続きます。名前は最大 16 バイト (長さ) です。

SETLFS ルーチンを呼び出すには、ユーザー プログラムは、デフォルト メモリ マップの ROM 内の OS のジャンプ テーブルの $FFBA アドレスにジャンプ (JSR) する必要があります。ジャンプ テーブルの最後の 6 バイトを除いて、各エントリは 3 バイトで構成されていることに注意してください。最初のバイトは JSR 命令で、サブルーチンにジャンプし、次の 2 バイトのアドレスから始まります。 SETNAM ルーチンを呼び出すには、ユーザー プログラムは ROM 上の OS のジャンプ テーブルの $FFBD アドレスにジャンプ (JSR) する必要があります。これら 2 つのルーチンの使用法については、次の説明で説明します。

5.5 チャネルのオープン、論理ファイルのオープン、論理ファイルのクローズ、およびすべての I/O チャネルのクローズ

チャネルは、メモリ バッファ、論理ファイル番号、デバイス番号 (デバイス アドレス)、およびオプションの 2 次アドレス (数値) で構成されます。論理ファイル番号によって識別される論理ファイル (抽象化) は、プリンタ、モデム、ディスク ドライブなどの周辺機器を参照できます。これらの異なるデバイスはそれぞれ、異なる論理ファイル番号を持つ必要があります。ディスク内には多くのファイルがあります。論理ファイルは、ディスク内の特定のファイルを参照することもできます。その特定のファイルには、プリンタやモデムなどの周辺機器の論理ファイル番号とは異なる論理ファイル番号も付いています。論理ファイル番号はプログラマによって与えられます。 010 ($00) から 25510 ($FF) までの任意の数値を指定できます。

OS SETLFS ルーチン
$FFBA にある OS ROM ジャンプ テーブルにジャンプ (JSR) することによってアクセスされる OS SETLFS ルーチンは、チャネルを設定します。ファイルテーブルに論理ファイル番号、つまり LAT ($0259 — $0262) を入れる必要があります。対応するデバイス番号を FAT ($0263 — $026C) であるファイルテーブルに入れる必要があります。ファイル (デバイス) アクセスに 2 次番号が必要な場合は、対応する 2 次アドレス (番号) をファイル テーブル (SAT ($026D — $0276)) に入れる必要があります。

SETLFS サブルーチンを動作させるには、µP アキュムレータから論理ファイル番号を取得する必要があります。 µP X レジスタからデバイス番号を取得する必要があります。チャネルで必要な場合は、µP Y レジスタから 2 次アドレスを取得する必要があります。

論理ファイル番号はプログラマによって決定されます。異なるデバイスを参照する論理ファイル番号は異なります。ここで、SETLFS ルーチンを呼び出す前に、プログラマは論理ファイルの番号を µP アキュムレータに入力する必要があります。デバイス番号は、表5.41のようなテーブル(文書)から読み取られます。プログラマは、μP X レジスタにデバイス番号を入力する必要もあります。プリンター、ディスク ドライブなどのデバイスのサプライヤーは、デバイスに使用できるセカンダリ アドレスとその意味を提供します。チャネルにセカンダリ アドレスが必要な場合、プログラマはデバイス (周辺機器) に付属のドキュメントからアドレスを取得する必要があります。 2 次アドレス (数値) が必要な場合、プログラマは、SETLFS サブルーチンを呼び出す前に、それを µP Y レジスタに設定する必要があります。 2 次アドレスが必要ない場合、プログラマは、SETLFS サブルーチンを呼び出す前に、$FF 番号を µP Y レジスタに入れる必要があります。

SETLFS サブルーチンは引数なしで呼び出されます。その引数はすでに 6502 µP の 3 つのレジスタにあります。適切な数値をレジスタに入力した後、別の行に次のコードを記述するだけで、プログラム内でルーチンが呼び出されます。

JSR SETLFS

ルーチンは、さまざまな数値をファイル テーブルに適切に配置します。

OS SETNAM ルーチン
OS SETNAM ルーチンには、$FFBD にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。すべての宛先にファイル名があるわけではありません。宛先があるもの (ディスク内のファイルなど) については、ファイル名を設定する必要があります。ファイル名が「mydocum」であると仮定します。これは引用符を除いた 7 バイトで構成されます。この名前は $C101 から $C107 の位置 (両端を含む) にあり、$07 の長さは $C100 の位置にあると仮定します。文字列文字の開始アドレスは $C101 です。開始アドレスの下位バイトは $01、上位バイトは $C1 です。

SETNAM ルーチンを呼び出す前に、プログラマは $07 (文字列の長さ) の数値を µP アキュムレータに入力する必要があります。 $01 の文字列開始アドレスの下位バイトが µP X レジスタに置かれます。 $C1 の文字列開始アドレスの上位バイトが µP Y レジスタに入れられます。サブルーチンは次のように単純に呼び出されます。

JSRセトナム

SETNAM ルーチンは、3 つのレジスタの値をチャネルに関連付けます。その後、値をレジスタに残す必要はありません。チャネルにファイル名が必要ない場合、プログラマは µP アキュムレータに $00 を入れる必要があります。この場合、X および Y レジスタ内の値は無視されます。

OS OPEN ルーチン
OS OPEN ルーチンには、$FFC0 にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。このルーチンは、論理ファイル番号、デバイス番号 (およびバッファ)、可能な 2 次アドレス、および可能なファイル名を使用して、コモドール コンピュータと外部デバイス内のファイルまたは外部デバイス自体との間の接続を提供します。

このルーチンは、他のすべての Commodore OS ROM ルーチンと同様、引数を取りません。 µP レジスタを使用しますが、どのレジスタにも引数 (値) を事前にロードする必要はありませんでした。これをコーディングするには、SETLFS と SETNAM が呼び出された後に次のように入力するだけです。

JSRオープン

OPEN ルーチンではエラーが発生する場合があります。たとえば、読み取り用のファイルが見つからない可能性があります。エラーが発生すると、ルーチンは失敗し、対応するエラー番号を µP アキュムレータに入れ、µP ステータス レジスタのキャリー フラグを (1 に) 設定します。次の表に、エラー番号とその意味を示します。

表5.51
OS ROM OPEN ルーチンのカーナル エラー番号とその意味
エラー番号 説明
1 ファイルが多すぎます すでに 10 個のファイルが開いている場合に OPEN
2 ファイルを開く オープン 1,3: オープン 1,4
3 ファイルが開いていません OPEN なしの PRINT#5
4 ファイルが見つかりません ロード「存在しない」、8
5 デバイスが存在しません オープン 11,11: プリント #11
6 入力ファイルではありません 「SEQ,S,W」を開く: GET#8,X$
7 ファイルを出力しません オープン 1,0: プリント #1
8 ファイル名がありません ロード '',8
9 不正なデバイス番号です。 「プログラム」をロード,3

この表は、読者が他の多くの場所で目にする可能性が高い方法で表示されています。

OS CHKIN ルーチン
OS CHKIN ルーチンには、$FFC6 にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。ファイル (論理ファイル) を開いた後、そのオープンが入力用であるか出力用であるかを決定する必要があります。 CHKIN ルーチンは、オープニングを入力チャンネルにします。このルーチンは、µP X レジスタから論理ファイル番号を読み取る必要があります。したがって、プログラマは、このルーチンを呼び出す前に、論理ファイル番号を X レジスタに入れる必要があります。これは単に次のように呼ばれます。

JSR チキン

OS CHKOUT ルーチン
OS CHKOUT ルーチンには、$FFC9 にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。ファイル (論理ファイル) を開いた後、そのオープンが入力用であるか出力用であるかを決定する必要があります。 CHKOUT ルーチンは、開口部を出力チャネルにします。このルーチンは、µP X レジスタから論理ファイル番号を読み取る必要があります。したがって、プログラマは、このルーチンを呼び出す前に、論理ファイル番号を X レジスタに入れる必要があります。これは単に次のように呼ばれます。

JSRチェックアウト

OS CLOSE ルーチン
OS CLOSE ルーチンには、$FFC3 にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。論理ファイルが開かれ、バイトが送信された後は、論理ファイルを閉じる必要があります。論理ファイルを閉じると、システム装置内のバッファが解放され、これから開かれる他の論理ファイルが使用できるようになります。 3 つのファイル テーブル内の対応するパラメータも削除されます。オープンしているファイル数の RAM の場所は 1 つ減ります。

コンピュータの電源がオンになると、マザーボード上のマイクロプロセッサおよびその他の主要チップ (集積回路) がハードウェア リセットされます。これに続いて、マザーボード上の一部のチップの一部の RAM メモリ位置と一部のレジスタが初期化されます。初期化プロセスでは、ページ 0 の $0098 アドレスのバイト メモリ位置が、オペレーティング システムのバージョンに応じて NFILES または LDTND ラベルで指定されます。コンピュータの動作中、この 8 ビットの 1 バイトの位置には、開かれた論理ファイルの数と、連続する 3 つのファイル テーブルの開始アドレス インデックスが保持されます。つまり、このバイトには、論理ファイルが閉じられると 1 ずつ減らされるオープンファイル数が含まれます。論理ファイルが閉じられると、端末 (宛先) デバイスまたはディスク内の実際のファイルにアクセスできなくなります。

論理ファイルを閉じるには、プログラマは論理ファイル番号を µP アキュムレータに入力する必要があります。これは、ファイルを開くときに使用されるのと同じ論理ファイル番号です。 CLOSE ルーチンは、その特定のファイルを閉じるためにこれを必要とします。他の OS ROM ルーチンと同様、CLOSE ルーチンは引数を取りませんが、アキュムレータから使用される値はある程度引数になります。アセンブリ言語の命令行は次のとおりです。

JSRを閉じる

カスタムまたは定義済みの 6502 アセンブリ言語サブルーチン (ルーチン) は引数を取りません。ただし、引数は、サブルーチンが使用する値をマイクロプロセッサ レジスタに入れることで非公式に提供されます。

CLRCHN ルーチン
OS CLRCHN ルーチンには、$FFCC にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。 CLRCHNはCLeaR CHanneLの略です。論理ファイルを閉じると、論理ファイル番号、デバイス番号、および使用可能な 2 次アドレスのパラメータが削除されます。したがって、論理ファイルのチャネルはクリアされます。

マニュアルには、OS CLRCHN ルーチンは開いているチャネルをすべてクリアし、デフォルトのデバイス番号とその他のデフォルトを復元すると記載されています。これは、ペリフェラルのデバイス番号を変更できるという意味ですか?まあ、完全ではありません。オペレーティング システムの初期化中に、コンピューターの動作時に現在の入力デバイス番号を保持するために、$0099 アドレスのバイト位置が DFLTI ラベルで指定されます。 commodore-64 は一度に 1 つの周辺機器にのみアクセスできます。オペレーティング システムの初期化中に、コンピューターの動作時に現在の出力デバイス番号を保持するために、$009A アドレスのバイト位置が DFLTO ラベルで指定されます。

CLRCHN サブルーチンが呼び出されると、DFLTI 変数がデフォルトの入力デバイス番号 (キーボード) である 0 ($00) に設定されます。 DFLTO 変数をデフォルトの出力デバイス番号 (画面) である 3 ($03) に設定します。他のデバイス番号変数も同様にリセットされます。つまり、入出力デバイスを正常(デフォルト値)にリセット(または復元)するという意味です。

Commodore-64 のマニュアルには、CLRCHN ルーチンが呼び出された後、開かれた論理ファイルは開いたままになり、バイト (データ) を送信できると記載されています。これは、CLRCHN ルーチンがファイル テーブル内の対応するエントリを削除しないことを意味します。 CLRCHN という名前は、その意味がかなり曖昧です。

5.6 キャラクターを画面に送信する

画面への文字やグラフィックの表示を処理する主な集積回路 (IC) はビデオ インターフェイス コントローラー (チップ) と呼ばれ、Commodore-64 では VIC と略されます (実際には VIC バージョン 2 の VIC II)。情報 (値) が画面に到達するには、画面に到達する前に VIC II を通過する必要があります。

画面は 25 行 40 列の文字セルで構成されます。これにより、画面に表示できる文字数は 40 x 25 = 1000 文字になります。 VIC II は、対応する 1000 メモリ RAM の文字の連続バイト位置を読み取ります。これら 1,000 個の場所を合わせて、スクリーン メモリと呼ばれます。この 1000 個の場所に入るのが文字コードです。 Commodore-64 の場合、文字コードは ASCII コードとは異なります。

文字コードは文字パターンではありません。いわゆるキャラクターROMもあります。キャラクターROMはあらゆる種類の文字パターンから構成されており、その中にはキーボード上の文字パターンに対応するものもあります。キャラクターROMは画面メモリとは異なります。画面に文字を表示する場合、文字コードは画面メモリの 1000 個の位置の中の任意の位置に送信されます。そこから、画面に表示されるキャラクターROMから対応するパターンが選択されます。文字コードから文字 ROM 内の正しいパターンを選択することは、VIC II (ハードウェア) によって行われます。

$D000 と $DFFF の間の多くのメモリ位置には 2 つの目的があります。1 つは画面以外の入出力操作を処理するために使用されるか、または画面のキャラクタ ROM として使用されます。メモリの 2 つのブロックが関係します。 1 つは RAM で、もう 1 つはキャラクター ROM 用の ROM です。入出力または文字パターン (文字 ROM) を処理するためのバンクの交換は、ソフトウェア ($F000 から $FFFF までの ROM 内の OS のルーチン) によって行われます。

注記 : VIC には、$D000 と $DFFF の範囲内のメモリ空間のアドレスでアドレス指定されるレジスタがあります。

CHROUT ルーチン
OS CHROUT ルーチンには、$FFD2 にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。このルーチンが呼び出されると、プログラマが µP アキュムレータに入力したバイトが取得され、カーソルが置かれている画面に出力されます。たとえば、「E」文字を出力するコード セグメントは次のとおりです。

LDA #$05
クロウト

0516 は「E」の ASCII コードではありません。 Commodore-64 には画面用に独自の文字コードがあり、$05 は「E」を意味します。 #$05 番号は、VIC が画面に送信する前に画面メモリに配置されます。これら 2 つのコーディング行は、チャネルが設定され、論理ファイルが開かれ、出力のために CHKOUT ルーチンが呼び出された後に来る必要があります。完全なコードは次のとおりです。

;セットアップチャンネル
LDA #$40 ;論理ファイル番号
LDX #$03 ;画面のデバイス番号は $03 です
LDY #$FF ;二次アドレスなし
JSR SETLFS ;チャンネルを適切に設定する
;画面に名前は必要ないため、SETNAM はありません
;
;論理ファイルを開く
JSRオープン
;出力するチャンネルを設定する
LDX #$40 ;論理ファイル番号
JSRチェックアウト
;
;文字を画面に出力する
LDA #$05
JSR CHROUT
;論理ファイルを閉じる
LDA #$40
JSRを閉じる

別のプログラムを実行する前に、開口部を閉じる必要があります。コンピュータ ユーザーが予期したとおりにキーボードに文字を入力すると仮定します。次のプログラムは、キーボードから文字を画面に出力します。

;セットアップチャンネル
LDA #$40 ;論理ファイル番号
LDX #$03 ;画面のデバイス番号は $03 です
LDY #$FF ;二次アドレスなし
JSR SETLFS ;チャンネルを適切に設定する
;画面に名前は必要ないため、SETNAM はありません
;
;論理ファイルを開く
JSRオープン
;出力するチャンネルを設定する
LDX #$40 ;論理ファイル番号
JSRチェックアウト
;
;キーボードから文字を入力
JSR GETIN を待ちます。キーボードキューが空の場合は A に $00 を入れます
CMP #$00 ; $00 が A に送られた場合、比較では Z は 1 になります。
待ってください。 0 がアキュムレータに移動した場合は、再度キューから GETIN
BNE PRNSCRN ; A が $00 を持っていないため、Z が 0 の場合は PRNSCRN に進みます。
;文字を画面に出力する
PRNSCRN JSR CHROUT ; Aの文字を画面に送信します
;論理ファイルを閉じる
LDA #$40
JSRを閉じる

注記 : WAIT と PRNSCRN はアドレスを識別するラベルです。 µP アキュムレータに到着するキーボードからのバイトは ASCII コードです。 Commodore-64 によって画面に送信される対応するコードは異なる必要があります。簡単にするために、前のプログラムではこれは考慮されていません。

5.7 ディスクドライブのバイトの送受信

Commodore-64 のシステム ユニット (マザーボード) には、VIA #1 および CIA #2 と呼ばれる 2 つの複雑なインターフェイス アダプターがあります。各 CIA には、ポート A およびポート B と呼ばれる 2 つのパラレル ポートがあります。Commodre-64 システム ユニットの背面の垂直面には、シリアル ポートと呼ばれる外部ポートがあります。このポートには 6 つのピンがあり、そのうちの 1 つはデータ用です。データは、一度に 1 ビットずつ直列にシステム ユニットに出入りします。

たとえば、CIA #2 の内部ポート A からの 8 つのパラレル ビットは、CIA のシフト レジスタによってシリアル データに変換された後、外部シリアル ポートを介してシステム ユニットから出力されます。外部シリアル ポートからの 8 ビット シリアル データは、CIA 内のシフト レジスタによってパラレル データに変換された後、CIA #2 の内部ポート A に入力されます。

Commodore-64 システム ユニット (ベース ユニット) は、ディスケットを備えた外部ディスク ドライブを使用します。プリンタは、デイジーチェーン方式 (デバイスをストリングとして直列に接続する) でこのディスク ドライブに接続できます。ディスク ドライブのデータ ケーブルは、Commodore-64 システム ユニットの外部シリアル ポートに接続されます。これは、デイジーチェーン接続されたプリンタも同じシリアル ポートに接続されていることを意味します。これら 2 つのデバイスは、2 つの異なるデバイス番号 (通常はそれぞれ 8 と 4) によって識別されます。

ディスク ドライブのデータの送信または受信は、前述したのと同じ手順に従います。あれは:

  • SETNAMルーチンを使用して、実際のディスクファイルと同じ論理ファイル名(番号)を設定します。
  • OPEN ルーチンを使用して論理ファイルを開きます。
  • CHKOUT ルーチンまたは CHKIN ルーチンを使用して、入力か出力かを決定します。
  • STA および/または LDA 命令を使用したデータの送信または受信。
  • CLOSE ルーチンを使用して論理ファイルを閉じます。

論理ファイルは閉じる必要があります。論理ファイルを閉じると、その特定のチャネルが効果的に閉じられます。ディスクドライブのチャネルを設定するとき、論理ファイル番号はプログラマによって決定されます。これは、$00 から $FF (両端を含む) までの数値です。他のデバイス (または実際のファイル) に対してすでに選択されている番号であってはなりません。ディスクドライブが 1 つしかない場合、デバイス番号は 8 です。セカンダリアドレス(番号)はディスクドライブのマニュアルから取得します。次のプログラムは 2 を使用します。プログラムは、文字「E」(ASCII) をディスク内の「mydoc.doc」というファイルに書き込みます。この名前は、メモリ アドレス $C101 から始まると想定されます。したがって、SETNAM ルーチンが呼び出される前に、$01 の下位バイトが X レジスタに存在し、$C1 の上位バイトが Y レジスタに存在する必要があります。 SETNAM ルーチンが呼び出される前に、A レジスタにも $09 番号が設定されている必要があります。

;セットアップチャンネル
LDA #$40 ;論理ファイル番号
LDX #$08 ;最初のディスクドライブのデバイス番号
LDY #$02 ;セカンダリアドレス
JSR SETLFS ;チャンネルを適切に設定する
;
;ディスクドライブ内のファイルには名前が必要です(すでにメモリ内にあります)
LDA #$09
LDX #$01
LDY #$C1
JSRセトナム
;論理ファイルを開く
JSRオープン
;出力するチャンネルを設定する
LDX #$40 ;論理ファイル番号
JSR CHKOUT ;書き込み用
;
;文字をディスクに出力する
LDA #$45
JSR CHROUT
;論理ファイルを閉じる
LDA #$40
JSRを閉じる

ディスクから µP Y レジスタにバイトを読み取るには、次の変更を加えて前のプログラムを繰り返します。書き込み用」の場合は、「JSR CHKIN ;」を使用します。読書用」。コードセグメントを「;」に置き換えます。 「文字をディスクに出力」を次のように実行します。

;ディスクから文字を入力
JSR クリス

OS CHRIN ルーチンには、$FFCF にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。このルーチンが呼び出されると、すでに入力チャンネルとして設定されているチャンネルからバイトを取得し、それを µPA レジスタに置きます。 CHRIN の代わりに GETIN ROM OS ルーチンを使用することもできます。

プリンターにバイトを送信する
プリンタへのバイトの送信は、ディスク内のファイルにバイトを送信するのと同様の方法で行われます。

5.8 OS SAVE ルーチン

OS SAVE ルーチンには、$FFD8 にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。 ROM 内の OS SAVE ルーチンは、メモリのセクションをファイル (名前付き) としてディスクに保存 (ダンプ) します。メモリ内のセクションの開始アドレスがわかっている必要があります。セクションの終了アドレスもわかっている必要があります。開始アドレスの下位バイトは、RAM のページ 0 の $002B アドレスに配置されます。開始アドレスの上位バイトは、$002C アドレスの次のバイト メモリ位置に配置されます。ページ 0 では、TXTTAB ラベルはこれら 2 つのアドレスを指しますが、TXTTAB は実際には $002B アドレスを意味します。終了アドレスの下位バイトはμP X レジスタに配置されます。終了アドレスの上位バイトに 1 を加えた値が µP Y レジスタに置かれます。 µP A レジスタは、TXTTAB ($002B) として $2B の値を取ります。これにより、次のように SAVE ルーチンを呼び出すことができます。

JSR保存

保存されるメモリのセクションは、アセンブリ言語プログラムまたはドキュメントです。文書の例としては、手紙やエッセイなどがあります。保存ルーチンを使用するには、次の手順に従う必要があります。

  • SETLFS ルーチンを使用してチャネルをセットアップします。
  • SETNAM ルーチンを使用して、実際のディスクファイルと同じ論理ファイル名 (番号) を設定します。
  • OPEN ルーチンを使用して論理ファイルを開きます。
  • CHKOUTを使用して出力用のファイルを作成します。
  • ファイルを保存するためのコードがここにあり、「JSR SAVE」で終わります。
  • CLOSE ルーチンを使用して論理ファイルを閉じます。

次のプログラムは、$C101 から $C200 のメモリ位置で始まるファイルを保存します。

;セットアップチャンネル
LDA #$40 ;論理ファイル番号
LDX #$08 ;最初のディスクドライブのデバイス番号
LDY #$02 ;セカンダリアドレス
JSR SETLFS ;チャンネルを適切に設定する
;
;ディスクドライブ内のファイルの名前 ($C301 のメモリ内に既に存在します)
LDA #$09 ;ファイル名の長さ
LDX #$01
LDY#$C3
JSRセトナム
;論理ファイルを開く
JSRオープン
;出力するチャンネルを設定する
LDX #$40 ;論理ファイル番号
JSR チェックアウト ;書くための
;
;ファイルをディスクに出力する
LDA #$01
STA 20 億ドル。 TXTTAB
LDA #$C1
STA $2C
LDX #$00
LDY#$C2
LDA #20億ドル
JSR保存
;論理ファイルを閉じる
LDA #$40
JSRを閉じる

これは、メモリの別のセクション (プログラム セクションではない) をディスク (Commodore-64 の場合はディスケット) に保存するプログラムであることに注意してください。

5.9 OS LOAD ルーチン

OS LOAD ルーチンには、$FFD5 にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。メモリのセクション (大領域) がディスクに保存される場合、メモリ内のセクションの開始アドレスを含むヘッダーが付けられて保存されます。 OS LOAD サブルーチンは、ファイルのバイトをメモリにロードします。この LOAD 操作では、アキュムレータの値は 010 ($00) でなければなりません。 LOAD 操作でディスクのファイル ヘッダーの開始アドレスを読み取り、そのアドレスから始まるファイル バイトを RAM に配置するには、チャネルの 2 次アドレスは 1 または 2 である必要があります (次のプログラムでは 2 を使用します)。このルーチンは、ロードされている RAM の最上位の位置のアドレスに 1 を加えたものを返します。これは、RAM 内のファイルの最終アドレスの下位バイトに 1 を加えたものが µP X レジスタに格納され、RAM 内のファイルの最終アドレスの上位バイトに 1 を加えたものが µP Y レジスタに格納されることを意味します。

ロードが失敗した場合、µP A レジスタにはエラー番号 (おそらく 4、5、8、または 9) が保持されます。また、マイクロプロセッサステータスレジスタのCフラグもセット(1)されます。ロードが成功した場合、A レジスタの最後の値は重要ではありません。

さて、このオンライン キャリア コー​​スの前の章では、アセンブリ言語プログラムの最初の命令は、プログラムが開始された RAM 内のアドレスにあります。そうである必要はありません。これは、プログラムの最初の命令が RAM 内のプログラムの先頭にある必要がないことを意味します。プログラムの開始命令は、RAM 内のファイル内のどこにでも置くことができます。プログラマは、アセンブリ言語命令の開始に START というラベルを付けることをお勧めします。これにより、プログラムがロードされた後、次のアセンブリ言語命令で再実行 (実行) されます。

JSRスタート

「JSR START」は、実行するプログラムをロードするアセンブリ言語プログラム内にあります。別のアセンブリ言語ファイルをロードし、ロードされたファイルを実行するアセンブリ言語には、次のコード プロシージャがあります。

  • SETLFS ルーチンを使用してチャネルを設定します。
  • SETNAM ルーチンを使用して、実際のディスクファイルと同じ論理ファイル名 (番号) を設定します。
  • OPEN ルーチンを使用して論理ファイルを開きます。
  • CHKINによる入力用ファイルとします。
  • ファイルをロードするためのコードがここにあり、「JSR LOAD」で終わります。
  • CLOSE ルーチンを使用して論理ファイルを閉じます。

次のプログラムは、ディスクからファイルをロードして実行します。

;セットアップチャンネル
LDA #$40 ;論理ファイル番号
LDX #$08 ;最初のディスクドライブのデバイス番号
LDY #$02 ;セカンダリアドレス
JSR SETLFS ;チャンネルを適切に設定する
;
;ディスクドライブ内のファイルの名前 ($C301 のメモリ内に既に存在します)
LDA #$09 ;ファイル名の長さ
LDX #$01
LDY#$C3
JSRセトナム
;論理ファイルを開く
JSRオープン
;入力チャンネルを設定する
LDX #$40 ;論理ファイル番号
JSR チキン ;読書用
;
;ディスクからファイルを入力
LDA #$00
JSRロード
;論理ファイルを閉じる
LDA #$40
JSRを閉じる
;ロードされたプログラムを開始する
JSRスタート

5.10 モデムと RS-232 規格

モデムは、コンピュータからのビットを、電話回線を介して送信される対応する電気オーディオ信号に変換するデバイス (周辺機器) です。受信側では、受信側コンピューターの前にモデムがあります。この 2 番目のモデムは、電気オーディオ信号を受信側コンピューター用のビットに変換します。

モデムは、外部ポート (コンピュータの垂直面) でコンピュータに接続する必要があります。 RS-232 規格は、(以前は) モデムをコンピュータに接続する特定のタイプのコネクタを指しました。言い換えれば、これまでの多くのコンピュータには、RS-232 コネクタまたは RS-232 互換コネクタの外部ポートがありました。

Commodore-64 システム ユニット (コンピュータ) には、背面の垂直面にユーザー ポートと呼ばれる外部ポートがあります。このユーザー ポートは RS-232 と互換性があります。そこにモデム装置を接続できます。 Commodore-64 は、このユーザー ポートを介してモデムと通信します。 Commodore-64 の ROM オペレーティング システムには、RS-232 ルーチンと呼ばれるモデムと通信するためのサブルーチンがあります。これらのルーチンにはジャンプ テーブルにエントリがあります。

ボーレート
コンピュータからの 8 ビット バイトは、モデムに送信される前に一連の 8 ビットに変換されます。モデムからコンピュータへは逆の処理が行われます。ボーレートは、1 秒あたりに連続して送信されるビット数です。

記憶の底
「メモリの底部」という用語は、$0000 アドレスのメモリ バイト位置を指すものではありません。これは、ユーザーがデータやプログラムの配置を開始できる RAM の最下位の場所を指します。デフォルトでは $0800 です。 $0800 と $BFFF の間の多くの場所が BASIC コンピュータ言語とそのプログラマ (ユーザー) によって使用されているという前の説明を思い出してください。 $C000 から $CFFF までのアドレス位置のみがアセンブリ言語プログラムとデータに使用されます。これはメモリの 64 K バイトのうちの 4 K バイトです。

メモリーのトップ
当時、顧客が Commodore-64 コンピュータを購入したとき、一部のコンピュータにはすべてのメモリ ロケーションが付属していませんでした。このようなコンピュータには、オペレーティング システムが $E000 から $FFFF までの ROM がありました。彼らは $0000 から $E000 の隣の $DFFF ではない制限までの RAM を持っていました。制限は $DFFF を下回っており、その制限は「メモリーのトップ」と呼ばれます。したがって、メモリの先頭は $FFFF の場所を指しません。

RS-232 通信用 Commodore-64 バッファ
送信バッファ
RS-232 送信用のバッファ (出力) は、メモリの先頭から下方向に 256 バイトかかります。この送信バッファのポインタには ROBUF というラベルが付けられます。このポインタはページ 0 にあり、$00F9 アドレスとその後に $00FA が続きます。 ROBUF は実際には $00F9 を識別します。したがって、バッファの先頭のアドレスが $BE00 の場合、$BE00 の下位バイト ($00) は $00F9 の位置にあり、$BE00 の上位バイト ($BE) は $00FA の位置にあります。位置。

受信バッファ
RS-232 バイト (入力) を受信するバッファは、送信バッファの最後から 256 バイトかかります。この受信バッファのポインタには RIBUF というラベルが付いています。このポインタはページ 0 にあり、$00F7 アドレスとその後に $00F8 が続きます。 RIBUF は実際には $00F7 を識別します。したがって、バッファの開始アドレスが $BF00 の場合、$BF00 の下位バイト ($00) は $00F7 の位置にあり、$BF00 の上位バイト ($BF) は $00F8 の位置にあります。位置。したがって、メモリの先頭から 512 バイトが合計 RS-232 RAM バッファとして使用されます。

RS-232チャンネル
モデムが (外部) ユーザー ポートに接続されている場合、モデムへの通信は単なる RS-232 通信です。完全な RS-232 チャネルを作成する手順は前の説明とほぼ同じですが、重要な違いが 1 つあります。ファイル名はメモリ内の文字列ではなくコードであるということです。コード $0610 が適切な選択です。これは、300 ビット/秒のボー レートとその他の技術パラメータを意味します。また、セカンダリアドレスもありません。デバイス番号は 2 であることに注意してください。完全な RS-232 チャネルをセットアップする手順は次のとおりです。

  • SETLFS ルーチンを使用してチャネルを設定します。
  • 論理ファイルの名前を $0610 に設定します。
  • OPEN ルーチンを使用して論理ファイルを開きます。
  • CHKOUTで出力用ファイル、CHKINで入力用ファイルにします。
  • CHROUT を使用して単一バイトを送信するか、GETIN を使用して単一バイトを受信します。
  • CLOSE ルーチンを使用して論理ファイルを閉じます。

OS GETIN ルーチンには、$FFE4 にある OS ROM ジャンプ テーブルにジャンプ (JSR) することでアクセスします。このルーチンが呼び出されると、受信バッファに送信されたバイトを受け取り、それを µP アキュムレータに入れます (返されます)。

次のプログラムは、ユーザーの RS-232 互換ポートに接続されているモデムにバイト「E」 (ASCII) を送信します。

;セットアップチャンネル
LDA #$40 ;論理ファイル番号
LDX #$02 ; RS-232のデバイス番号
LDY #$FF ;二次アドレスなし
JSR SETLFS ;チャンネルを適切に設定する
;
; RS-232 の名前はコードです。 $0610
LDA #$02 ;コードの長さは2バイトです
LDX #$10
LDY#$06
JSRセトナム
;
;論理ファイルを開く
JSRオープン
;出力するチャンネルを設定する
LDX #$40 ;論理ファイル番号
JSRチェックアウト
;
;文字を RS-232 に出力します。モデム
LDA #$45
JSR CHROUT
;論理ファイルを閉じる
LDA #$40
JSRを閉じる

バイトを受信する場合のコードは非常に似ていますが、「JSR CHKOUT」が「JSR CHKIN」に置き換えられる点と次の点が異なります。

LDA #$45
JSR CHROUT

は「JSR GETIN」に置き換えられ、結果は A レジスタに格納されます。

バイトの連続送信または受信は、それぞれコード セグメントの送信または受信のループによって行われます。

Commodore での入出力は、キーボードを除いて、ほとんどのケースで同様であることに注意してください。キーボードの場合、一部のルーチンはプログラマによって呼び出されず、オペレーティング システムによって呼び出されます。

5.11 カウントとタイミング

次のようなカウントダウン シーケンスを考えてみましょう。

2、1、0

これは 2 から 0 までカウント ダウンしています。次に、繰り返されるカウント ダウン シーケンスを考えてみましょう。

2、1、0、2、1、0、2、1、0、2、1、0

これは、同じシーケンスの繰り返しのカウントダウンです。このシーケンスが 4 回繰り返されます。 4 回はタイミングが 4 であることを意味します。1 つのシーケンス内でカウントされます。同じシーケンスを繰り返すことがタイミングです。

Commodore-64 のシステム ユニットには 2 つの複雑なインターフェイス アダプターがあります。各 CIA には、タイマー A (TA) とタイマー B (TB) という名前の 2 つのカウンター/タイマー回路があります。カウント回路はタイミング回路と変わりません。 Commodore-64 のカウンターまたはタイマーも同じものを指します。実際、どちらも本質的には、システム クロック パルスで常に 0 までカウントダウンする 1 つの 16 ビット レジスタを指します。 16 ビットレジスタには異なる値を設定できます。値が大きいほど、ゼロまでカウントダウンするのに時間がかかります。いずれかのタイマーがゼロを超えるたびに、 IRQ 割り込み信号がマイクロプロセッサに送信されます。カウントがゼロを超えて減少することをアンダーフローと呼びます。

タイマー回路のプログラム方法に応じて、タイマーは 1 回モードまたは連続モードで実行できます。前の図では、ワンタイム モードは「2、1、0 を実行」を意味し、クロック パルスが継続している間は停止します。連続モードは「2、1、0、2、1、0、2、1、0、2、1、0、...」のようなものです。それはクロックパルスとともに続きます。つまり、ゼロを超えると、指示が与えられなければ、カウントダウン シーケンスが繰り返されます。通常、最大の数値は 2 よりもはるかに大きくなります。

CIA #1 のタイマー A (TA) が生成 IRQ 定期的な間隔 (期間) でキーボードのメンテナンスを行ってください。実際、これはデフォルトでは 1/60 秒ごとです。 IRQ 1/60 秒ごとにマイクロプロセッサに送信されます。それはそのときだけです IRQ プログラムがキーボード キュー (バッファ) からキー値を読み取ることができることが送信されます。マイクロプロセッサには、 IRQ 信号。マイクロプロセッサには、 NMI 信号。マイクロプロセッサへの  ̄NMI 信号は常に CIA #2 から送信されます。

16 ビット タイマ レジスタには 2 つのメモリ アドレスがあります。1 つは下位バイト用、もう 1 つは上位バイト用です。各 CIA には 2 つのタイマー回路があります。 2 つの CIA は同一です。 CIA #1 の場合、2 つのタイマーのアドレスは、TA の場合は DC04 と DC05、TB の場合は DC06 と DC07 です。 CIA #2 の場合、2 つのタイマーのアドレスは、TA の場合は DD04 と DD05、TB の場合は DD06 と DD07 です。

数値 25510 がカウントダウンのために CIA #2 の TA タイマーに送信されると仮定します。 25510 = 00000000111111112 は 16 ビットです。 00000000111111112 = $000FFF は 16 進数です。この場合、$FF は $DD04 アドレスのレジスタに送信され、$00 は $DD05 アドレスのレジスタに送信されます (リトル エンディアン)。次のコード セグメントは、数値をレジスタに送信します。

LDA #$FF
州 $DD04
LDA #$00
州 $DD05

CIA 内のレジスタには RAM アドレスがありますが、それらは物理的に CIA 内にあり、CIA は RAM や ROM とは別の IC です。

それだけではありません!前のコードのように、タイマーにカウントダウンの数値が指定されている場合、カウントダウンは開始されません。 8 ビット バイトがタイマーの対応する制御レジスタに送信されると、カウント ダウンが開始されます。制御レジスタのこのバイトの最初のビットは、カウントダウンを開始するかどうかを示します。この最初のビットの値 0 はカウントダウンの停止を意味し、値 1 はカウントダウンの開始を意味します。また、このバイトは、カウントダウンがワンショット (1 回) モードであるか、フリーランニング モード (連続モード) であるかを示す必要があります。ワンショットモードはカウントダウンし、タイマレジスタの値がゼロになると停止します。フリー ランニング モードでは、0 に達した後、カウント ダウンが繰り返されます。制御レジスタに送信されるバイトの 4 番目 (インデックス 3) ビットはモードを示します。0 はフリー ランニング モードを意味し、1 はワンショット モードを意味します。

ワンショット モードでカウントを開始するのに適した数値は、16 進数で 000010012 = $09 です。フリーランニング モードでカウントを開始するのに適した数値は、16 進数で 000000012 = $01 です。各タイマー レジスタには独自の制御レジスタがあります。 CIA #1 では、タイマー A の制御レジスタの RAM アドレスは DC0E16 で、タイマー B の制御レジスタの RAM アドレスは DC0F16 です。 CIA #2 では、タイマー A の制御レジスタの RAM アドレスは DD0E16 で、タイマー B の制御レジスタの RAM アドレスは DD0F16 です。ワンショット モードで CIA #2 の TA の 16 ビット数値のカウントダウンを開始するには、次のコードを使用します。

LDA #$09
STA $DD0E

フリーランニング モードで CIA #2 の TA の 16 ビット数値のカウントダウンを開始するには、次のコードを使用します。

LDA #$01
STA $DD0E

5.12 IRQ そして NMI リクエスト

6502 マイクロプロセッサには、 IRQ そして NMI ライン(ピン)。 CIA #1 と CIA #2 はそれぞれ、 IRQ マイクロプロセッサ用のピン。の IRQ CIA #2 のピンは、 NMI μPのピン。の IRQ CIA #1 のピンは、 IRQ μPのピン。マイクロプロセッサを接続する割り込み線はこれら 2 つだけです。それで、 IRQ CIA #2 のピンは NMI ソースであり、 ̄NMI ラインとしても見られます。

CIA #1 には、直接発生する可能性のある 5 つのソースがあります。 IRQ μP の信号。 CIA #2 の構造は CIA #1 と同じです。したがって、CIA #2 には、今回と同じ 5 つの割り込み信号を生成する即時ソースが考えられます。 NMI 信号。 μP が NMI 信号を処理している場合、 IRQ リクエストがあると、それを一時停止し、 NMI リクエスト。処理が完了すると、 NMI リクエストの処理を再開します。 IRQ リクエスト。

CIA #1 は通常、キーボードやジョイスティックなどのゲーム デバイスに外部接続されます。キーボードは、ポート B よりも CIA #1 のポート A を多く使用します。ゲーム デバイスは、ポート A よりも CIA #1 のポート B を多く使用します。CIA #2 は、通常、ディスク ドライブに外部接続されます (プリンタにデイジー チェーン接続されています)。そしてモデム。ディスク ドライブは、ポート B よりも CIA #2 のポート A を (外部シリアル ポート経由ではありますが) 多く使用します。モデム (RS-232) は、ポート A よりも CIA #2 のポート B を多く使用します。

これらすべてを踏まえると、システムユニットはどのようにして原因を知るのでしょうか? IRQ または NMI 割り込み? CIA #1 と CIA #2 には 5 つの即時割り込みソースがあります。 µP への割り込み信号が NMI 、情報源はCIA #2からの直接の5つの情報源のうちの1つです。 µP への割り込み信号が IRQ 、情報源はCIA #1からの直接の5つの情報源のうちの1つです。

次の質問は、「システム ユニットは各 CIA の 5 つの直接情報源をどのように区別するのでしょうか?」です。各 CIA には、割り込み制御レジスタ (ICR) と呼ばれる 8 ビットのレジスタがあります。 ICR は CIA の両方の港にサービスを提供しています。次の表は、割り込み制御レジスタのビット 0 から始まる 8 ビットの意味を示しています。

表5.13
割り込み制御レジスタ
ビットインデックス 意味
0 タイマAのアンダフローによりセット(1される)
1 タイマBのアンダフローによりセット
2 時刻がアラームと等しいときに設定
3 シリアルポートがいっぱいのときに設定されます
4 外部機器で設定
5 使用しない(0にする)
6 使用しない(0にする)
7 最初の 5 ビットのいずれかが設定されると設定されます

表からわかるように、各直接ソースは最初の 5 ビットの 1 つで表されます。したがって、割り込み信号がμPで受信されると、コードを実行して割り込み制御レジスタの内容を読み取り、割り込みの正確なソースを知る必要があります。 CIA #1 の ICR の RAM アドレスは DC0D16 です。 CIA #2 の ICR の RAM アドレスは DD0D16 です。 CIA #1 の ICR の内容を µP アキュムレータに読み取る (返す) には、次の命令を入力します。

LDA$DC0D

CIA #2 の ICR の内容を µP アキュムレータに読み取る (返す) には、次の命令を入力します。

LDA $DD0D

5.13 割り込み駆動のバックグラウンドプログラム

通常、キーボードは 1/60 秒ごとにマイクロプロセッサに割り込みを行います。プログラムが実行中で、以下のコード セグメントを続行する前にキーボードからのキーを待機する位置に到達したと想像してください。キーボードからキーが押されていない場合、プログラムはキーを待つ小さなループのみを実行すると仮定します。プログラムが実行中で、キーボード割り込みが発行された直後にキーボードからのキーを期待していると想像してください。その時点で、コンピュータ全体が間接的に停止し、待機ループ以外は何も実行されません。次のキーボード割り込みが発行される直前にキーボードのキーが押されたと想像してください。これは、コンピュータが約 60 分の 1 秒間何もしなかったことを意味します。これは、Commodore-64 の時代であっても、コンピューターが何もしない期間としては長い時間です。コンピューターはその時間 (継続時間) に別のことを行っていた可能性があります。プログラムにはそのような期間がたくさんあります。

2 番目のプログラムは、そのような「アイドル」期間で動作するように作成できます。このようなプログラムは、メイン (または最初の) プログラムのバックグラウンドで動作していると言われます。これを行う簡単な方法は、キーボードからのキー入力が予期されるときに変更された BRK 割り込み処理を強制的に適用することです。

BRK命令のポインタ
RAM 上の $0316 と $0317 アドレスの連続した位置は、実際の BRK 命令ルーチンのポインタ (ベクトル) です。コンピュータの電源がオンになると、ROM 内のオペレーティング システムによってデフォルトのポインタがそこに配置されます。このデフォルト ポインタは、OS ROM 内のデフォルト BRK 命令ハンドラをまだポイントしているアドレスです。ポインタは 16 ビットのアドレスです。ポインタの下位バイトは $0306 アドレスのバイト位置に配置され、ポインタの上位バイトは $0317 バイト位置に配置されます。

システムが「アイドル」のときに、第 2 のプログラムの一部のコードがシステムによって実行されるように、第 2 のプログラムを記述することができます。これは、2 番目のプログラムがサブルーチンで構成されている必要があることを意味します。システムがキーボードからのキーを待っている「アイドル」状態の場合、2 番目のプログラムの次のサブルーチンが実行されます。人間によるコンピュータの操作は、システム装置の動作に比べて遅いです。

この問題を解決するのは簡単です。コンピュータがキーボードからのキーを待つ必要があるたびに、コードに BRK 命令を挿入し、$0316 (および $0317) のポインタを 2 番目のサブルーチン (カスタム)プログラム。この方法では、両方のプログラムの実行時間は、メイン プログラムが単独で実行される時間よりもそれほど長くはなりません。

5.14 アセンブリとコンパイル

アセンブラはすべてのラベルをアドレスに置き換えます。アセンブリ言語プログラムは通常、特定のアドレスから開始するように書かれます。アセンブラの結果(アセンブル後)は、すべてバイナリ形式で「オブジェクトコード」と呼ばれます。ファイルがドキュメントではなくプログラムである場合、その結果は実行可能ファイルになります。ドキュメントは実行可能ではありません。

アプリケーションは複数の (アセンブリ言語) プログラムで構成されます。通常はメインプログラムがあります。ここでの状況を、割り込み駆動バックグラウンド プログラムの状況と混同しないでください。ここにあるプログラムはすべてフォアグラウンド プログラムですが、最初のプログラムまたはメイン プログラムがあります。

複数のフォアグラウンド プログラムがある場合は、アセンブラの代わりにコンパイラが必要です。コンパイラは、各プログラムをオブジェクト コードにアセンブルします。ただし、問題が発生します。プログラムはおそらく別の人によって書かれているため、コード セグメントの一部が重複します。コンパイラによる解決策は、プログラムが重ならないように、最初のプログラムを除くすべての重なり合うプログラムをメモリ空間上でシフトすることです。さて、変数の格納に関しては、依然として一部の変数アドレスが重複します。ここでの解決策は、重複するアドレスを新しいアドレス (最初のプログラムを除く) に置き換えて、重複しないようにすることです。このようにして、さまざまなプログラムがメモリのさまざまな部分 (領域) に収まります。

これらすべてを踏まえると、あるプログラム内の 1 つのルーチンが別のプログラム内のルーチンを呼び出すことが可能になります。したがって、コンパイラがリンクを行います。リンクとは、あるプログラム内でサブルーチンの開始アドレスを取得し、それを別のプログラムで呼び出すことを指します。どちらもアプリケーションの一部です。これには両方のプログラムで同じアドレスを使用する必要があります。最終的には、すべてがバイナリ (ビット) で構成される 1 つの大きなオブジェクト コードになります。

5.15 プログラムの保存、ロード、実行

アセンブリ言語は通常、何らかのエディタ プログラム (アセンブラ プログラムとともに提供される場合もあります) で記述されます。エディタ プログラムは、メモリ (RAM) 内のプログラムの開始位置と終了位置を示します。 Commodore-64 の OS ROM の Kernal SAVE ルーチンは、メモリ内のプログラムをディスクに保存できます。ディスクへの命令呼び出しを含む可能性のあるメモリのセクション (ブロック) をダンプするだけです。プログラムがディスクからメモリにロードされるときに、実行時に再度保存されないように、SAVE への呼び出し命令を保存中のプログラムから分離することをお勧めします。アセンブリ言語プログラムをディスクからロードすることは、プログラム自体をロードできないため、別の種類の課題となります。

プログラムは、ディスクから RAM の開始位置と終了位置にそれ自体をロードできません。当時の Commodore-64 には、通常、BASIC 言語プログラムを実行するための BASIC インタプリタが付属していました。マシン (コンピューター) の電源がオンになると、コマンド プロンプト「READY」が表示されます。そこから、入力後に「Enter」キーを押すことで、BASIC コマンドまたは命令を入力できます。ファイルをロードするための BASIC コマンド (命令) は次のとおりです。

LOAD 'ファイル名',8,1

コマンドは BASIC 予約語 LOAD で始まります。この後にスペースが続き、その後に二重引用符で囲まれたファイル名が続きます。デバイス番号 8 の後にカンマが続きます。ディスクの 2 次アドレス 1 が続き、その前にカンマが続きます。このようなファイルでは、アセンブリ言語プログラムの開始アドレスがディスク内のファイルのヘッダーにあります。 BASIC がプログラムのロードを完了すると、プログラムの最後の RAM アドレスに 1 を加えた値が返されます。ここでの「返される」という言葉は、最後のアドレスの下位バイトに 1 を加えたものが µP X レジスタに置かれ、最後のアドレスの上位バイトに 1 が加えられたものが µP Y レジスタに置かれることを意味します。

プログラムをロードした後は、実行(実行)する必要があります。プログラムのユーザーは、メモリ内での実行の開始アドレスを知っている必要があります。ここでも、別の BASIC プログラムが必要です。 SYSコマンドです。 SYS コマンドを実行すると、アセンブリ言語プログラムが実行 (および停止) します。実行中にキーボードからの入力が必要な場合、アセンブリ言語プログラムはそれをユーザーに示す必要があります。ユーザーがキーボードにデータを入力して「Enter」キーを押すと、アセンブリ言語プログラムは、BASIC インタプリタの干渉を受けることなく、キーボード入力を使用して実行を続けます。

アセンブリ言語プログラムの実行開始 (実行中) RAM アドレスが C12316 であるとすると、C123 は SYS コマンドで使用する前に 10 進数に変換されます。 C12316 を 10 進数に変換すると、次のようになります。

したがって、BASIC SYS コマンドは次のようになります。

SYS 49443

5.16 Commodore-64 の起動

Commodore-64 の起動は、ハードウェア リセット フェーズとオペレーティング システムの初期化フェーズの 2 つのフェーズで構成されます。オペレーティング システムは、ROM 内の (ディスク内ではなく) カーナルです。リセットラインがあります(実際には レス ) は 6502 μP のピンに接続され、CIA 1、CIA 2、VIC II などのすべての特別な船の同じピン名に接続されます。リセットフェーズでは、このラインにより、µP および特殊チップ内のすべてのレジスタが 0 にリセットされます (各ビットがゼロになります)。次に、マイクロプロセッサのハードウェアにより、マイクロプロセッサ内のスタック ポインタとプロセッサ ステータス レジスタに初期値が与えられます。プログラム カウンタには、$FFFC および $FFFD の場所の値 (アドレス) が指定されます。プログラム カウンタが次の命令のアドレスを保持していることを思い出してください。ここで保持される内容(アドレス)は、ソフトウェアの初期化を開始するサブルーチンの内容です。ここまでのすべてはマイクロプロセッサ ハードウェアによって実行されます。この段階ではメモリ全体には触れません。次に、初期化の次のフェーズが始まります。

初期化は、ROM OS のいくつかのルーチンによって行われます。初期化とは、特殊チップ内の一部のレジスタに初期値またはデフォルト値を与えることを意味します。初期化は、特殊チップ内のいくつかのレジスタに初期値またはデフォルト値を与えることから始まります。 IRQ たとえば、1/60 秒ごとに発行を開始する必要があります。したがって、CIA #1 の対応するタイマーをデフォルト値に設定する必要があります。

次に、カーナルは RAM テストを実行します。バイトをその場所に送信し、それを読み取ることによって、各場所をテストします。違いがあるとしたら、少なくともその場所が悪いということになります。また、カーナルはメモリの先頭とメモリの末尾を識別し、対応するポインタをページ 2 に設定します。メモリの先頭が $DFFF の場合、$FF は $0283 バイトの位置に配置され、$DF は $0284 バイトの位置に配置されます。 $0283 と $0284 の両方に HIRAM ラベルが付いています。メモリの最下位が $0800 の場合、$00 は $0281 の位置に配置され、$08 は $0282 の位置に配置されます。 $0281 と $0282 の両方に LORAM ラベルが付いています。 RAM テストは実際には $0300 からメモリ (RAM) の先頭まで始まります。

最後に、入力/出力ベクトル (ポインター) がデフォルト値に設定されます。 RAM テストは実際には $0300 からメモリ (RAM) の先頭まで始まります。これは、ページ 0、ページ 1、およびページ 2 が初期化されることを意味します。特にページ 0 には OS ROM ポインターが多く、ページ 2 には BASIC ポインターが多くあります。これらのポインターは変数と呼ばれます。ページ 1 がスタックであることに注意してください。ポインターには名前 (ラベル) があるため、変数と呼ばれます。この段階で、画面 (モニター) の画面メモリーがクリアされます。これは、スペースとして $20 のコード (これはたまたま ASCII $20 と同じです) を 1000 RAM 画面の場所に送信することを意味します。最後に、カーナルは BASIC インタプリタを起動し、モニタ (画面) の上部に READY の BASIC コマンド プロンプトを表示します。

5.17 問題点

次の章に進む前に、章内のすべての問題を解決することをお勧めします。

  1. CIA #2 ポート A のすべてのビットを出力とし、CIA #2 ポート B を入力とするアセンブリ言語コードを作成します。
  2. キーボードのキーが押されるまで待機する 6502 アセンブリ言語コードを作成します。
  3. Commodore-64 画面に「E」文字を送信する 6502 アセンブリ言語プログラムを作成します。
  4. キー コードとタイミングを無視して、キーボードから文字を取得して Commodore-64 画面に送信する 6502 アセンブリ言語プログラムを作成します。
  5. Commodore-64 ディスケットからバイトを受け取る 6502 アセンブリ言語プログラムを作成します。
  6. Commodore-64 ディスケットにファイルを保存する 6502 アセンブリ言語プログラムを作成します。
  7. Commodore-64 ディスケットからプログラム ファイルをロードして起動する 6502 アセンブリ言語プログラムを作成します。
  8. Commodore-64 のユーザー RS-232 互換ポートに接続されているモデムにバイト「E」(ASCII) を送信する 6502 アセンブリ言語プログラムを作成します。
  9. Commodore-64 コンピューターでカウントとタイミングがどのように行われるかを説明します。
  10. Commodore-64 システム ユニットが、ノンマスカブル割り込み要求を含む 10 種類の即時割り込み要求ソースをどのように識別できるかを説明します。
  11. Commodore-64 コンピューターでバックグラウンド プログラムがフォアグラウンド プログラムとともにどのように実行されるかを説明します。
  12. アセンブリ言語プログラムを Commodore-64 コンピューター用の 1 つのアプリケーションにコンパイルする方法を簡単に説明します。
  13. Commodore-64 コンピューターの起動プロセスを簡単に説明します。