次のページ 前のページ 目次へ

2. ハードウェアによるバイトデータの転送の仕方

2.1 送信

送信(transmitting)とは、シリアルポートを通じてコンピュータからバイ ト列を送ることです。ここで最初に示す例は極端に簡略化したものです。 もっと詳しい説明を後で追加します。 コンピュータがシリアルポートから 1 バイトのデータを送ろうとする時、CPU はコンピュータ内部のバス上にあるそのデータをシリアルポートの I/O アド レスに送ります。シリアルポートはそのデータを受け取り、シリアル端子の 送信ピンを使ってこれを 1 ビットずつ送ります(シリアルビットストリーム)。 あるビット(とバイト)が電気的にはどう見えるのかについては、 電圧の波形の章をご覧ください。この章に書いてあ ることは全てバイトデータの送信に関するものです(シリアルポート内にある 別のハードウェアを用いる受信については触れていません)。

上記の説明をもう少し詳しくして(しかしまだ完全には程遠いものです)繰り返 します。シリアルポートで行われる処理のほとんどは UART (または同等のも の)が行います。1 バイトのデータを転送するために、シリアルデバイスドラ イバプログラム(CPU 上で動作)はシリアルポートの I/O アドレスに 1 バイト を送ります。このデータはシリアルポートの「送信シフトレジスタ」(大きさ が 1 バイト)に入ります。このシフトレジスタでは、このバイトデータから 1 ビットずつ取り出され、1 ビットずつシリアル線に送られます。そして最後の ビットが送信されると、シフトレジスタは送るための別のバイトが必要になる ので、CPU に別のバイトデータを送るように求めます。これなら単純な話です が、CPU はバイトデータを即座に取得することができないかもしれないので、 遅延を考慮しなければならないでしょう。結局、CPU は普通は単なるシリアル ポートの処理以外のことを行っています。

シフトレジスタにバイトデータを取得する際の遅延をなくす方法は、シフトレ ジスタがバイトデータを必要とする前に CPU がバイトデータを取得して、こ れをシリアルポートの(ハードウェア)バッファに格納することです。それから、 シフトレジスタがバイトデータを送り出して新しいバイトが即座に必要になる と、シリアルポートのハードウェアは自分のバッファの次のバイトをシフトレ ジスタに転送するだけです。これを行うために CPU を呼ぶ必要はありません。

シリアルポートのバッファのサイズは元々 1 バイトしかありませんでしたが、 現在は普通 16 バイトです(高価なシリアルポートにはもっとあります)。しか しそれでも、シフトレジスタが転送するデータを必要とした時に必ずバッファ にデータがあるように、このバッファに十分なバイトデータを与え続けるとい う問題が残っています(送るデータがもう残っていない場合は除きます)。これ は割り込みを使って CPU と連絡することで行います。

古い方式のバッファが 1 バイトのシリアルポートはこのように動作します。 シフトレジスタがバイトデータをバッファから取り出し、バッファが他のバイ トデータを必要とすると、コンピュータのバス上にある専用の配線の電圧を上 げることにより、CPU に割り込みが送られます。CPU が非常に重要な処理をし ていなければ、CPU が実行中の処理は割り込みにより強制的に中断され、シリ アルポートのバッファに別のバイトデータを与えるためのプログラムが実行さ れます。このように、このバッファの目的は、シリアルポートから送り出され るバイトが途切れないように、いつでも出せるようなバイトデータを(送られ るのを待って)ハードウェア内のキューに入れた状態にしておくことです。

一度 CPU に割り込みがかかると、CPU は誰が割り込みをかけたか知ることが できます。なぜなら、各シリアルポートについて専用の割り込み線があるから です(ただし割り込みの共有をしていない場合)。それから CPU はシリアルデ バイスドライバを動作させます。ドライバは I/O アドレスにあるレジスタを チェックし、何が起きたのかを調べます。そして、シリアルポートの送信バッ ファが空になり、追加のバイトデータを待っていることを知ります。したがっ て、送るべきバイトデータがもっとあれば、CPU は次のバイトデータをシリア ルポートの I/O アドレスに送ります。このバイトは、前のバイトがまだ送信 シフトレジスタ内にあり、1 ビットずつ送られている間に届かなくてはなりま せん。

