あなたはBrendanに応じて、画面に直接書き込むことができます。
PART古いVGAモードの場合1
は、(レガシー)に書き込むための固定アドレス 表示メモリ領域があります。テキストモードの場合、この領域は0x000B8000から始まります。 グラフィックモードの場合、0x000A0000から開始します。高解像度のビデオモードについて
(例えばVESA/VBE インターフェイスで設定されたもの) 面積が64 KiBの、最も高解像度のビデオモードに限定されているレガシー表示メモリのサイズが必要なので、これは動作しません。 より多くのスペース(たとえば、1024 * 768 * 32-bpp = 2.25 MiB)。 を回避するには、VBEでサポートされている2つの異なる方法があるとします。
最初の方法は「 」のビデオカードのディスプレイメモリの一部分のみがレガシーエリアにマップされ、(マップされている部分を変更できる)「バンク切り替え」と呼ばれます。これはかなり厄介なことがあります。例えば、 ピクセルを描画する必要があるピクセルを1つ描画し、そのピクセルが入っているバンクを計算し、そのバンクに切り替えて、バンク内のどのオフセットを計算しますか。 これを悪化させるためには、いくつかのビデオモード(例えば、ピクセルあたり3バイトの24-bpp ビデオモード)では、ピクセルのデータの最初の部分のみが1つのバンクにあり、同じ ピクセルのデータの第2部分は別の銀行。これの主な利点は、 レガシーディスプレイメモリ領域 が0x00100000
以下であるため、リアルモードアドレッシングで動作することです。
ビデオカードの表示メモリ領域全体にアクセスするには、乱雑なバンク切り替えがなく、「リニアフレームバッファ」(または単に「LFB」)と呼ばれる があります。このエリアがあるVESA/VBE インターフェイスに問い合わせる必要があります(通常、「PCIホール」 のどこか0xC0000000
と0xFFF00000
の間にあります)。つまり、 はリアルモードでアクセスできず、プロテクトモードまたはロングモード、または 「非リアルモード」を使用する必要があります。
LFBモードを使用しているときにピクセルのアドレスを確認するには、 のように「pixel_address = display_memory_address + y * bytes_per_line + x * bytes_per_pixel
」と入力します。 "bytes_per_line
"はVESA/VBEインターフェイスからの となります(水平線間には のパディングがある可能性があるため、 "horizontal_resolution * bytes_per_line
"と同じではない場合があります)。
VBE/VESAモードを "銀行は切り替え" の場合、それはより多くのようなものになり:いくつかの古いVGAモード(例えば256色 "モード0x13に")については
pixel_offset = y * bytes_per_line + x * bytes_per_pixel;
bank_number = pixel_offset/bank_size;
pixel_starting_address_within_bank = pixel_offset % bank_size;
それは、LFBに似て非常に です行間に余白がないことを除いて、 は "pixel_address = display_memory_address + (y * horizontal_resolution + x) * bytes_per_pixel
"とすることができます。テキストモードでは、 は基本的に同じものですが、2バイトで各文字を決定し、 の属性を指定します。 "char_address = display_memory_address + (y * horizontal_resolution + x) * 2
"他の古いVGAモードの (モノクロ/ 2色、4色、16色モード)では、ビデオカードの メモリは完全に異なった配置になっています。それは、各プレーンが1ビットのピクセルを含む「プレーン」 に分割され、 には、16色モードで1ピクセルを更新し、別々の プレーンに書き込む必要があります。パフォーマンス上の理由から、VGAハードウェアは異なる書込みモードと異なる読取りモードをサポートしており、複雑になる可能性があります(ここでも適切に説明するには複雑な )。 (80×86で、 "PC互換")I/Oポートの場合
PART 2
、3つの一般 カテゴリがあります。第1は、 固定I/Oポートを使用する「デファクトスタンダード」レガシーデバイスです。これには、PICチップ、ISA DMA コントローラ、PS/2コントローラ、PITチップ、シリアル/パラレルポートなどが含まれます。 これらの各デバイスのプログラミング方法を説明するほとんどのものは、どのI/Oポートデバイス使用。
次のカテゴリには、I/Oポートは デバイスの使用はカード自体上のジャンパによって決定されたレガシー/ ISAデバイスであり、そして、彼らはソフトウェアから使用しているI/Oポートを決定するための健全な方法が ありません。 これを回避するには、エンドユーザは各デバイスが使用するI/OポートをOSに伝える必要があります。ありがたいことに、この皮肉なものはすべて廃止されました (ただし、必ずしも誰もそれを使用しているわけではありません)。
第三のカテゴリーは、それが(ほとんどの場合、 デバイスが使用するI/Oポートを変更)を使用してI/Oポートデバイスを尋ねる いくつかの方法があります場合は、「&プレイプラグ」です。たとえば、 には、それぞれのPCIデバイスに関する多くの情報を示す「PCI構成スペース」があります。ここにはPCIがあります。 このカテゴリの場合、 は、実行時に を実行せずにどのデバイスがどのI/Oポートを使用するかを判断する方法がなく、一部のBIOS設定を変更すると、これらのデバイスがI/Oを変更する可能性があります。ポート。
また、Intel CPUはCPUのみであることに注意してください。 「PC 互換」のコンピュータとは根本的に異なるものでは、これらのCPUを で使用することはできません。インテルのCPUマニュアルでは、 チップセットを含め、CPU自体の外部にあるハードウェアについては、 に何も伝えません。
パート3
は、おそらくより多くの情報(それはOSの開発者/愛好家のための を意図しています)のために行くには最高の場所はhttp://osdev.org/(自分のwikiと そのフォーラム)です。
ここでは例のカラードットを描画するASMで、drawn from here:
これは、指定されたグラフィックス 座標で画面上の色のドットになります。
INPUT:
AH = 0Ch
AL = Color of the dot
CX = Screen column (x coordinate)
DX = Screen row (y coordinate)
OUTPUT:画面上のピクセルを除く
何もありません。
注:この関数は、新しい色 値との排他的論理和(XOR)を実行し、ALのビット7のピクセルの現在のコンテキストが設定されます。
このプログラムは、ピクセルをプロットする方法を示します。画面の中央に4つの赤い ピクセルをプロットする必要があります。
.model tiny
.code
org 100h
start:
mov ax,13 ; mode = 13h
int 10h ; call bios service
mov ah,0Ch ; function 0Ch
mov al,4 ; color 4 - red
mov cx,160 ; x position = 160
mov dx,100 ; y position = 100
int 10h ; call BIOS service
inc dx ; plot pixel downwards
int 10h ; call BIOS service
inc cx ; plot pixel to right
int 10h ; call BIOS service
dec dx ; plot pixel up
int 10h ; call BIOS service
xor ax,ax ; function 00h - get a key
int 16h ; call BIOS service
mov ax,3 ; mode = 3
int 10h ; call BIOS service
mov ax,4C00h ; exit to DOS
int 21h
end start
いくつかの最適化この方法はあまり速くないと我々はそれが たくさん速く作ることができます。どうやって?ビデオメモリに直接書き込みます。これはかなり簡単に行われます 。
VGAセグメントは0A000hです。各ピクセルがどこに行くのかを調べるには、 この単純な数式を使ってオフセットを取得します。
Offset = X + (Y * 320)
私たちはすべて、この場所に数を置くことで、画面上のピクセル が今そこにあります。色は何色かです。 命令を使用して、ピクセルを画面に配置することができます。最初に はstosbを使用してALに値をES:DIに入れたり、新しい 形式のMOV命令を使用することができます。
mov es:[di], color
私たちはどちらを使用しますか?ピクセルを画面に書き込もうとするときには、可能な限り速く行う必要があります。
Instruction Pentium 486 386 286 86
STOSB 3 5 4 3 11
MOV AL to SEG:OFF 1 1 4 3 10
あなたがMOVメソッドを使用している場合は、(STOSB はありません)DIをインクリメントする必要があるかもしれません。
連続している必要があるスプライトを使用するプログラムがある場合は、消去してから再描画するとちらつきに問題が発生します。これを避けるには、 に「ダブルバッファ」を使用することができます。これは のメモリの別の部分であり、書き込みしてすべての情報を 画面にコピーします。
これはISO Cを超えているため、環境(Unix端末/ Windowsコンソールapp/...)を指定する必要があります。 – ninjalj