Изменить цвет фона консоли dosbox при запуске программы tasm

Я пытаюсь отобразить x в центре экрана, а затем изменить цвет фона консоли на синий. У меня есть следующий код, который выполняет все, кроме изменения цвета фона:

    TITLE screen1.ASM
.MODEL SMALL

.STACK 0100h
.DATA

.CODE
start:
MOV AX,@DATA
MOV DS,AX


MOV AX,0600h
MOV BH,07h
MOV CX,0000h
MOV DX,184Fh
INT 10h

MOV AH,02h
MOV BH,00h
MOV DH,0Ch
MOV DL,28h
INT 10h

MOV AH,02h
MOV DL,'x'
INT 21h

MOV AX,4C00h
INT 21h
END start

Код очищает экран, отображает x в центре окна dosbox и возвращает управление DOS. Я пытаюсь выяснить, какое изменение мне нужно, чтобы просто обновить цвет фона окна (а не текста) до синего.


person SoulRider    schedule 25.03.2016    source источник
comment
Возможно, вы имели в виду MOV BH,17h вместо MOV BH,07h. Верхние 4 бита — цвет фона (1 = синий), нижние 4 бита — цвет переднего плана (символа). (7=белый)   -  person Michael Petch    schedule 25.03.2016
comment
@Michael video mode не выбран. Независимо от того, какой цвет присутствует в bh, он не будет отображаться, пока не будет выбран режим видео.   -  person Hamza Anis    schedule 25.03.2016
comment
Я предполагаю, что DOSBOX уже находится в текстовом режиме. Если он не был намеренно помещен в графический режим, тогда возникает проблема. Но ОП не сказал, что он в графическом режиме. Вам нужно только перейти в текстовый режим, если вы еще не были в текстовом режиме. Мой комментарий остается в силе. относительно откусываний для цвета переднего плана и фона   -  person Michael Petch    schedule 25.03.2016
comment
Я не говорил, что комментарий неправильный.   -  person Hamza Anis    schedule 25.03.2016
comment
Но зачем использовать int 10h, если это текстовый режим.   -  person Hamza Anis    schedule 25.03.2016
comment
@HamzaAnis Потому что int 10h отлично работает в текстовом режиме. Несмотря на то, что использование BIOS происходит медленно (по сравнению с непосредственным обновлением видеодисплея), оно все же вполне приемлемо.   -  person Michael Petch    schedule 25.03.2016
comment
@Майкл Спасибо .;p   -  person Hamza Anis    schedule 25.03.2016
comment
@Michael Я смотрел на код совершенно по-другому. Спасибо, что поправили меня.   -  person Hamza Anis    schedule 25.03.2016
comment
Помог ли какой-либо из ответов решить вашу проблему?   -  person Michael Petch    schedule 17.12.2020


Ответы (4)


При очистке экрана перемещайте bh=17h вместо 07h

 TITLE screen1.ASM
.MODEL SMALL

.STACK 0100h
.DATA

.CODE
start:
MOV AX,@DATA
MOV DS,AX



MOV AX,0600h 
MOV BH,17h   
MOV CX,0000h  
MOV DX,184Fh  
INT 10h

MOV AH,02h   ;settin cursor position 
MOV BH,00h   ;page number
MOV DH,0Ch    ;row
MOV DL,28h   ;column
INT 10h

MOV AH,02h
MOV DL,'x'
INT 21h

MOV AX,4C00h
INT 21h
END start

введите здесь описание изображения

person Hamza Anis    schedule 25.03.2016

Мое первое впечатление от вашего кода и то, что вызвало мой первый комментарий, заключалось в том, что вы, возможно, использовали неправильный цвет переднего плана и фона. Ты имел:

MOV BH,07h

Который светло-серый на черном. Белое на синем было бы:

MOV BH,1fh 

Информацию об атрибутах цвета BIOS можно найти здесь.


Ваш вопрос неоднозначен, однако код в этом примере обновит цвет фона текущего текстового режима, но сохранит цвет и символ переднего плана. Я предполагаю, что текстовый режим 80x25 перед запуском screen1.

Эта программа обновляет память дисплея напрямую. Страница 0 текстовых режимов обычно начинается с физического адреса 0xB8000. Я установил для ES значение 0xB800, чтобы обновлять видео, потому что 0xB800:0x0000 пара сегмент:смещение совпадает с физическим адресом (0xB800‹‹4)+0x0000=0xB8000.

Каждый символ на экране занимает 2 байта (или одно 16-битное слово). Текстовый режим 80x25 — это 2000 ячеек (по 2 байта) или всего 4000 байт видеопамяти. Символ находится в первом байте, а атрибут — во втором байте. Дополнительную информацию об этом макете видео можно получить здесь.

Следующий код считывает каждый атрибут для каждого символа на экране, очищает цвет фона (старшие 4 бита), а затем устанавливает для этих старших 4 бит новый цвет фона. 0x01 — синий цвет. После обновления цвета фона код записывает новый атрибут обратно в видеопамять.

