Cannot write to screen memory in C

I am very new to C, this is my second high level programming language after Java. I have lost most of the basics, but for some reason I cannot write a single character to display memory.

This program was compiled using Turbo C for DOS on the Am486-DX4-100 with a frequency of 120 MHz. The graphics card is a standard VLB Diamond Multimedia Stealth SE using the Trio32 chip.

For OS, I run PC-DOS 2000 with the ISO codepage loaded. I work in standard text mode in MDA / CGA / EGA / VGA 80 format with color.

Here is the program as I wrote it:

#include <stdio.h> int main(void) { unsigned short int *Video = (unsigned short int *)0xB8000; *Video = 0x0402; getchar(); return 0; } 

As I said, I am very new to C, so I apologize if my mistake seems obvious, I could not find a reliable source of how to do this, that I could understand.

As far as I know, in real mode on x86 platform, screen memory for text mode starts with 0xB8000. Each character is stored in two bytes, one for the character and one for the background / foreground. The idea is to write the value 0x0402 (which should be a red smiling face) to 0xB8000. This should put it in the upper left corner of the screen.

I took into account the possibility of scrolling the screen and thus immediately deleting my character when performing in two ways. To solve this problem, I tried:

  • Record this value with a loop
  • Write a little further.

I can read and print the value that I wrote in memory, so it is obviously still somewhere in the memory, but for some reason I am not getting anything on the screen. I'm obviously doing something wrong, but I don't know what the problem is. If you need any other information, please ask. Thanks for any help you can give.

+42
c x86 real-mode turbo-c
Dec 01 '17 at 7:23
source share
3 answers

In real mode, a mechanism called the 20-bit segment: offset is used to access the first full 1MiB of memory. 0xb8000 - physical memory address. You need to use something called the far pointer, which allows you to address memory with real-mode segmentation. The various types of pointers are described in this Stop Request response .

0xb8000 can be represented as segment 0xb800 and offset 0x0000. The calculation to get the physical address is a segment * 16 + offset. 0xb800 * 16 + 0x0000 = 0xb8000. With that in mind, you can enable dos.h and use the MK_FP C macro to initialize the far pointer for the address given for the segment and offset.

In the documentation, MK_FP is defined as:

MK_FP () Make a far pointer

 #include <dos.h> void far *MK_FP(seg,off); unsigned seg; Segment unsigned off; Offset 

MK_FP () is a macro that makes a far pointer out of its segment segment โ€œsegโ€ and โ€œoff offโ€.

Returns: far pointer.

Your code can be written as follows:

 #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; } 
+50
Dec 01 '17 at 7:44
source share

The address of the memory segment depends on the video mode used:

 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) 

For direct access to vram, you will need a 32-bit pointer to hold the segment and offset address, otherwise you would ruin your heap. This usually results in undefined behavior.

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

See also: What are nearby, far and huge pointers?

+4
Dec 01 '17 at 7:41
source share

As pointed out by @stacker, in a 16-bit environment, you need to assign the pointer carefully. AFAIK you need to put the keyword FAR (my hell, what nostalgia).

Also make sure that you are not compiling into the so-called "huge" memory model. This is not compatible with remote addressing, since each 32-bit pointer automatically "normalizes" to 20 bits. Try to choose the Big memory model.

+1
Dec 01 '17 at 7:44
source share



All Articles