2016-05-10 7 views
3

に時間/分/秒の実際の時間は、これは私のコードサンプルで表示しようとイムを時刻表示:こんにちは総会

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コンソールは

enter image description here

+0

それは2:14:02ですか? :) – hobbs

+0

はい私は数値で出力を得ることができますか? :s –

+0

投稿した画面の出力がそのエミュレータ用であることを前提として、タグにemu8086を追加しました。 –

答えて

2

材料とチュートリアルを参照するためにタグリファレンスマニュアルを命令セットのための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, 10cbw

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つの命令は保存されません。 diveaxからの読み取りにleaを使用し

axはおそらくESP、Sandybridge-家族のCPU上で高速になります書き込みます。ハズウェル以降では、しかし、インテルのプリSnBでは、部分的なレジスタストールは、別々のadd命令とmov命令で純粋な16ビット版を使う方が良いでしょう。

+0

これは8086のタグ付き質問であり、エミュレータ(emu8086)は8086といくつかの80186命令に制限されています。少なくとも、16ビットコードのコメントを外して32ビットコードをコメントアウトすることをお勧めします。 emu8086と8086プロセッサには32ビットの汎用レジスタはありません。 –

+0

@MichaelPetch:ありがとう、私はタグを読んでいない、質問を見た後に答えを読むためにフリップしただけでは些細なことでした。一定。 –

+0

ありがとうございました! –

3
が表示されることができるもの

文字を画面に直接書き込むのではなく、数値として数字を印刷するには、印刷ルーチンが必要です。幸いにも、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 
+0

私は非常に多くのことを理解していませんが、私はprint2digitsという関数を呼び出す必要がありますか? (移動AX、CHを書くときにも間違ったパラメータが出ます) –

+0

面倒な 'AAM'命令は、' al'を10で割ったショートカットです。これは即値除数で 'div'と似ています。 'ax'の代わりに' al'から。 Haswellの 'div r8'よりも少し速いです。 divの後に 'add ax、0x3030'を実行することでコードを最適化し、両方の数字をinsnのASCIIに変換することができます。しかし、問題はあります: 'DI'は16ビットのレジスタなので、実際に' div r16'を実行して 'dx:ax'を' di'で割っています。そして、「movディ、ああ」は集結しません。 –

+0

'edx'や' ecx'はスクラッチレジスタに適しています。ほとんどのABIではコールクローバーです。これらは、64ビットモード以外でアクセス可能なバイトコンポーネントを持っています。 (64ビットモードでは 'DIL'は' RDI'のロー8ですが、アクセスするにはREXプレフィックスが必要です)。 –

2

あなたはaschi文字としてCHCLDHレジスタの値(時間)を表示しようとしています。

あなたのCHに値15hが含まれているとします。

ALにこの値を設定し、int 10hを呼び出すと、値15hに一致するaschi文字が表示されます。小数点を15時間表示する場合は、レジスタ内の値を破棄する表示ルーチンを呼び出して、その値のaschi表現だけでなく、表示する数字を抽出する必要があります。

レジスタに小数点以下85桁があるとします。これで、画面「8」と「5」に印刷する必要があります。したがって、値85をaschi-56( "8")とaschii-53( "5")に変換する必要があります。次々にレジスタに入れ、int 10を2回呼び出して「85」を表示します。

答えはどのように行うかを示しています。

Hereは、別のチュートリアル