TITLE screen1.ASM
.MODEL SMALL

.STACK 0100h
.DATA

.CODE
start:
    MOV AX,@DATA
    MOV DS,AX

    MOV AX,0B800h
    MOV ES,AX        ; Set ES to text video memory segment
    MOV SI,1         ; Attributes are on odd addresses
    MOV CX,2000      ; 2000 2-byte cells on an 80x25 display

L1:
    MOV AL,ES:[SI]   ; Get cell attribute
    AND AL,0Fh       ; Clear the current background
    OR  AL,10h       ; Set the background to 1 (1=blue)
    MOV ES:[SI],AL   ; Update the attribute on screen with new background color
    ADD SI,2         ; Go to next cell's attribute
    DEC CX
    JNZ L1           ; Loop for entire display

    MOV AH,02h
    MOV BH,00h
    MOV DH,0Ch
    MOV DL,28h
    INT 10h          ; Set cursor

    MOV AH,02h
    MOV DL,'x'
    INT 21h          ; Write character at cursor using the current
                     ; foreground and background colors at that position

    MOV AX,4C00h
    INT 21h          ; Exit Program
END start

Пример экрана перед запуском этой программы:

введите здесь описание изображения

И после:

введите здесь описание изображения

Весь текст (и цвета переднего плана) сохраняются, а цвет фона обновляется.


Цикл в коде, выполняющий обновление цвета фона, можно было бы записать так:

    MOV AX,0B800h
    MOV ES,AX        ; Set ES to text video memory segment
    MOV SI,4000      ; 4000 bytes with each screen cell on an 80x25 display
                     ;     taking 2 bytes each. 80*25*2 = 4000
L1:
    MOV AL,ES:[SI-1] ; Get cell attribute
    AND AL,0Fh       ; Clear the current background color bits
    OR  AL,10h       ; Set the background color bits to 1 (1=blue)
    MOV ES:[SI-1],AL ; Update the attribute with new background color
    SUB SI,2         ; Go to next cell (move backwards)
    JG   L1          ; Loop for entire display

Код в моем исходном примере может быть легче понять, если вы новичок в сборке x86.


Обновить цвета переднего плана и фона для всего экрана

Если вам не нужно сохранять цвет переднего плана для каждого символа на экране, вы можете просто обновить атрибуты новым значением и сохранить существующий символ. Цикл в моем первом примере кода можно изменить так, чтобы он выглядел так:

    MOV AX,0B800h
    MOV ES,AX        ; Set ES to text video memory segment
    MOV SI,4000      ; 2000 2-byte cells on an 80x25 display
L1:
    MOV BYTE PTR ES:[SI-1],01Fh
                     ; Set attribute to 1F (1=blue background, F=white foreground)
    SUB SI,2         ; Go to next attribute(backwards)
    JG  L1           ; Loop for entire display

Это изменило бы все символы на экране на белые на синем и выглядело бы примерно так:

введите здесь описание изображения


Очистить весь экран без прерывания BIOS

Для полноты картины также можно очистить весь экран персонажем. Символ пробел действует как символ очистки. Мы можем обновить символ и атрибут, используя REP STOSW. Мы хотим двигаться вперед по памяти с помощью STOSW, поэтому мы устанавливаем флаг направления вперед, используя КЛД. STD перемещался бы назад по памяти. STOSW описывается как:

REP STOS   m16    Fill (E)CX words at ES:[(E)DI] with AX.

Код для очистки экрана с синим фоном и белым передним планом можно сделать примерно так:

    MOV AX,0B800h
    MOV ES,AX        ; Set ES to text video memory segment
    XOR DI,DI        ; Starting offset = 0 for STOSW
    MOV CX,2000      ; 2000 2-byte (16-bit WORD) cells on an 80x25 display
    MOV AX,1F20h     ; 20h = ASCII value for space character
                     ; 1Fh = attribute (white on blue)
    CLD              ; Set direction flag forward (used by STOSW etc)

    REP STOSW        ; Copy AX (attribute and char) to ES:DI, Repeat CX (2000) times

Этот код эквивалентен вашему коду, который использовал службы видео BIOS:

MOV AX,0600h
MOV BH,1Fh
MOV CX,0000h
MOV DX,184Fh
INT 10h

Вывод программы с этим кодом выше будет выглядеть так:

введите здесь описание изображения

person Michael Petch    schedule 25.03.2016

Вы должны установить цвет для каждого символа вручную. Либо используйте INT 0x10 / AH=0x09, либо просто пишите прямо в экранный буфер (по адресу B800:xxxx).

Каждый символ в экранном буфере занимает два байта, младший байт содержит символ, старший байт — атрибут цвета.

person user5434231    schedule 25.03.2016
comment
Ранее это упоминалось в комментариях. - person Hamza Anis; 25.03.2016