Невозможно записать в память экрана на C

Я очень плохо знаком с C, это мой второй язык программирования высокого уровня после Java. Я получил большинство основ, но по какой-то причине я не могу записать один символ в экранную память.

Эта программа скомпилирована с использованием Turbo C для DOS на Am486-DX4-100, работающем на частоте 120 МГц. Видеокарта представляет собой очень стандартную VLB Diamond Multimedia Stealth SE с использованием чипа Trio32.

Для ОС я использую PC-DOS 2000 с загруженной кодовой страницей ISO. Я работаю в стандартном текстовом режиме с 80 колонками MDA/CGA/EGA/VGA в цвете.

Вот программа, как я написал:

#include <stdio.h>

int main(void) {
    unsigned short int *Video = (unsigned short int *)0xB8000;
    *Video = 0x0402;
    getchar();
    return 0;
}

Как я уже говорил, я очень плохо знаком с C, поэтому я прошу прощения, если моя ошибка кажется очевидной, я не смог найти надежного источника о том, как сделать это, чтобы я мог понять.

Насколько мне известно, в реальном режиме на платформе x86 экранная память для текстового режима начинается с 0xB8000. Каждый символ хранится в двух байтах, один для символа и один для фона / переднего плана. Идея состоит в том, чтобы записать значение 0x0402 (которое должно быть красным улыбающимся лицом) в 0xB8000. Это должно поставить его в левом верхнем углу экрана.

Я принял во внимание возможность прокрутки экрана, и, таким образом, сразу удаляю моего персонажа при исполнении двумя способами. Чтобы решить эту проблему, я попытался:

  • Повторно напишите это значение, используя цикл
  • Напишите это немного ниже.

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

3 ответа

Решение

В реальном режиме для адресации первых 1 МБ памяти используется механизм, называемый 20-битным сегментом: смещение адресации. 0xb8000 - это адрес физической памяти. Вы должны использовать то, что называется far указатель, который позволяет вам обращаться к памяти с реальным режимом сегментации. Различные типы указателей описаны в этом ответе Stackru

0xb8000 может быть представлен как сегмент 0xb800 и смещение 0x0000. Расчет для получения физического адреса является сегментом *16+ смещение. 0xb800*16+0x0000=0xb8000. Имея это в виду, вы можете включить dos.h и использовать MK_FP МакросC для инициализации far указатель на такой адрес, заданный сегмент и смещение.

Из документации MK_FP определяется как:

MK_FP() сделать дальний указатель

#include   <dos.h>

void       far *MK_FP(seg,off);
unsigned   seg;                         Segment
unsigned   off;                         Offset

MK_FP() - это макрос, который делает дальний указатель от сегмента компонента 'seg' и смещает 'off' части.

Возвращает: дальний указатель.

Ваш код может быть написан так:

#include <stdio.h>
#include <dos.h>
int main(void) {
    unsigned short int far *Video = (unsigned short int far *)MK_FP(0xB800,0x0000);
    *Video = 0x0402;
    getchar();
    return 0;
}

Адрес сегмента памяти зависит от используемого режима видео:

0xA0000 for EGA/VGA graphics modes (64 KB)
0xB0000 for monochrome text mode (32 KB)
0xB8000 for color text mode and CGA-compatible graphics modes (32 KB)

Чтобы получить прямой доступ к vram, вам нужен 32-битный указатель для хранения адреса сегмента и смещения, иначе вы бы испортили свою кучу. Это обычно приводит к неопределенному поведению.

char far *Video = (char far *)0xb8000000;

Смотрите также: Что такое ближний, дальний и огромный указатели?

Как отметил @stacker, в 16-битной среде вам нужно тщательно назначать указатель. AFAIK нужно поставить FAR ключевое слово (черт возьми, какая ностальгия).

Также убедитесь, что вы не компилируете в так называемую "огромную" модель памяти. Это несовместимо с удаленной адресацией, поскольку каждый 32-битный указатель автоматически "нормализуется" до 20 бит. Попробуйте выбрать "Большую" модель памяти.

Другие вопросы по тегам