11

ハード ドライブから 2 番目のセクターをロードし、赤い背景のスペースを含む画面全体に書き込む簡単なコードを作成しました。問題は、常にスペースの代わりに @ 記号が表示されることです。これはコードです:

org 0x7C00
bits 16

xor ax,ax
mov ds,ax
mov es,ax

mov bx,0x8000
cli
mov ss,bx
mov sp,ax
sti

cld
clc

xor ah,ah
int 0x13
mov bx,0x07E0
mov es,bx
xor bx,bx
mov ah,0x2 ;function
mov al,0x5 ;sectors to read
mov ch,0x0 ;track
mov cl,0x2 ;sector
mov dh,0x0 ;head
int 0x13
;jc error
;mov ah, [0x7E00]
;cmp ah,0x0
;je error
jmp error
cli
hlt
jmp 0x07E0:0x0000

error:
    xor bx,bx
    mov ax,0xb800
    mov es,ax
    mov al,0x40 ;colour
    mov ah,' ' ;character
    .red:
        cmp bx,0x0FA0
        je .end
        mov WORD [es:bx], ax
        inc bx
        jmp .red
    .end:
        cli
        hlt

times 0x1FE - ($ - $$) db 0x0
db 0x55
db 0xAA

このコードによると、画面はスペースで埋める必要がありますが、そうではありません。

4

1 に答える 1

12

ビデオ メモリ (@ 0xb8000で始まる) に書き込む場合、画面上のすべてのセルに対して 2 バイトがあります。表示する文字は 1 バイト目にあり、属性は 2 バイト目にあります。赤 (カラー コード 0x40) スペース (0x20) 文字を画面の最初のセルに出力するには、次のようにバイトをメモリに配置する必要があります。

0xb800:0x0000 :  0x20         ; ASCII char for 0x20 is ' '
0xb800:0x0001 :  0x40         ; Red background, black foreground

あなたのコードでは、次のようなコードでこれを行おうとしていたようです:

mov al,0x40 ;colour
mov ah,' ' ;character
.red:
    cmp bx,0x0FA0
    je .end
    mov WORD [es:bx], ax
    inc bx
    jmp .red

残念ながら、x86 アーキテクチャはリトルエンディアンであるため、メモリに配置される値は最下位バイトが最初で最上位バイトが最後になります (16 ビットのWORDを処理する場合)。0x2040を含むAXがあり、 WORD全体をビデオ メモリに移動しました。たとえば、次のバイトが最初のセルに書き込まれます。mov WORD [es:bx], ax

0xb800:0x0000 :  0x40         ; ASCII char for 0x40 is `@'
0xb800:0x0001 :  0x20         ; Green background, black foreground

これは緑@だと思いますが、2 番目のバグのため、赤く見える可能性があります。これを修正するには、 AXレジスタの文字と属性の位置を逆にする必要があります( AHALの値を交換します)。コードは次のようになります。

mov ah,0x40 ;colour is now in AH, not AL 
mov al,' '  ;character is now in AL, not AH
.red:
    cmp bx,0x0FA0
    je .end
    mov WORD [es:bx], ax
    inc bx
    jmp .red

2 番目のバグは、ビデオ領域のトラバースに関連しています。各セルは 2 バイトを使用するため、反復ごとにBXカウンターを 2ずつインクリメントする必要があります。あなたのコードは:

mov WORD [es:bx], ax
inc bx                 ; Only increments 1 byte where it should be 2 
jmp .red

BXに 2 を追加するようにコードを変更します。

mov WORD [es:bx], ax
add bx,2               ; Increment 2 since each cell is char/attribute pair 
jmp .red

AXの値を取り、それをES:[DI]にコピーするSTOSW命令を使用して、コードを単純化できます。この命令の前にREPを付けると、 CX回繰り返されます (反復ごとにそれに応じて DI が更新されます)。コードは次のようになります。

error:
    mov ax,0xb800 
    mov es,ax     ;Set video segment to 0xb800
    mov ax,0x4020 ;colour + space character(0x20)
    mov cx,2000   ;Number of cells to update 80*25=2000
    xor di,di     ;Video offset starts at 0 (upper left of screen)
    rep stosw     ;Store AX to CX # of words starting at ES:[DI]

コードは、コードの先頭でCLDを使用して方向フラグを既にクリアしているため、反復ごとにREPによってDIが増加します。方向フラグがSTDで設定されていた場合、DIはデクリメントされます。

于 2015-11-12T23:36:32.437 に答える