Невозможно записать в память экрана на 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 бит. Попробуйте выбрать "Большую" модель памяти.