に時間/分/秒の実際の時間は、これは私のコードサンプルで表示しようとイムを時刻表示:こんにちは総会
MOV AH, 2Ch
INT 21h
MOV AH, 0Eh
MOV AL, CH
INT 10h
MOV AL, 3Ah
INT 10h
MOV AL, CL
INT 10h
MOV AL, 3Ah
INT 10h
MOV AL, DH
INT 10h
ret
ここでは、SEコンソールは
に時間/分/秒の実際の時間は、これは私のコードサンプルで表示しようとイムを時刻表示:こんにちは総会
MOV AH, 2Ch
INT 21h
MOV AH, 0Eh
MOV AL, CH
INT 10h
MOV AL, 3Ah
INT 10h
MOV AL, CL
INT 10h
MOV AL, 3Ah
INT 10h
MOV AL, DH
INT 10h
ret
ここでは、SEコンソールは
材料とチュートリアルを参照するためにx86タグリファレンスマニュアルを命令セットのためのwiki、および多くの良いリンクを参照してくださいです。
整数をASCII桁に分割するのに十分なコードが必要です。これを関数に組み込む必要があります。
これは、@ hobbsのprint2Digits関数の最適化されたバグ修正版です。 (私も彼の答えでバージョンをバグ修正したので、それも正しいが、この1つの最適化を残した)。
print2Digits:
;; input in AL (0-99).
;; clobbers AX and DX
cbw ; zero AH. Sign-extending AL does the job because AL is only allowed to be 0-99.
; omit this step if you can easily have the caller use the full AX, i.e. zero AH for us
mov dl, 10
div dl ; quotient in AL(first (high) digit), remainder in AH(second (low) digit)
add ax, 0x3030 ; add '0' to al and ah at the same time.
mov dl, ah ; save the 2nd digit
mov ah, 0x0E ; DOS system call number for printing a single character
int 0x10 ; print high digit first. Doesn't clobber anything, so AH still holds 0x0E after
mov al, dl
int 0x10 ; print the low digit 2nd
ret
我々は、2つのbase10桁に整数を分割するdiv
を使用するので、我々はゼロにah
を必要とします。呼び出し元がmovzx ax, ch
か何かを行った場合は、を保存することができます。ah
。
(ただし、8086にはが含まれていないことを除いて、実際にはxor ax,ax
/mov al, ch
である必要があります。)
それはすることも可能をだ私はこのAMD64 Linux FizzBuzz
で行うようにあなたは、小さなバッファに文字を格納し、一度にすべてを印刷することができるように、文字列全体を印刷するためのDOSのシステムコールがありますaam
を使用して、AHを最初にゼロにする必要性を避けて、1でAL(AXの代わりに)を除算します。現在のIntelおよびAMD CPUでは、div r8
よりわずかに高速です。ただし、結果は反対側のレジスタdiv
に格納されます。これは、aam
の後に余分な命令があることを意味します。これはmov dl, 10
とcbw
print2Digits:
;; input in AL (0-99). (Ignores AH because we use AAM instead of div)
;; clobbers AX and DX
aam ; like `div` by 10, but with the outputs reversed, and input from AL only
; quotient in AH (high digit), remainder in AL(low digit). (Opposite to div)
add ax, 0x3030 ; add '0' to al and ah at the same time.
mov dl, al ; save the low digit
mov al, ah ; print high digit first
mov ah, 0x0E ; DOS system call number for printing a single character
int 0x10 ; print first digit. Doesn't clobber anything, so AH still holds 0x0E after
mov al, dl
int 0x10 ; print second digit
ret
の節約を釣り合う我々は文字列に保存したい場合でも(と印刷文字列関数やシステムコールに1本の電話をかける)、我々は、Alを交換する必要があると思いますし、 AXをメモリに格納する前に(例えば、xchg al,ah
、またはより現代的なハードウェア上ではより効率的にrol ax,8
)。 div
は正しい順序でそれらを生成します。
32ビットのアドレスサイズが利用可能ある386のために、私たちは一つの命令保存することができます:lea
アドレスサイズプレフィックスと2バイトのMOD/RMを必要と
lea dx, [eax + 0x3030] ; need a 32bit addressing mode to use eax as a source reg. Adds '0' to both digits at once, with a different destination.
mov al, dh
をし、 32ビットのディスプレースメントであるため、コードサイズでひどく負けますが、1つの命令は保存されません。 div
後eax
からの読み取りにlea
を使用し
はax
はおそらくESP、Sandybridge-家族のCPU上で高速になります書き込みます。ハズウェル以降では、しかし、インテルのプリSnBでは、部分的なレジスタストールは、別々のadd命令とmov命令で純粋な16ビット版を使う方が良いでしょう。
これは8086のタグ付き質問であり、エミュレータ(emu8086)は8086といくつかの80186命令に制限されています。少なくとも、16ビットコードのコメントを外して32ビットコードをコメントアウトすることをお勧めします。 emu8086と8086プロセッサには32ビットの汎用レジスタはありません。 –
@MichaelPetch:ありがとう、私はタグを読んでいない、質問を見た後に答えを読むためにフリップしただけでは些細なことでした。一定。 –
ありがとうございました! –
文字を画面に直接書き込むのではなく、数値として数字を印刷するには、印刷ルーチンが必要です。幸いにも、0から59までの値を扱うだけで済むので、先行ゼロを必要とするので、問題はかなり簡単です。 AXで印刷する値を仮定すると:
print2Digits:
;; input in AX (0-99)
;; clobbers AX and DX, save them if needed
MOV DL, 0Ah ; divide by: 10
DIV DL ; first digit in AL (quotient), second digit in AH (remainder)
MOV DX, AX ; save the digits
ADD AL, 30h ; ASCII '0'
MOV AH, 0Eh ; set up print
INT 10h ; print first digit.
MOV AL, DH ; retrieve second digit
ADD AL, 30h
INT 10h ; print it
RET
私は非常に多くのことを理解していませんが、私はprint2digitsという関数を呼び出す必要がありますか? (移動AX、CHを書くときにも間違ったパラメータが出ます) –
面倒な 'AAM'命令は、' al'を10で割ったショートカットです。これは即値除数で 'div'と似ています。 'ax'の代わりに' al'から。 Haswellの 'div r8'よりも少し速いです。 divの後に 'add ax、0x3030'を実行することでコードを最適化し、両方の数字をinsnのASCIIに変換することができます。しかし、問題はあります: 'DI'は16ビットのレジスタなので、実際に' div r16'を実行して 'dx:ax'を' di'で割っています。そして、「movディ、ああ」は集結しません。 –
'edx'や' ecx'はスクラッチレジスタに適しています。ほとんどのABIではコールクローバーです。これらは、64ビットモード以外でアクセス可能なバイトコンポーネントを持っています。 (64ビットモードでは 'DIL'は' RDI'のロー8ですが、アクセスするにはREXプレフィックスが必要です)。 –
あなたはaschi文字としてCH
、CL
とDH
レジスタの値(時間)を表示しようとしています。
あなたのCH
に値15hが含まれているとします。
AL
にこの値を設定し、int 10h
を呼び出すと、値15hに一致するaschi文字が表示されます。小数点を15時間表示する場合は、レジスタ内の値を破棄する表示ルーチンを呼び出して、その値のaschi表現だけでなく、表示する数字を抽出する必要があります。
レジスタに小数点以下85桁があるとします。これで、画面「8」と「5」に印刷する必要があります。したがって、値85をaschi-56( "8")とaschii-53( "5")に変換する必要があります。次々にレジスタに入れ、int 10
を2回呼び出して「85」を表示します。
答えはどのように行うかを示しています。
Hereは、別のチュートリアル
それは2:14:02ですか? :) – hobbs
はい私は数値で出力を得ることができますか? :s –
投稿した画面の出力がそのエミュレータ用であることを前提として、タグにemu8086を追加しました。 –