7

背景:ユニテックHT630のデータ収集プログラムの作成を任されました。このプログラムは、16ビットMS DOS用にコンパイルされた実行可能ファイルを実行できる独自のDOSオペレーティングシステムを実行しますが、いくつかの制限があります。私はDigitalMarsC / C ++コンパイラを使用していますが、これは非常にうまく機能しているようです。

標準Cライブラリを使用できるものもありますが、ユニットの画面に描画するなど、アセンブリコードが必要なものもあります。デバイスのドキュメントに記載されているアセンブリの例は、C /C++でインラインアセンブリコードを使用するように教えられた方法とは異なります。参考までBYTEに、以下の例ではタイプはunsigned charです。

私が与えられたサンプルコードのサンプル:

#include <dos.h>

/* Set the state of a pixel */
void LCD_setpixel(BYTE x, BYTE y, BYTE status) {
  if(status > 1 || x > 63 || y > 127) {
    /* out of range, return */
    return;
  }
  /* good data, set the pixel */
  union REGS regs;
  regs.h.ah = 0x41;
  regs.h.al = status;
  regs.h.dh = x;
  regs.h.dl = y;
  int86(0x10, &regs, &regs);
}

インラインアセンブリを使用するように常に教えられた方法:

/* Set the state of a pixel */
void LCD_setpixel(BYTE x, BYTE y, BYTE status) {
  if(status > 1 || x > 63 || y > 127) {
    /* out of range, return */
    return;
  }
  /* good data, set the pixel */
  asm {
    mov AH, 41H
    mov AL, status
    mov DH, x
    mov DL, y
    int 10H
  }
}

どちらの形式も機能しているようですが、現時点ではどちらのアプローチでも問題は発生していません。DOSプログラミングでは、一方の形式がもう一方の形式よりも優れていると見なされますか?このint86関数は、2番目の例の独自のアセンブリコードで自分自身を処理していないものを処理しますか?

よろしくお願いします。

4

6 に答える 6

9

関数呼び出しを使用する場合int86、これは C ランタイム ライブラリ呼び出しであり、レジスタを設定して DOSintエラー関数を発行します。どちらの方法も、1 つの例外を除いて実際には同じです。インライン アセンブラーを使用すると、コンパイルおよびリンク時にコードが実際にオブジェクト コードに埋め込まれます。

DOS 割り込みを呼び出す C ランタイム ライブラリの呼び出しに伴うオーバーヘッドがないため、インライン アセンブリの方が高速であると見なされます。インライン アセンブリを使用する場合は、十分なスタック スペースを確保する必要がありますが、C ランタイム ライブラリは、int86関数を呼び出す前にレジスタを設定するときにスタック スペースを割り当てます。

これint86は、DOS 割り込みを呼び出しやすくする方法です。これは古い Borland Turbo C コンパイラ スイートの間で非常に人気があり、Microsoft では、Win 3.1 が登場する前の古いコンパイラについて話しています。

ビデオ出力を担当する割り込み0x10について言えば、私の記憶が正しければ、当時、いくつかのBIOSがbpレジスタを破壊し、回避策はこれを行うことでした:

__asm{
   push bp;
}
/* set up the registers */
int86(0x10, &regs, &regs);
__asm{
   pop bp;
}

ここで Ralph Brown の割り込みリストで広範な BIOS 機能を見つけることができます。また、HelpPC v2.1 も役立つ場合があります

于 2010-01-18T16:03:06.043 に答える
1

最初の形式はより読みやすく、これも何かの重要な要素です ;-)

int86 が背後で何かを行っているかどうかを知りたい場合は、プログラムをコンパイルして、生成されたアセンブリ コードを調べるだけです。

于 2010-01-18T15:30:55.347 に答える
1

どちらのコード スニペットも同じことを実現します。最初のものの大きな利点は、コンパイラを切り替えてもまだ使用できる可能性があることです。また、「C」コンパイラのコード ジェネレータが別の目的で使用していたレジスタを踏まないこと。asm スニペットで必ず忘れてしまうことがあります。

于 2010-01-18T16:42:59.520 に答える
1

int86 を呼び出すことで、コードは C のままになります。いずれにしても、システム割り込みを実行してピクセルを書き込んでいます。

書き込むピクセルが多く、速度の問題が深刻化し始めた場合は、ピクセル メモリに直接書き込むより直接的な (そして安全性ははるかに劣りますが、価値のある) 方法があるかもしれません。

于 2010-01-18T15:43:12.560 に答える
1

コンパイラのマニュアルを調べて、インライン アセンブリ セクションの後にレジスタ値を復元する責任者を確認する必要があります。変数はレジスタに割り当てられるため、意図しない値の変更により、見つけにくいバグが発生する可能性があります。int86(0x10, ®s, ®s); レジスタを保存し、ソフトウェア割り込みの実行後にそれらを復元します。

一部のコンパイラは、破壊リスト (保存および復元する必要があるレジスタ) を定義する命令を受け入れます。通常、アセンブラ セクションは、プッシュで変更されるレジスタとフラグを保存し、コンパイラまたは自分でポップを使用してそれらを復元する必要があります。したがって、最初の例を優先する必要があります。

于 2010-01-18T17:00:47.563 に答える
0

それはインライン アセンブリではなく、C です。非常に低レベルの C で、関数を使用して割り込みを発生させますが、それでも C です。

このページには、レジスタを表すために使用される構造など、いくつかのドキュメントがあります (DJGPP コンパイラの場合は、別の方法で動作する可能性があります)。また、次の点にも注意してください。

__dpmi_int 関数とは異なり、int86 および同様の関数を通過する要求は、プロテクト モード プログラムからのリアル モード割り込みの呼び出しに適したものにするために特別に処理されることに注意してください。たとえば、特定のルーチンが BX でポインターを受け取る場合、int86 は (保護モードの) ポインターを EBX に置くことを期待します。したがって、int86 は、この方法で呼び出すすべての割り込みと関数に対して特定のサポートを提供する必要があります。現在、利用可能なすべての割り込みと関数のサブセットのみをサポートしています [...]

于 2010-01-18T15:29:04.200 に答える