復習すると、1 つのバイトがシリアルポートの送信線へ完全に送り出されると、 シフトレジスタは空になり、以下の 3 つの動作がほとんど同時に起こります:

  1. 次の新しいバイトが送信バッファから送信シフトレジスタに入れられ ます。
  2. この新しいバイトの(1 ビットずつの)送信が始まります。
  3. 次の割り込みが発行され、今さっき空になった送信バッファに次のバ イトを送るようにデバイスドライバに指示します。

シリアルポートは割り込み駆動(interrupt driven)であると言えます。 シリアルポートが割り込みを発行する度に、CPU は次のバイトを送ります。 CPU が 1 バイトを送信バッファに送ると、次の割り込みを受け取るまで、CPU は他の処理を自由に行うことができます。シリアルポートはユーザ(あるいは アプリケーションプログラム)が選択した 固定の速度でビット列を送信します。この速度はボーレートと呼ばれることも あります。シリアルポートはバイトごとに追加のビット(スタートビット、ス トップビット、場合によってはパリティビットも)も付け加えるので、多 くの場合、1 バイトごとに 10 ビットのデータが送られます。したがって、通 信レート(速度とも言われます) 19,200 ビット/秒(bps, bit per second)は 1,920 バイト/秒(1,920 割り込み/秒)ということになります。

この処理を全て行うことは CPU にとっても重い負担です。これは色々な理由 から言えます。まずは、32 ビット(64 ビットのことだってあります)のバス上 で一回に 1 バイト(8 ビット)のデータしか送らないので、バス幅をあまり有 効に使っているとは言えません。また、割り込みを送る度に大きなオーバーヘッ ドが生じます。割り込みを受け取った場合でも、デバイスドライバに分かるこ とは何かがシリアルポートで割り込みを起こしたことだけであり、文字が送ら れたことが理由であることまでは分かりません。何が起こったかを調べるには、 デバイスドライバは色々なチェックを行わなければなりません。同じ割り込み が起こっても、文字を受け取ったのかもしれませんし、制御線の状態が変化し たのかもしれません。

解決方法の一つは、シリアルポートのバッファの大きさを増やすことでした。 現在のシリアルポートの大部分は、1 バイトだけではなく、16 バイトのバッ ファを持っています。つまり、CPU は割り込みを受け取ると、シリアルポート に 16 バイトまでのデータを新たに送ることができます。これにより割り込み の発行は減りますが、太いバスにもかかわらず 1 バイトずつしかデータを送 れない問題はそのままです。16 バイトのバッファは実際には FIFO (First In First Out, 先入れ先出し)のキューです。上記の一部を繰り返して もう少し詳しく説明したものについては、 FIFO を ご覧ください。

2.2 受信

シリアルポートによるバイト列の受信は送信とほぼ同じで、方向が逆になっ ているだけです。受信も割り込み駆動です。受信バッファを 1 バイトしか持 たない古い型のシリアルポートでは、1 バイトのデータ全体を受け取ると、こ のデータは(大きさが 1 バイトである)受信バッファに入ります。するとシリ アルポートは CPU に割り込みをかけてそのデータを取り込ませ、現在受信中 のデータを格納できる場所が空くようにします。16 バイトのバッファを持っ ている新しいシリアルポートの場合は、この(バイトデータを取得するための) 割り込みはバッファに 14 バイトのデータが蓄積した時点で発行されます。す ると CPU は現在の処理を一旦止め、1 から 16 バイトのデータをシリアルポー トから取り出します。14 番目のバイトが受け取られた時に送られた割り込み に対し、これが起きてからさらに 2 つのバイトデータが届くと、受け取るべ きバイトの個数は 16 バイトになるかもしれません。しかし(2 バイトではな く) 3 バイト届いてしまうと、16 バイトのバッファは溢れてしまいます。

2.3 シリアルポートの大きなバッファ

今まではシリアルポートが持っている小さい(1 または 16 バイト)ハード ウェアバッファについて説明しましたが、メインメモリにはもっと大きな バッファもあります。シリアルポートがバイトデータ(1 から 16 バイト)を ハードウェアの受信バッファから取り込んだ時、CPU はこれらデータをメイン メモリ中の大きな(例えば 8K バイトの)バッファに入れます。したがって、 シリアルポートからデータを受け取るプログラムは、この大きなバッファから (プログラム中で "read" 文を用いて)データを取り出します。送信するデータ についても同じことが言えます。CPU がデータをいくらか送る必要がある場合、 CPU はメインメモリにある大きい(8K バイトの)送信バッファからデータを取 り出し、これらをハードウェアが持つ小さな(1 または 16 バイトの)送信バッファ に入れます。


次のページ 前のページ 目次へ