DOS 割り込みには、次のサービスのみが画面に出力されます。
AH = 02h - 標準出力への文字の書き込み
AH = 06h - 直接コンソール出力
AH = 09h - 標準出力への文字列の書き込み
AH = 40h - "WRITE" - ファイルまたはデバイスへの書き込み(STDOUT または STDERR ファイルハンドルで呼び出された場合)
これらはすべて、変換や書式設定を行わずに、入力から出力に値をコピーするだけなので、通常、入力は ASCII 文字または文字列、またはバイナリ バイト配列である必要があります。
ただし、コンピューターはバイナリ (低電流/高電流、0 または 1 として解釈されることが多い) で動作することを理解する必要があります。それ以外の値は理解できません。
したがって69
、CPUレジスタal
に値がある場合al
、CPUチップ上の8ビットセルから作成され、それらのセルは「0 1 0 0 1 0 1」として設定されます。セルはビットと呼ばれます。したがって、 Assembly sourcemov al,45h
に書き込むと、コンパイル中にアセンブラーがこのバイナリ形式を作成し、それを単一バイトとしてマシンコードに格納します。これmov al,imm8
は、命令がエンコードされた値を期待する方法だからです。
したがって、「バイナリ文字列」に対して行う必要があるのは、左から右にビットごとに 8 回移動し、特定のビットがクリアされているか設定されているかに応じて、文字'0'
または画面に出力することだけです。'1'
数値を他の基数 (基数 10 = 10 進数など) で表示する場合は、複雑な計算を行って特定の桁を見つけ、10 進数形式 "69"'6'
を形成する必要があります。'9'
ビットのグループを抽出するだけでよいため、2 の累乗の基数は少し単純です (たとえば、16 進数の基数 16 では、すべての 1 桁が正確に 4 ビットの値の部分です45h
。バイナリ0100
(4) と0101
(5) . しかし、それでもビットのグループを計算する必要があります。
基本的には、基数 2 のバイナリ出力のみを印刷する準備ができています。これは、コンピュータが整数値をレジスタとメモリに格納するネイティブな方法であるためです。
al
ビットとは何か、8 ビット レジスタ、ax
16 ビット レジスタ、ah
上位 8 ビットax
などを理解することは非常に重要です。これらの値はビット単位でエンコードされているため、このような非常に単純なアセンブリ タスクには苦労するでしょう。
そのため、値の "base N" エンコーディングが何を意味するのかを完全に理解するには、最初に数学を計算する必要があるため、ここではコードを追加しません。
コンピューターが何を処理するかを理解すると、シフトやテストなどのビット単位の命令をすばやくチェックし、ビット チェック + 出力 0/1 を画面ループに実行できるようになる可能性が非常に高くなります。理解すれば、それは非常に単純な作業です。
編集: もっと視覚的なものを提供することにしました。「単純な 8 ビット アセンブラー」に「バイナリ 8 ビット値を表示する」と書きました。
8086 ではありませんが、
- 手順は「同じ」です(完全な8086ではなく、非常に限られたセットです)
- 完全に異なるレジスタ (4 つの 8 ビット汎用 A、B、C、D および 2 つの特殊な PC および SP ポインタ)
- メモリ レイアウトが完全に異なる (合計メモリは 256 バイトのみ、最後の 24 バイトは「出力」表示用)
- 原則は同じです。これを理解すれば、8086 の方がはるかに簡単に見え、はるかに強力でコーディングが簡単になります (命令が増えます)。
次のコードをページに入れます: http://schweigi.github.io/assemblyr-simulator/
そして、「ステップ」を使用して命令ごとにゆっくりと進み、右側の「メモリ」ビューと「レジスタ」ビューを見て、命令が何をするかを確認します(x86命令リファレンスガイドを使用して、命令が何をすべきかを読むことができます。説明はこの単純なアセンブラーにも当てはまります (ただし、フラグについては 100% 正しくないものもありますが、最初から 8086 命令に気付かず、学習したほうがよいでしょう)。
; init input values
MOV A, 0x45 ; A = 45h (this ASM needs "0x" for hexa)
MOV D, 240 ; point to output display after last digit
MOV C, 8 ; 8 chars (representing bits) to output
print_loop:
; convert lowest bit of A into ASCII digit '0' or '1'
MOV B, A ; copy of A (to preserve A value)
AND B, 1 ; extract lowest bit of A (B = 0 or 1)
ADD B, '0' ; turn the value 0/1 into ASCII '0'/'1'
; display '0' or '1' to "Output" window
MOV [D], B ; write the digit to output
DEC D ; update output pointer
; shift all bits in A to right by 1 position
SHR A, 1
; create space after 4 bits displayed
CMP C, 5 ; 8-3 = 5, fourth DEC is below (in future)
JNE .no_space
DEC D ; skip one position in output
.no_space:
; loop until 8 bits are displayed
DEC C ; counter of bits
JNZ print_loop ; repeat until C becomes 0
; stop simulator
HLT
次に、これを 8086 バージョンに変換する方法を考えることができます。
ループ ロジックを最上位ビットから順に変更することをお勧めします。8086 の方が簡単adc
ですmov dl,24
adc dl,dl
。後で非常に興味深いshl
)。次に、数字を直接出力できますint 21h,2
(ロジックを逆にしてビットを左から右にテストする場合)。
または、同じロジックを維持し、ASCII 数字を最後からメモリ バッファーに格納し (十分な大きさのバッファーがあることを確認してください)、それを single で出力することもできますint 21h, 9
。
または...同じ結果を計算する方法は他にも何百万もあります(元の値から「0100 0101」ASCII桁を画面に出力します45h
)。正しい場所と時間に正しい数値を出力するだけで、結果が正しい限り、計算方法は関係ありません。