構文からは、これはMASM/TASM構文であると推測します。
col
をより正確にメモリ「可変」(col
であるような場合には
mov di,col*8
はかなり偽では、...の値としてその後定義されたメモリの最初のバイトのメモリアドレスを有する「組立記号」であるcol
あなたの場合、dw 0
ディレクティブ=>で定義されている2つのバイトが0の値で生成されます)。
次にmov di,col
はmov
instructionのmov r16,r/m16
変異体に組み立て、または16ビットの整数値のcol
スタンドがcol
メモリアドレスのOFFSET
一部であるmov di,[col]
に適切なインテル構文にされます。アドレスのセグメント部分はデフォルトでds
から取得され、ds
を正しく先に設定した場合、mov
はdw
によって予約されたそのメモリに到達します。
mov di, col*8
があいまいである、あなたはどちらか(OFFSET col)*8
アドレスからメモリを取得するために意味するでしょうmov di,[col*8]
として=あなたが望まないものをすることをアセンブルし、またはmov di,[col] * 8
算術として、メモリからフェッチされた値を乗算し、およびx86 CPUは持っていないことができますそのような指示。
mov di,[col]
shl di,3 ; di = di * 8
mov eax,[ebx + esi*8]
は32Bモードで有効であるようにmov
の指示で任意の「算術様」の操作は、メモリ・アドレスに関連する算術演算であり、それはメモリを意味します。あなたは次のように、個別の値に算術演算を行う必要があります最初にフェッチされるアドレスが計算されます。値に符号/ゼロ拡張を行うmovsx/movzx
命令を除き、x86 CPUファミリのmov
命令に組み込まれている値そのものには算術演算はありません。他の例外を呼び出すことはできません。 lodsb
のような命令の「ストリング」ファミリは、フェッチ後にポインタ値を調整しますが、それは値自体の調整ではなく、ポインタのみです。
実際のメモリオフセットで計算する代わりに、lea
命令を使用してメモリアドレス算術CPUモジュールを利用して、値を使った算術演算を行うことができます。もちろん、あなたの特定のコードで
いくつかのレジスタの値を維持する方が最適であり、そしてだけに何かを読んで/保存、それを更新するために、事前に乗じすべての時間を維持するために、そしてないadd xxx,8
を行います/メモリから。すべてをレジスタに収めることができないときは、最後の手段としてのみメモリを使用してください。
編集:ソースをもう少し読んだ後...
おそらく、コードを多くの小さなステップで記述し、それぞれのコードの後に+デバッグを続けてください。
現時点では、あなたには役に立たない出力ルーチンであるint 21h
で直接ビデオRAM書き込みをミックスしていますが、それを選択してください。
すべての拡張ASCII文字を表示したいので、直接書き込みは唯一の選択です(DOSは10,13などの制御コード値を表示してから表示することになり、カーソルの移動(改行、タブ)、ビープ音など)。
256シンボルが必要な場合は、16x16テーブルが理にかなっています。
多分、最初の16個の拡張ASCIIを1行で表示してコードを書き始めてください。同様に:あなたは、最初にテキストモードの設定を追加するように...「クリアスクリーン」を、それを拡張するプラスあなたがあることを確認することができます(16個のシンボルの1行を示しています)
code segment
assume cs:code, ds:code
main:
jmp begin
; reserved for data in future
; top left corner of the table at [0, 4] position
TABLE_LEFT_TOP_OFFSET equ (4*80*2)
; the table will be 16x16, each element being 5x1
; total size = 80x16 = (will fit 80x25 text mode screen)
; element 5 chars as:
; symbol, space, first hex digit, second hex digit, space
begin:
mov ax,0B800h
mov es,ax ; es = text mode VRAM segment
; display 16 symbols (single row) on proper positions
mov di,TABLE_LEFT_TOP_OFFSET ; di = starting VRAM adr
xor dl,dl ; symbol value = 0
mov cx,16 ; loop counter
row_loop:
; show symbol + space
mov al,dl ; symbol ASCII
mov ah,4h ; colour attribute
mov es:[di],ax ; write symbol
mov al,' '
mov es:[di+2],ax ; write space after it
; advance loop for next symbol
inc dl
add di,5*2 ; move 5 chars forward
dec cx
jnz row_loop
; exit back to DOS
xor ah,ah ; ah = 0 - wait for key service
int 16h
int 20h ; terminate to DOS
code ends
end main
あなたは期待通り、この作品を確認したら期待されるモードで:
begin:
mov ax,3 ; ah = 0 (set gfx mode), al = 3
int 10h ; set VGA text mode 80x25 chars
コンパイル+実行+検証動作します。あなたは16進数を追加することができます...再びそれが動作することを確認+実行...
...
xor dl,dl ; symbol value = 0
rows_loop:
mov cx,16 ; loop counter
...
と
...
; both dl and di are ready for next line
; so all is needed is just to loop until dl==0
test dl,dl ; until all 256 symbols were displayed
jnz rows_loop
; exit back to DOS
...
:
その後、あなたはすべての256個のシンボルを表示するために16行のループを追加することができます表示します。あなたが唯一の0〜255の値を行います知っているように、あなたは完全にループ/プッシュ/ポップを回避することができ、そしてちょうど簡単な2桁の変換を行います。
...
mov es:[di+2],ax ; write space after it
; show hexadecimal value of symbol - first digit
mov al,dl
shr al,4 ; al = upper 4 bits of dl (first hex digit)
add al,'0'
cmp al,'9'
jbe first_hex_digit_ok
add al,('A'-'0'-10) ; adjust it to A-F letter if needed
first_hex_digit_ok:
mov es:[di+4],ax ; write first hex digit
; show hexadecimal value of symbol - second digit
mov al,dl
and al,0Fh ; al = lower 4 bits of dl (second hex digit)
add al,'0'
cmp al,'9'
jbe second_hex_digit_ok
add al,('A'-'0'-10) ; adjust it to A-F letter if needed
second_hex_digit_ok:
mov es:[di+6],ax ; write second hex digit
; write space after that
mov al,' '
mov es:[di+8],ax ; write space after it
; advance loop for next symbol
inc dl
...
デバッグ+は、それが(私は実際にはしませんでした動作することを確認だから私のコードがうまくいくことを願っています)。
その後、あなたは結果のコードに見てとることができ、あなたが最初の試みの後に最適化されたコードのように、di+?
変位とadd di,5*2
を取り除くために代わりstosw
を使用できるように、すべての書き込みは、連続したes:[di] = word value
をやってのようなものに気づくことがあり(プラス私は、HEX値を変更した色を追加しました):
...
; display 16 symbols (single row) on proper positions
mov di,TABLE_LEFT_TOP_OFFSET ; di = starting VRAM adr
xor dl,dl ; symbol value = 0
rows_loop:
mov cx,16 ; loop counter
row_loop:
; show symbol + space
mov al,dl ; symbol ASCII
mov ah,4h ; colour attribute for symbol
stosw ; write symbol
mov al,' '
stosw ; write space after it
; show hexadecimal value of symbol - first digit
mov ah,2h ; colour attribute for hex value
mov al,dl
shr al,4 ; al = upper 4 bits of dl (first hex digit)
add al,'0'
cmp al,'9'
jbe first_hex_digit_ok
add al,('A'-'0'-10) ; adjust it to A-F letter if needed
first_hex_digit_ok:
stosw ; write first hex digit
; show hexadecimal value of symbol - second digit
mov al,dl
and al,0Fh ; al = lower 4 bits of dl (second hex digit)
add al,'0'
cmp al,'9'
jbe second_hex_digit_ok
add al,('A'-'0'-10) ; adjust it to A-F letter if needed
second_hex_digit_ok:
stosw ; write second hex digit
; write space after that
mov al,' '
stosw ; write space after it
; advance loop for next symbol
inc dl
dec cx
jnz row_loop
; both dl and di are ready for next line
; so all is needed is just to loop until dl==0
test dl,dl ; until all 256 symbols were displayed
jnz rows_loop
...
そして最後に、あなたは、単一の行がいっぱい80をいっぱいにするので、行と列のループは、エンドオブローの状況(オーバー特別何もしないことがあり行の文字なので、自動的に次の行に進む)ので、cx
のカウンターを完全に取り除くだけで単一の256シンボルのループ:
...
xor dl,dl ; symbol value = 0
symbol_loop:
; show symbol + space
...
...
stosw ; write space after it
; advance loop for next symbol
inc dl
jnz symbol_loop ; until all 256 symbols are displayed
; exit back to DOS
...
これだけです。私は自分のコードを検証しなかったので、いくつかのバグの場合は残念ですが、私はasmコードを書くときに自分の考え方を提示しようとしています...実際には、私はおそらく最初の桁だけを行うだろう、+'0'
+'A'-'0'-10
が期待どおりに動作することを確認してから、2番目の桁を追加します。また、最終的なバージョン(x86 asmの経験のため)でコードがどのように終了するのかについての明確なビジョンがあったため、es:di
などのレジスタの使用方法の多くは非常に幸運に思えます。後で "無料で"。x86アセンブリの初心者であれば、最初のバージョンのコードの後にもっと良いアイデアが見つかるはずです。さらに多くのものを上書きすることを躊躇しないでください。あなたの現在のコードで
あなたは別の問題を打つでしょう:
mov byte ptr es:[di+2],s[0]
のx86 CPU上mov
のないmov mem, mem
バリアントがありません、片側は、登録または即時なければなりません。
あなたは、一時的に値を保持するためにAL
レジスタを使用してのように、2 mov
秒にそれを分割する必要があります:
mov al,s[0]
mov es:[di+2],al
は、あなたのソースがいくつかの既存のバリアントを標的にされていることを確認するためにhttp://x86.renejeschke.de/のような命令のリファレンスガイドを使用してください命令がどのように動作しているか完全に理解していることをご存知でしょうか(特にmul/imul
とdiv/idiv
命令では、スタックオーバーフローに関する多くの質問がありますが、リファレンスガイドを確認するだけで簡単に回避できます)。
アセンブリプログラムとCの関係は何ですか? – StoryTeller
実際に '8'をメモリに格納するのではなく、' col * 8'を直接的に使用できるようにするには 'col equ 8 'を使用してください。あなたは何にでも「si」を使用しているようではありません。静的な記憶域ではなくレジスタに変数を保持します。また、1を増やして8を掛ける代わりに、8だけ増分するだけです。つまり、列の値を既にスケーリングしたままにしておきます。 –