assembly - ¿Cómo escribir en la pantalla con la dirección de memoria de video 0xb8000 desde el modo real?
x86 nasm (1)
Al escribir en la memoria de video (comenzando @ 0xb8000 ), hay 2 bytes por cada celda en la pantalla. El carácter a mostrar está en el primer byte y el atributo en el segundo. Para imprimir un carácter rojo (código de color 0x40) espacio (0x20) en la primera celda de la pantalla, los bytes deben colocarse en la memoria de esta manera:
0xb800:0x0000 : 0x20 ; ASCII char for 0x20 is '' ''
0xb800:0x0001 : 0x40 ; Red background, black foreground
En tu código, parece que intentaste hacer esto con un código como:
mov al,0x40 ;colour
mov ah,'' '' ;character
.red:
cmp bx,0x0FA0
je .end
mov WORD [es:bx], ax
inc bx
jmp .red
Desafortunadamente, debido a que la arquitectura x86 es poco endian, los valores que se colocan en la memoria tienen el byte menos significativo primero y el byte más significativo al último (cuando se trata de un WORD de 16 bits). Tiene AX que contiene 0x2040 y movió la PALABRA completa con mov WORD [es:bx], ax
a la memoria de video. Por ejemplo, habría escrito estos bytes en la primera celda:
0xb800:0x0000 : 0x40 ; ASCII char for 0x40 is `@''
0xb800:0x0001 : 0x20 ; Green background, black foreground
Creo que esto es un green @
pero debido al segundo error mencionaré que puede haber aparecido rojo. Para solucionar esto, necesita invertir la posición del carácter y el atributo en el registro AX (intercambie los valores en AH y AL ). El código se vería así:
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
El segundo error está relacionado con atravesar el área de video. Debido a que cada celda toma 2 bytes, necesita incrementar el contador BX en 2 en cada iteración. Tu código hace:
mov WORD [es:bx], ax
inc bx ; Only increments 1 byte where it should be 2
jmp .red
Modifique el código para agregar 2 a BX :
mov WORD [es:bx], ax
add bx,2 ; Increment 2 since each cell is char/attribute pair
jmp .red
Podría haber simplificado el código utilizando la instrucción STOSW que toma el valor en AX y lo copia a ES: [DI] . Puede prefijar esta instrucción con REP, que la repetirá CX veces (se actualizará DI en consecuencia durante cada iteración). El código podría haber sido así:
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]
Su código ya borra el indicador de dirección con CLD al comienzo de su código, por lo que REP aumentará DI durante cada iteración. Si la bandera de dirección se hubiera establecido con STD , DI habría disminuido.
Creé un código simple para cargar el segundo sector desde el disco duro, y luego escribo en pantalla completa, con espacios con fondo rojo. El problema es que siempre en lugar de espacios obtuve @ signos. Este es el código:
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
de acuerdo con este código, la pantalla debe estar llena de espacios, pero no es así.