1

これは、単純な 16 色の​​ BMP を DOS で印刷するためだけに、私が行っている大雑把な趣味のプロジェクトです。これをいじっていると、情報を見つけることができなかった予期しないエラーに遭遇しました。

問題のエラーは、line_len を dxに移動する行がコメント アウトされるたびに、または dx が ax に置き換えられると消えます。

new_line: 
    mov dx,[line_len]       ;;restock on pixels
    sub cx,[line_pad_len]   ;;decrement cx by the padlen -1 to skip the padding.
    add bx,[line_pad_len]   ;;increment read address.
    inc bx 
    loop process_loop       ;;return to loop and decrement.

エラーが読み取られます(ただし、正確な数値は変化しますが、当然のことだと思います)

Invalid Opcode at EEAf 2D00 0217 0000 [... rest is zeroes ]
Invalid Opcode at 0013 0000 0202 0000 0013 0100 0002 0001 756E 6573 0864 0607 0405
Invalid Opcode at FECB 118A 0202 118A 189C 0000 4D4E 0000 [...]

その後、FreeDOS を停止します。これでデバッグを実行してステップスルーすると、最後に読み取れるのは(最初の)LOOPニーモニックで、通常はループの最初の変更にスキップします。(私の知る限り。)

残念ながら、私は DOS とアセンブリの両方の初心者であり、この情報で解決策を見つけることができませんでした。DX を AX に置き換えるとエラーはなくなりますが、今後このエラーを回避できるように、このエラーが表示される理由を理解しようとします。

以下の bmp->bin コンバーターのソース全体。

org 100h

segment .code
    mov ax,3d00h            ;;OPEN FILE WITH 00 ACCESS. (READ ONLY)
    mov dx,filename
    int 21h
    jc exit                 ;;C FLAG MEANS ERROR.
    mov bx,ax               ;;GET FILE HANDLE

    mov ax,3f00h            ;;read file.
    mov cx,400h             ;;1024byte buffer available.
    mov dx,file_buffer      ;;address to the buffer.
    int 21h
    jc exit                 ;;C etc.
    mov cx,ax               ;;Move read bytes into cx.

    mov ax,3e00h            ;;close file
    int 21h
    jc exit

;;confirm_file:
    cmp word [file_buffer],4d42h
    jnz exit_bmp            ;;THIS IS NOT A BMP FILE.

    mov dx,00h
    mov ax, word [file_buffer+0022h]
    div word [file_buffer+0016h]
    dec ax
    mov [line_pad_len],ax

    mov dx, word [file_buffer+0012h]    ;;get width of image in pixels.
    cmp dx,0050h            ;;check if it's too wide for our screen.
;;jmp if it is.
    mov [line_len],dx
    mov bx, word [file_buffer+000ah]    ;;get offset of bmp array.
    mov cx, word [file_buffer+0022h]    ;;get size of pixel array + padding

process_loop:               ;;WE WANT 16 COLOUR BMP. 2PX/BYTE. LEFTMOST PX MOST SIGNIFICANT NIBBLE.
    mov al,[file_buffer+bx] ;;GET FIRST BYTE OF PIXEL ARRAY.
    inc bx                  ;;INCREMET OUR FILE READ LOCATION.
    dec dx
    jbe new_line            ;;if we are out of line, skip back.
    mov ah,al               ;;copy al into ah for safekeeping
    shr ah,04h              ;;ah shifted left 4bit. high nibble should be 0
    and al,0fh              ;;high nibble zeroed.
                            ;;WRITE NEW DATA TO BUFFER. (STILL UPSIDE DOWN)
    mov [outp_buffer+di],ah ;;write ax
    inc di
    mov [outp_buffer+di],al ;;write al
    inc di
    loop process_loop       ;;DECREMENT CX LOOP
    jmp write_file

new_line: 
    mov dx,[line_len]       ;;restock on pixels
    sub cx,[line_pad_len]   ;;decrement cx by the padlen -1 to skip the padding.
    add bx,[line_pad_len]   ;;increment read address.
    inc bx 
    loop process_loop       ;;return to loop and decrement.

write_file:                 ;;WARNING! THIS WILL DESTROY THE FILE IT WRITES TO.
    mov ah,3ch              ;;CREAT FILE
    mov dx,newfile          ;;PTR TO FILENAME
    mov cx,0000h            ;;FLAGS
    int 21h
    jc exit
    mov bx,ax               ;;file handle.

    mov ah,40h              ;;write to our file
    mov cx,di               ;;di should have bytes written.
    mov dx,outp_buffer      ;;get pointer to output buffer.
    int 21h
    jc exit                 ;;did we fail?

    mov ah,3eh              ;;Close our file.
    int 21h

exit:
    mov ah,4ch
    int 21h

exit_bmp:
    mov ax,4c66h
    int 21h

segment .data
filename:       db  "IN.BMP",00h
line_len:       dw  0000h
newfile:        db  "OUT.BIN",00h
line_pad_len:   dw  0000h
segment .bss
file_buffer:    resb    1024    ;;FIGURE OUT BETTER WAY TO DO LEN.
outp_buffer:    resb    1024    ;;FIGURE OUT BETTER STUFF.
4

1 に答える 1

2

私はあなたのコードにいくつかの問題を発見しました:

JBEの後に使用しないでくださいDECJBEの場合はジャンプしますCF=1 or ZF=1DEC、キャリー フラグは変更しません。ただし、上記はキャリーCMP DX,50hフラグを変更するため、 ( )の値によっては、最初の反復で誤ったジャンプが発生する可能性があります。を使用する場合は、キャリー フラグを変更するため、代わりにを使用する必要があります。DXline_lenJBESUB DX,1DEC DXSUB


CXループ内の更新が正しくありません。
80*32 ピクセルの画像を考えてみましょう: ピクセル配列のサイズは 80*32/2 == 0x500 バイトになります。あなたline_lenは 0x50 になり、あなたline_pad_lenは 0x500 / 0x20 - 1 == 0x27 になります。は最初のprocess_loopスキャンラインで 80 回実行されるため、最初CXに到達したときは 0x4B0 になりますnew_lineCX その後、再び減少します。今回は 0x27+1 です。したがって、合計で、CXスキャンラインごとに 80+0x27+1 == 0x78 ずつ減少します。0x500 は 0x78 で割り切れないため、CXゼロに到達する代わりにラップアラウンドし、無限 (または少なくとも長すぎる) ループが作成されます。


上記のように、内側のループline_lenはスキャンラインごとに何度も反復し (つまり、ピクセルごとに 1 回反復)、反復ごとにファイル バッファー インデックス ( BX) を 1 ずつ更新しています。ただし、バッファーには、ピクセルの半分のバイトしか含まれていません。内側のループで既にインクリメントしていても、各スキャンラインの最後に追加line_pad_lenしています。ここに追加する必要があるのは、パディング バイト数 (存在する場合) だけです。BXBXBX

于 2013-10-02T16:16:33.553 に答える