uart.c void uartputc(int c)

トップページ
jupiteroak.hatenablog.com


uart.c
https://github.com/mit-pdos/xv6-public/blob/master/uart.c#L51

void uartputc(int c)
{
  int i;

  if(!uart)
    return;
  for(i = 0; i < 128 && !(inb(COM1+5) & 0x20); i++)
    microdelay(10);
  outb(COM1+0, c);
}

uartputc関数は、引数cで指定された1文字分のデータ(8bit)をシリアル通信で送信する処理を行います。

引数 int c
シリアル通信で送信したい1文字分のデータ(8bit)です。


処理の内容

シリアルポートがシステム上に存在することを確認する

if(!uart)
    return;

!uartが真となる場合→uartに1が代入されていない場合→uartinit関数でシリアルポートの存在が確認できなかった場合は、ここで処理を終了します。

THR(Transmitter Holding Register)が利用できることを確認する

for(i = 0; i < 128 && !(inb(COM1+5) & 0x20); i++)
    microdelay(10);

in命令(ポート入力命令)でポートアドレス COM1(#define COM1 0x3f8)+5を指定することにより、UARTが持つLine Status Registerの読み取りを行なっています。
Line Status Registerは、シリアル通信の現在の状態やUART内で生じたエラー情報を示すために使用されているレジスタです。読み取ったレジスタの値を0x20でマスク処理することで、Line Status Registerのbit5の値を取得しています。Line Status Registerのbit5の値はTHR(Transmitter Holding Register)が空になっている(利用可能な)時に1となります。

THR(Transmitter Holding Register)が利用できる場合

!(inb(COM1+5) & 0x20)が偽となる場合→(inb(COM1+5) & 0x20)が1となる場合→THR(Transmitter Holding Register)が利用できる場合は、ループに入らず、次の処理へ進みます。

THR(Transmitter Holding Register)が利用できない場合

!(inb(COM1+5) & 0x20)が真となる場合→(inb(COM1+5) & 0x20)が0となる場合→THR(Transmitter Holding Register)が利用できない場合は、for分内の処理に入り、microdelay関数を呼び出します。その後、THR(Transmitter Holding Register)が利用できるまで、または、iの値が129になるまで、ループします。

THR(Transmitter Holding Register)への書き込みを行う

outb(COM1+0, c);

out命令(ポート出力命令)でポートアドレスCOM1(#define COM1 0x3f8)+0を指定することにより、UART が持つ THR(Transmitter Holding Register)への書き込みを行なっています。THR(Transmitter Holding Register)は送信用のバッファとして使用されます。1つの文字データだけをこのレジスタに保存すると、保存された文字データが送信用のシフトレジスタに転送され、シフトレジスタからシリアル線へと送信されます。