Подтвердить что ты не робот

Не удается записать на экранную память в C

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

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

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

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

#include <stdio.h>

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

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

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

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

  • Повторно записывайте это значение с помощью цикла
  • Напиши немного дальше.

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

4b9b3361

Ответ 1

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

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 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;
}

Ответ 2

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

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-битный указатель, чтобы удерживать сегмент и адрес смещения, иначе вы испортили бы свою кучу. Обычно это приводит к поведению undefined.

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

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

Ответ 3

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

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